Compare commits

...

489 Commits

Author SHA1 Message Date
Jeremy Stretch
504800a7db Merge pull request #11551 from netbox-community/develop
Release v3.4.3
2023-01-20 14:19:15 -05:00
jeremystretch
97723b1f96 Correct pinned sentry-sdk version 2023-01-20 13:53:28 -05:00
jeremystretch
5911041777 #11516: Tweak fix to ensure proper highlighting 2023-01-20 13:43:47 -05:00
jeremystretch
fcd0481b09 Release v3.4.3 2023-01-20 13:10:21 -05:00
jeremystretch
cc350165dd Fixes #11544: Catch ValidationError exception when filtering by invalid MAC address 2023-01-20 12:06:34 -05:00
Arthur
db7e1b8a97 11537 remove connection from power feed table 2023-01-20 11:52:56 -05:00
jeremystretch
188f773081 Changelog for #11118, #11227, #11228 2023-01-20 10:24:57 -05:00
reishoku
6271f81cff Add 800GbE interface support: QSFP-DD OSFP (#11429)
Signed-off-by: KOSHIKAWA Kenichi <reishoku.misc@pm.me>

Signed-off-by: KOSHIKAWA Kenichi <reishoku.misc@pm.me>
2023-01-20 10:09:53 -05:00
jeremystretch
4bfc3bf412 #11118: Extend L2VPN filters to device & VM interfaces 2023-01-20 09:58:58 -05:00
Abhimanyu Saharan
d5a92104d1 added l2vpn_termination on vlan filterset (#11501)
* added l2vpn_termination on vlan filterset

* added l2vpn to vlan filterset
2023-01-20 09:34:41 -05:00
Abhimanyu Saharan
ddd4f805a5 added device and vm tab on device role (#11500)
* added vm tab on device role

* added blank lines

* updated templates

* fixed lint issues
2023-01-20 09:30:18 -05:00
Jeremy Stretch
a1c1b19482 Changelog for #11433, #11516 2023-01-17 21:22:02 -05:00
Abhimanyu Saharan
426bc15065 fixed AttributeError: object of class Schema has no attribute fields 2023-01-17 21:12:06 -05:00
kkthxbye-code
df5febf6e7 Add re.escape to highlight_string 2023-01-17 20:42:17 -05:00
jeremystretch
9e09e46700 Fixes #11522: Correct tag links under contact & tenant list views 2023-01-17 10:32:22 -05:00
jeremystretch
ba0e9bb1d2 Changelog for #11488, #11497 2023-01-17 10:27:53 -05:00
jeremystretch
19da92b510 #11488: Additional cleanup 2023-01-17 10:26:34 -05:00
Abhimanyu Saharan
beb1f4e172 added missing description field on the api serializers 2023-01-17 10:20:34 -05:00
kkthxbye-code
fb3d1ef399 Check for the extras.run_script permission when running scripts via. the API 2023-01-17 10:13:18 -05:00
jeremystretch
d7c37d9dd6 Fixes #11483: Apply configured formatting to custom date fields 2023-01-13 08:23:57 -05:00
jeremystretch
24de404fbc Changelog for #11416 2023-01-12 09:37:52 -05:00
jeremystretch
8565d175f9 Fixes #11467: Correct count on interfaces tab when viewing a VC master device 2023-01-12 09:05:55 -05:00
Arthur
8d9e151030 11416 fix circuit termination deletion 2023-01-11 16:09:39 -05:00
jeremystretch
758c5347fb Fixes #10201: Fix AssertionError exception when removing some terminations from an existing cable 2023-01-11 14:42:25 -05:00
Jonathan Senecal
1e54eee631 Update ipaddress.md
Missing `ipam` before `IPAddress.status`
2023-01-11 09:45:28 -05:00
jeremystretch
448760a2fe Add items to contributing guide 2023-01-10 15:47:33 -05:00
jeremystretch
e44b22f7d1 Refresh contributing guide 2023-01-10 08:41:06 -05:00
jeremystretch
30379c3f52 Changelog for #11438, #11444 2023-01-09 10:58:23 -05:00
jeremystretch
8729d60c1c Fixes #11402: Avoid LookupError exception when running scripts with commit disabled 2023-01-09 10:57:13 -05:00
kkthxbye
effcdb8723 Snapshot DeviceBay before populating/depopulating. 2023-01-09 08:39:54 -05:00
kkthxbye
1354947434 Get the queue from QUEUE_MAPPINGS when deleting JobResults 2023-01-09 08:22:40 -05:00
jeremystretch
864ce0088e Changelog for #10486, #11210, #11340, #11379 2023-01-06 16:25:41 -05:00
jeremystretch
93ac0b77c9 Fixes #11379: Fix TypeError exception when bulk editing custom date fields 2023-01-06 16:23:38 -05:00
Mario
ea327e6b37 Closes #10486: Add buttons to edit cables (#11414)
* Added buttons to edit cables

* Revert change that did not address this branch

* Consolidated buttons

* moved back trace button / added permission checks

* reverted disabled trace button
2023-01-06 15:11:29 -05:00
kkthxbye-code
f7b85ab941 Return no terminations if the cable is unsaved 2023-01-06 14:57:07 -05:00
Arthur Hanson
ce9933da85 11340 cable termination setter (#11341)
* 11340 update _terminations_modified only if modified

* 11340 update _terminations_modified only if modified
2023-01-06 10:15:43 -05:00
Robin Schneider
0662f0dab4 Add summary release notes for v3.4 2023-01-06 10:07:21 -05:00
jeremystretch
0669fda1fd Fixes #11384: Correct current time display on script & report forms 2023-01-06 09:42:13 -05:00
jeremystretch
b88fcb6625 Closes #11406: Correct example JSON 2023-01-05 16:38:29 -05:00
jeremystretch
69be24cd5f Changelog for #9996, #11150, #11245, #11371, #11403 2023-01-05 16:29:17 -05:00
Renato Almeida de Oliveira
35273cc87f Add ExportTemplatesMixin to JournalEntry model (#11251)
* Add ExportTemplatesMixin to JournalEntry model

* Move mixin ahead of base class

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2023-01-05 16:26:48 -05:00
Daniel W. Anner
5af73e9bf7 #11371 - Add various 100Mb Interface Types (#11377)
* Added 100base-fx (aka fast ethernet over fiber optic)

* Added 100BASE-T1 (single pair fast ethernet) as well as 100BASE‑LFX (fast ethernet over fiber, non standard)

* Update choices.py

Updated the placing of the 100base-fx and lfx choices

* Update netbox/dcim/choices.py

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2023-01-05 16:26:26 -05:00
Patrick Kerwood
128ccb4330 feat: added setting redis certificate authority path 2023-01-05 16:15:26 -05:00
Robin Schneider
07df622b59 NetBox should always be referred to as NetBox [DATALAD RUNCMD]
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "git ls-files -z . | xargs --null -I '()' find './()' -type f -not -name 'style-guide.md' -print0 | xargs --null sed --in-place --regexp-extended 's/\\bNetbox\\b/NetBox/g;'",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^
2023-01-05 16:06:00 -05:00
Michaël Arnauts
5d22260589 #11150: Add a filter for device.primary_ip4 and primary_ip6 (#11382)
* Closes #11150: Add a filter for device.primary_ip4 and primary_ip6

* Tweaked tests to query for multiple IDs

Co-authored-by: jeremystretch <jstretch@ns1.com>
2023-01-05 14:25:15 -05:00
kkthxbye-code
39985ebdd1 Fix exception when scheduling a job in the past 2023-01-05 13:52:07 -05:00
jeremystretch
92ec06c694 PRVB 2023-01-03 16:30:17 -05:00
Jeremy Stretch
04137e887e Merge pull request #11376 from netbox-community/develop
Release v3.4.2
2023-01-03 16:28:05 -05:00
jeremystretch
e940f00c01 Release v3.4.2 2023-01-03 16:13:11 -05:00
jeremystretch
1c72a80d9a Changelog for #11156, #11259, #11342, #11345 2023-01-03 10:21:19 -05:00
kkthxbye
b9f8370097 Fixes #11156 - Allow InventoryItem component reassignment (#11256)
* Allow re-assigning InventoryItem components

* Refactor logic for finding initial component assignment on InventoryItems

* PEP8 fix

* Fix wrong HTML causing tab list to extend past the end of the parent row

* Tweak form field labels

Co-authored-by: jeremystretch <jstretch@ns1.com>
2023-01-03 10:13:34 -05:00
Christian Harendt
1c636ea127 add username for redis authentication 2023-01-03 09:42:18 -05:00
kkthxbye
e1169e7ea6 Fixes #11345 - Fix module validation (#11346)
* Make sure we bail out if field validation failed when importing modules

* Tweak form validation logic

Co-authored-by: jeremystretch <jstretch@ns1.com>
2023-01-03 09:14:25 -05:00
kkthxbye-code
5975dbcb07 Fix component traces all pointing to the interface trace URL 2023-01-03 08:25:28 -05:00
Arthur Hanson
08a419ec7a 11271 flag to disable localization (#11323)
* 11271 flag to disable localization

* 11271 change to remove middleware

* 11271 update docs for new var

* Update docs/configuration/system.md

Co-authored-by: kkthxbye <400797+kkthxbye-code@users.noreply.github.com>

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
Co-authored-by: kkthxbye <400797+kkthxbye-code@users.noreply.github.com>
2022-12-29 09:04:35 -05:00
jeremystretch
d417168805 Changelog for #11223, #11244, #11248 2022-12-28 16:58:04 -05:00
Mario
ccb2966c4c Fixes #11244: Elevations: Filter badge missing (#11321)
* Added filter badge in rack elevation

* Tweak template context

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-12-28 16:54:33 -05:00
Alef Burzmali
b7cdbd3d41 Fixes #11248 - Reindex only NetBox apps 2022-12-28 16:35:05 -05:00
Alef Burzmali
ae440c9edf Fixes #11223 - Accept app_label for reindex 2022-12-28 16:35:05 -05:00
jeremystretch
b6cd099117 Changelog for #11121, #11280 2022-12-27 16:07:02 -05:00
Arthur
98f57f2dba 11297 have custom field form display content-type instead of model 2022-12-27 15:50:08 -05:00
kkthxbye-code
735fa4aa31 Add summed resource card to cluster view 2022-12-27 10:24:46 -05:00
kkthxbye
c7108bb3f7 Fixes #11280 - Fix exporting interfaces and FHRP group rows with multiple IP's assigned (#11285)
undefined
2022-12-27 10:15:28 -05:00
jeremystretch
98b3fc03b8 Changelog for #9285, #10700, #11290 2022-12-22 10:14:38 -05:00
kkthxbye-code
92da2fe082 Add device name as part of module search for the q filter 2022-12-22 10:09:53 -05:00
kkthxbye-code
bfab3a26bc Add component import to InventoryItem bulk import 2022-12-22 09:59:50 -05:00
kkthxbye-code
b35b33e798 Use the start time to calculate duration of jobs instead of created time 2022-12-22 09:52:05 -05:00
jeremystretch
db5c2a379e Fixes #11232: Enable partial & regex matching for non-string types in global search 2022-12-22 09:14:57 -05:00
jeremystretch
3675ad2539 PRVB 2022-12-16 17:18:06 -05:00
Jeremy Stretch
27c71b8ec0 Merge pull request #11219 from netbox-community/develop
Release v3.4.1
2022-12-16 17:16:07 -05:00
jeremystretch
0058c7749c Release v3.4.1 2022-12-16 17:03:40 -05:00
jeremystretch
f882dcabf7 Fixes #11184: Correct visualization of cable path which splits across multiple circuit terminations 2022-12-16 16:45:51 -05:00
Arthur Hanson
c8f4a7c742 11206 dont remove user groups if no valid REMOTE_AUTH_DEFAULT_GROUPS (#11207)
* 11206 dont remove user groups if no valid REMOTE_AUTH_DEFAULT_GROUPS

* 11206 dont remove user groups if no valid REMOTE_AUTH_DEFAULT_GROUPS
2022-12-16 08:59:24 -05:00
jeremystretch
ed366c5ab2 Closes #11214: Introduce the DEFAULT_LANGUAGE configuration parameter 2022-12-16 08:56:14 -05:00
jeremystretch
2738da2d39 Fixes #11189: Fix localization of dates & numbers 2022-12-16 08:43:05 -05:00
jeremystretch
9f15ca2d90 Closes #9971: Enable ordering of nested group models by name 2022-12-15 16:21:30 -05:00
jeremystretch
e4f5407c70 Changelog for #11175, #11178 2022-12-15 16:05:43 -05:00
jeremystretch
951f82b428 Fixes #11205: Correct cloning behavior for recursively-nested models 2022-12-15 16:04:29 -05:00
Arthur Hanson
f8685ad7aa 11175 fix cloning special chars in fields (#11181)
* 11175 fix cloning special chars in fields

* 11175 fix cloning special chars in fields
2022-12-15 13:07:55 -05:00
Arthur
c59d527664 11178 fix quick search press enter button 2022-12-15 13:01:21 -05:00
jeremystretch
77423e7bb1 Fixes #11185: Fix TemplateSyntaxError when viewing custom script results 2022-12-15 12:55:09 -05:00
jeremystretch
ba12675267 PRVB 2022-12-14 14:24:46 -05:00
Jeremy Stretch
def3ccfaee Merge pull request #11180 from netbox-community/develop
Release v3.4.0
2022-12-14 14:18:49 -05:00
jeremystretch
bbc68f9484 Release v3.4.0 2022-12-14 13:10:22 -05:00
Jeremy Stretch
93685d92a4 Merge pull request #11179 from netbox-community/feature
Prepare for v3.4.0 release
2022-12-14 11:56:29 -05:00
Arthur Hanson
b2bf613895 11171 fix graphql related models query (#11172)
* 11171 fix graphql related models query

* 11171 remove redundant code from code review

* 11171 remove redundant code from code review
2022-12-14 11:32:22 -05:00
jeremystretch
80ced6b782 Closes #11163: Auto-detect data format during bulk import 2022-12-14 10:09:59 -05:00
jeremystretch
47dfb89c52 Relocate ImportFormatChoices 2022-12-14 09:30:10 -05:00
jeremystretch
064e3ff605 Merge branch 'develop' into feature 2022-12-13 17:17:05 -05:00
Jeremy Stretch
fb27803ab0 Merge pull request #11174 from netbox-community/develop
Release v3.3.10
2022-12-13 15:44:42 -05:00
jeremystretch
5e32b39f25 Release v3.3.10 2022-12-13 15:29:07 -05:00
jeremystretch
b9888d6f86 Fixes #11109: Fix nullification of custom object & multi-object fields via REST API 2022-12-13 14:48:40 -05:00
jeremystretch
96a796ebde Fixes #11173: Enable missing tags columns for contact, L2VPN lists 2022-12-13 14:04:50 -05:00
jeremystretch
996e73d5d8 Fixes #10981: Fix release notes formatting 2022-12-13 13:26:41 -05:00
jeremystretch
5c969a8caf Changelog for #9361, #10447, #11077 2022-12-13 13:24:07 -05:00
jeremystretch
68faab8196 Fixes #11168: Honor RQ_DEFAULT_TIMEOUT config parameter when using Redis Sentinel 2022-12-13 13:22:28 -05:00
sleepinggenius2
b3693099dc Adds replication and adoption for module import (#9498)
* Adds replication and adoption for module import

* Moves common Module form clean logic to new class

* Adds tests for replication and adoption for module import

* Fix test

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-12-13 11:33:09 -05:00
Arthur Hanson
9bb9ac3dec 11077 use formatting for custom field date (#11143)
* 11077 use formatting for custom field date

* Apply configured date format to column render() method

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-12-13 09:22:57 -05:00
kkthxbye-code
a57378e780 Add missing newline and change wording of InventoryItem validation 2022-12-13 08:58:57 -05:00
kkthxbye-code
41f631b65b Allow re-assigning inventoryitems to other devices 2022-12-13 08:58:57 -05:00
jeremystretch
2db668f5cc Clean up v3.4 release notes 2022-12-12 16:49:00 -05:00
jeremystretch
aacf606999 #10739: Collapse BaseView class 2022-12-12 16:32:55 -05:00
jeremystretch
e338f7cfe3 #10371: Fix API serializer representation for module status 2022-12-12 16:14:18 -05:00
jeremystretch
758030733c #8366: Misc cleanup 2022-12-12 15:27:37 -05:00
jeremystretch
ad78f9e075 #7961: Fix updating via import when custom fields are absent 2022-12-12 14:19:27 -05:00
jeremystretch
3468e8c8ae #9623: Misc cleanup 2022-12-12 12:56:38 -05:00
jeremystretch
13d39a28ce #7854: Misc cleanup 2022-12-12 12:34:05 -05:00
jeremystretch
8809fc949b Fixes #11154: Index VM interface MAC address and MTU for global search 2022-12-12 10:43:48 -05:00
jeremystretch
860805ba82 Closes #10255: Introduce LOGOUT_REDIRECT_URL config parameter to control redirection of user after logout 2022-12-09 17:08:07 -05:00
jeremystretch
1e0b024609 Closes #10516: Add vertical frame & cabinet rack types 2022-12-09 16:35:37 -05:00
jeremystretch
8486d47d17 Fixes #11142: Correct available choices for status under IP range filter form 2022-12-09 16:04:46 -05:00
jeremystretch
407365888a Closes #11089: Permit whitespace in MAC addresses 2022-12-09 16:00:11 -05:00
jeremystretch
2ad1db0c64 Tweak migration name 2022-12-09 15:07:10 -05:00
jeremystretch
83a0576ca4 #9072: Add weight parameter to influence ViewTab ordering 2022-12-09 14:50:13 -05:00
jeremystretch
0b100b8fc8 Closes #10675: Add max_weight field to track maximum load capacity for racks 2022-12-09 12:45:02 -05:00
jeremystretch
2b12138c41 Fix configuration key for WirelessLANStatusChoices 2022-12-09 10:45:02 -05:00
jeremystretch
97aa40f7a8 Closes #10371: Add operational status field for modules 2022-12-09 10:43:29 -05:00
jeremystretch
b2f34cec19 Fixes #10950: Fix validation of VDC primary IPs 2022-12-09 09:49:01 -05:00
jeremystretch
3bc9586b0c Changelog for #10945 2022-12-08 18:18:51 -05:00
Jeremy Stretch
4297c65f87 Closes #10945: Enable recurring execution of scheduled reports & scripts (#11096)
* Add interval to JobResult

* Accept a recurrence interval when executing scripts & reports

* Cleaned up jobs list display

* Schedule next job only if a reference start time can be determined

* Improve validation for scheduled jobs
2022-12-08 18:17:13 -05:00
jeremystretch
62b0f034e7 Changelog for #11022 2022-12-08 10:00:21 -05:00
jeremystretch
6ffd8aa320 Introduce constants for RQ queue names 2022-12-08 09:58:52 -05:00
kkthxbye-code
d53ddd611b Add any queues defined in QUEUE_MAPPINGS to RQ_QUEUES 2022-12-08 09:45:21 -05:00
kkthxbye-code
080a001118 Allow redefining internally used queues 2022-12-08 09:45:21 -05:00
jeremystretch
5a77791f9d Merge branch 'develop' into feature 2022-12-08 09:31:22 -05:00
jeremystretch
ab9c253310 Fixes #11128: Disable ordering changelog table by object to avoid exception 2022-12-08 09:00:02 -05:00
jeremystretch
35596ddcbc Closes #10806: Add warning to run deactivate prior to upgrade script 2022-12-08 09:00:02 -05:00
kkthxbye-code
0cacac82ee Disable sorting by object_repr on ObjectChangeTable 2022-12-08 08:44:11 -05:00
Jeremy Stretch
780997a568 Closes #11119: Enable filtering L2VPNs by slug 2022-12-06 15:48:22 -05:00
Jeremy Stretch
d2d60c0607 Fixes #11087: Fix background color of bottom banner content 2022-12-06 15:40:59 -05:00
Renato Almeida de Oliveira
d4d8d00d01 add distinct method to circuit_count 2022-12-06 15:19:35 -05:00
jeremystretch
cb52d9c84e Changelog for #11000, #11046 2022-12-02 13:02:13 -05:00
jeremystretch
db61e57893 Closes #11090: Add regular expression support to global search engine 2022-12-02 12:54:35 -05:00
Jeremy Stretch
52cf9086a5 Fixes #11046: Restrict length of indexed search values (#11076)
* Fixes #11046: Restrict length of indexed search values

* Reference constant in index declaration

* Remove index from CachedValue.value
2022-12-02 10:07:53 -05:00
jeremystretch
db7590df1a Changelog for #10748, #11041 2022-12-02 09:30:44 -05:00
PieterL75
ee03f3d584 10748 Add 'Provider' to the circuit termination edit/view (#10939)
* Show the Provider of the NetworkProvider

* Clean up form fields

Co-authored-by: Pieter Lambrecht <pieter.lambrecht@sentia.com>
Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-12-02 09:27:47 -05:00
Arthur Hanson
2577f3a786 11000 improve yaml import (#11075)
* 11000 improve yaml import

* 11000 add commenting

* 11000 add commenting
2022-12-02 08:34:24 -05:00
Arthur
826a1714c3 11041 return power percentage with 1 decimal place 2022-12-01 15:41:15 -05:00
jeremystretch
d0e0c2ff8b Merge branch 'develop' into feature 2022-11-30 16:21:20 -05:00
jeremystretch
fb407e9076 PRVB 2022-11-30 16:18:03 -05:00
Jeremy Stretch
85c60670dc Merge pull request #11059 from netbox-community/develop
Release v3.3.9
2022-11-30 16:14:00 -05:00
jeremystretch
f2f36c67f6 Release v3.3.9 2022-11-30 15:51:37 -05:00
jeremystretch
281934cf34 Fixes #11047: Cloning a rack reservation should replicate rack & user 2022-11-30 15:37:50 -05:00
jeremystretch
00d72f18cf Annotate need for natural ordering 2022-11-30 15:33:01 -05:00
Arthur
b36afdc924 11014 code review changes 2022-11-30 15:33:01 -05:00
Arthur
4ed45e4031 11014 fix rack elevation name sorting 2022-11-30 15:33:01 -05:00
Arthur
cf0258204f 11048 fix connected_endpoint refs 2022-11-30 15:13:45 -05:00
Patrick Hurrelmann
3bd560add8 Fixes #11028 - Enable clearing of the color field for front and rear ports in bulk edit 2022-11-30 15:09:07 -05:00
Arthur
9e51a8d9d2 10999 fix power utilization on Device detail 2022-11-29 09:38:04 -05:00
Arthur
f59c6699f6 11025 fix error tag toast 2022-11-29 09:36:48 -05:00
jeremystretch
39732fa861 Merge branch 'develop' into feature 2022-11-29 09:19:11 -05:00
jeremystretch
80f5eeacdd Fix issues loading demo data 2022-11-29 09:18:03 -05:00
jeremystretch
f56e3eb784 Fixes #8058: Display server-side form errors inline with fields 2022-11-22 12:02:21 -05:00
jeremystretch
c3dcd8937f Merge branch 'develop' into feature 2022-11-22 10:08:23 -05:00
jeremystretch
b1da374df2 Fixes #10997: Fix exception when editing NAT IP for VM with no cluster 2022-11-22 08:52:21 -05:00
jeremystretch
dc1da0a738 Fixes #10996: Hide checkboxes on child object lists when no bulk operations are available 2022-11-22 08:52:04 -05:00
jeremystretch
1946e8f053 #10984: Update test 2022-11-21 16:05:51 -05:00
jeremystretch
4623858849 Fixes #10936: Permit demotion of device/VM primary IP via IP address edit form 2022-11-21 15:36:13 -05:00
jeremystretch
9c5891f1b6 Fixes #10929: Raise validation error when attempting to create a duplicate cable termination 2022-11-21 14:08:33 -05:00
jeremystretch
d5538c1ca3 Fixes #10241: Support referencing custom field related objects by attribute in addition to PK 2022-11-21 12:48:13 -05:00
jeremystretch
90f15b8d55 Fixes #10938: render_field template tag should respect label kwarg 2022-11-21 09:49:30 -05:00
jeremystretch
4e27e8d3dd Fixes #10969: Update cable paths ending at associated rear port when creating new front ports 2022-11-21 09:44:08 -05:00
jeremystretch
150cb772fe Fixes #10984: Fix navigation menu expansion for plugin menus comprising multiple words 2022-11-21 08:38:44 -05:00
jeremystretch
e494d7bb22 Fixes #10982: Catch NoReverseMatch exception when rendering tabs with no registered URL 2022-11-21 08:06:12 -05:00
jeremystretch
9774bb46ce Fixes #10973: Fix device links in VDC table 2022-11-18 16:33:06 -05:00
jeremystretch
84c0c45da9 Fixes #10980: Fix view tabs for plugin objects 2022-11-18 16:26:08 -05:00
jeremystretch
46e3883f19 Closes #815: Enable specifying terminations when bulk importing circuits 2022-11-18 15:22:24 -05:00
Arthur
3a89a676cd 10869 convert docstring to comment 2022-11-18 13:47:55 -05:00
jeremystretch
0885333b11 Fixes #9223: Fix serialization of array field values in change log 2022-11-18 11:24:14 -05:00
jeremystretch
c287641363 Changelog for #10236, #10653 2022-11-18 11:23:30 -05:00
Arthur Hanson
de9646d096 10653 log failed login attempts on INFO (#10843)
* 10653 log failed login attempts on INFO

* 10653 use signal to log failed login attempts

* 10653 use signal to log failed login attempts

* Update netbox/users/signals.py

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

* Update netbox/users/apps.py

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-18 08:57:57 -05:00
Arthur Hanson
dd2520d675 10236 fix device detail for power-feed (#10961)
* 10236 fix device detail for power-feed

* 10236 optimize with statement
2022-11-18 08:55:28 -05:00
jeremystretch
3a5914827b Fixes #6389: Call snapshot() on object when processing deletions 2022-11-17 21:04:55 -05:00
jeremystretch
cf55e96241 Fixes #10721: Disable ordering by custom object field columns 2022-11-17 16:30:54 -05:00
jeremystretch
bd29d15814 Fixes #10579: Mark cable traces terminating to a provider network as complete 2022-11-17 16:08:29 -05:00
jeremystretch
d3911e2a4c Fixes #9878: Fix spurious error message when rendering REST API docs 2022-11-17 15:13:37 -05:00
jeremystretch
eb591731ef #10712: Remove pin for swagger-spec-validator (fixed in v3.0.3) 2022-11-17 13:06:51 -05:00
jeremystretch
ae11419045 Changelog for #10946, #10948 2022-11-17 12:41:24 -05:00
jeremystretch
43bbd42d3c Fixes #10957: Add missing VDCs column to interface tables 2022-11-17 12:29:30 -05:00
jeremystretch
d4a231585a Clean up tests 2022-11-17 10:50:05 -05:00
kkthxbye-code
977b79ecee Check that device has a platform set before rendering napalm tab 2022-11-17 08:25:06 -05:00
kkthxbye-code
5202d0add9 Linkify primary IP for VDC 2022-11-17 08:22:42 -05:00
jeremystretch
ebf555e1fb Use strings to specify prerequisite models 2022-11-16 17:22:09 -05:00
jeremystretch
f411c4f439 Introduce panel template for services 2022-11-16 16:52:35 -05:00
jeremystretch
216d8d24b8 Add note to update model's SearchIndex 2022-11-16 16:40:01 -05:00
jeremystretch
cb2b256934 Fix typo 2022-11-16 16:38:29 -05:00
jeremystretch
2f96fdd135 Merge branch 'develop' into feature 2022-11-16 11:42:32 -05:00
jeremystretch
e40e2550a6 PRVB 2022-11-16 11:34:45 -05:00
Jeremy Stretch
bfda5d9011 Merge pull request #10937 from netbox-community/develop
Release v3.3.8
2022-11-16 11:32:44 -05:00
jeremystretch
62a80c46a8 Release v3.3.8 2022-11-16 10:45:29 -05:00
jeremystretch
ceec1055e0 Changelog for #10356, #10904, #10920 2022-11-16 10:40:18 -05:00
jeremystretch
540bba4544 Closes #10920: Include request cookies when queuing a custom script 2022-11-16 10:37:06 -05:00
jeremystretch
44c248e6c2 Closes #10934: Update release package URL 2022-11-16 10:36:30 -05:00
Patrick Hurrelmann
3a62fd49e6 Fixes: #10356 backplane connections (#10554)
* Fixes: #10356 Add interface type and cable for backplane connections

* Allow Backplone for front and readports , too.

* Correct tyo in port definition

* pep8 fix (blank lines)

* Remove port type and changed name/description of backplane cable

* Omit backplane cable type

Co-authored-by: Patrick Hurrelmann <patrick.hurrelmann@nfon.com>
Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-16 10:26:46 -05:00
Derick Vigne
a2007a4728 Closes #10904: Added Colors to SVG for Front and Rear Ports (#10905)
* Added Colors to SVG for Front and Reaer Ports

Fix for feature request 10904 thanks to @TheZackCodec

* Simplify termination color resolution

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-16 09:57:49 -05:00
jeremystretch
316c3808f7 Changelog for #9439, #10902, #10914, #10915, #10919 2022-11-16 09:43:11 -05:00
Arthur Hanson
928d880f0e 10902 add location to power feed form (#10913)
* 10902 add location to power feed form

* Bind location field to selected site

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-16 09:27:49 -05:00
Arthur
c6930e3ea8 10919 add location to cable termination panels 2022-11-16 09:22:39 -05:00
jeremystretch
db77e9428f Update features docs for v3.4 2022-11-16 09:11:03 -05:00
jeremystretch
80f5c96af3 Document save_object() on BulkImportView 2022-11-16 08:47:45 -05:00
jeremystretch
de1b346da0 Split core views into separate modules 2022-11-16 08:43:22 -05:00
jeremystretch
96818cacf0 #10608: Use register_model_view() for token views 2022-11-16 08:11:42 -05:00
jeremystretch
0c0c848597 Clean up plugins documentation 2022-11-15 16:55:18 -05:00
jeremystretch
23077821f6 #10052: Serialize date fields 2022-11-15 16:10:20 -05:00
jeremystretch
87fd09ca8b Cleanup for #9654 2022-11-15 15:30:39 -05:00
jeremystretch
0bcc59a1e9 #8366: Add started field to JobResult 2022-11-15 15:06:11 -05:00
jeremystretch
87727c71f7 #8366: name scheduled_time to scheduled for consistency with other fields 2022-11-15 13:37:13 -05:00
jeremystretch
23c0ca456f #4347: Rename NetBoxModelCSVForm to NetBoxModelImportForm 2022-11-15 12:24:57 -05:00
jeremystretch
d9d25ff4e7 Cleanup for #4347 2022-11-15 12:09:03 -05:00
jeremystretch
6f8a7fdbe3 Cleanup for #7854 2022-11-15 11:24:36 -05:00
jeremystretch
640fd8045d #9887: Add missing model documentation links 2022-11-15 11:00:13 -05:00
jeremystretch
4230162294 Add missing model documentation 2022-11-15 10:50:26 -05:00
jeremystretch
355678274d #9623: Add slug field to SavedFilter 2022-11-15 10:44:12 -05:00
jeremystretch
ecf5304a14 #10560: Add new fields to indexers 2022-11-15 10:37:35 -05:00
jeremystretch
94dd07e1e6 #10560: Build search index as part of migration 2022-11-15 10:37:16 -05:00
jeremystretch
1b707e07f2 Add missing milestones to release notes 2022-11-14 17:07:39 -05:00
Arthur
564884a774 10903 add module type on manufacturer page 2022-11-14 14:17:06 -05:00
Arthur
7401fd7050 10909 add l2vpn to tenant stats 2022-11-14 14:16:18 -05:00
jeremystretch
42e9dc0da7 Changelog for #4751, #10694, #10851 2022-11-14 14:06:30 -05:00
Jeremy Stretch
a5308ea28e Closes #10851: New staging mechanism (#10890)
* WIP

* Convert checkout() context manager to a class

* Misc cleanup

* Drop unique constraint from Change model

* Extend staging tests

* Misc cleanup

* Incorporate M2M changes

* Don't cancel wipe out creation records when an object is deleted

* Rename Change to StagedChange

* Add documentation for change staging
2022-11-14 13:55:03 -05:00
Arthur Hanson
27bf7b4a9a 4751 Enable plugins to inject content within object list views (#10901)
* 4751 add plugin buttons to list templates

* 4751 add plugin buttons to list templates

* 4751 add documentation

* 4751 fix object reference

* 4751 update docs
2022-11-14 13:51:58 -05:00
Jeremy Stretch
a57c937aaa #10694: Emit post_save signal when creating/updating device components in bulk (#10900)
* Emit post_save signal when creating/updating device components in bulk

* Fix post_save for bulk_update()
2022-11-14 13:46:32 -05:00
jeremystretch
4a95cfd1c4 Permanently connect change logging & webhook receivers 2022-11-14 09:31:25 -05:00
jeremystretch
cd8943144b Use context vars instead of thread-local storage for change logging 2022-11-14 09:31:25 -05:00
jeremystretch
8400509358 Fixes #10891: Populate tag selection list for service filter form 2022-11-14 09:28:03 -05:00
jeremystretch
d971131198 Fixes #10897: Fix form widget styling on FHRP group form 2022-11-14 09:24:12 -05:00
jeremystretch
5729a06348 Fixes #10910: Fix cable creation links on power port view 2022-11-14 09:20:02 -05:00
Arthur
6eba5d4d96 10300 initial translation support use gettext 2022-11-11 08:47:29 -05:00
jeremystretch
2cc2d2cc37 Changelog & documentation for #7854 2022-11-11 08:25:44 -05:00
Daniel Sheppard
b374351154 Closes: #7854 - Add VDC/Instances/etc (#10787)
* Work on #7854

* Move to new URL scheme.

* Fix PEP8 errors

* Fix PEP8 errors

* Add GraphQL and fix primary_ip missing

* Fix PEP8 on GQL Type

* Fix missing NestedSerializer.

* Fix missing NestedSerializer & rename VDC to VDCs

* Fix migration

* Change Validation for identifier

* Fix missing migration

* Rebase to feature

* Post-review changes

* Remove VDC Type
* Remove M2M Enforcement logic

* Interface related changes

* Add filter fields to filterset for Interface filter
* Add form field to filterset form for Interface filter
* Add VDC display to interface detail template

* Remove VirtualDeviceContextTypeChoices

* Accommodate recent changes in feature branch

* Add tests
Add missing search()

* Update tests, and fix model form

* Update test_api

* Update test_api.InterfaceTest create_data

* Fix issue with tests

* Update interface serializer

* Update serializer and tests

* Update status to be required

* Remove error message for constraint

* Remove extraneous import

* Re-ordered devices menu to place VDC below virtual chassis

* Add helptext for `identifier` field

* Fix breadcrumb link

* Remove add interface link

* Add missing tenant and status fields

* Changes to tests as per Jeremy

* Change for #9623

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

* Update filterset form for status field

* Remove Rename View

* Change tabs to spaces

* Update netbox/dcim/tables/devices.py

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

* Update netbox/dcim/tables/devices.py

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

* Fix tenant in bulk_edit

* Apply suggestions from code review

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

* Add status field to table.

* Re-order table fields.

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 07:55:49 -05:00
jeremystretch
d59d23e308 Fixes #10881: Fix dark mode coloring for data on device status page 2022-11-10 16:47:17 -05:00
jeremystretch
3d1501e8fd Changelog for #10837, #10874 2022-11-10 16:33:34 -05:00
Brian Candler
c854c29016 Fix broken cookie paths when BASE_PATH is set (introduced in #10706) (#10856)
Fixes #10837
2022-11-10 16:23:05 -05:00
Arthur Hanson
33d8f8e5e7 10874 remove link to contact roles (#10879) 2022-11-10 16:19:43 -05:00
jeremystretch
653acbf62c #4347: Changelog & cleanup 2022-11-10 11:05:44 -05:00
Arthur Hanson
93e7457e0d 4347 Add JSON/YAML import support for all objects (#10367)
* 4347 initial code for json import

* 4347 initial code for json import

* Clean up form processing logic

* Consolidate import forms

* Consolidate object import/update logic

* Clean up bulk import view

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-10 11:01:52 -05:00
jeremystretch
93e241e8f3 Changelog for #10709, #10829 2022-11-04 16:56:52 -04:00
Arthur
43da786016 10829 fix top edit selected button 2022-11-04 16:54:24 -04:00
jeremystretch
ea6d86e6c4 Closes #10052: The cf attribute now returns deserialized custom field data 2022-11-04 14:53:18 -04:00
jeremystretch
fe73e90b7b Reorganize virtualization models 2022-11-04 13:51:30 -04:00
jeremystretch
f68c7fb188 Changelog for #7376, #10710 2022-11-04 13:46:15 -04:00
jeremystretch
ad40d42dc4 Closes #10710: Add status field to WirelessLAN 2022-11-04 13:40:39 -04:00
Arthur Hanson
cdeb65e2fb 7376 csv tags (#10802)
* 7376 add tags to CSV import

* 7376 change help text

* 7376 validate tags

* 7376 fix tests

* 7376 add tag validation tests

* Introduce CSVModelMultipleChoiceField for CSV import tag assignment

* Clean up CSVImportTestCase

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-04 10:50:43 -04:00
Arthur
271d524687 10709 add AzureAD Tenant Oauth2 2022-11-04 09:12:22 -04:00
Jeremy Stretch
bc6b5bc4be Closes #10545: Standardize description & comment fields on primary models (#10834)
* Standardize description & comments fields on primary models

* Update REST API serializers

* Update forms

* Update tables

* Update templates
2022-11-04 08:28:09 -04:00
jeremystretch
e2f5ee661a Clean up redundant NestedGroupModel, OrganizationalModel fields 2022-11-03 13:59:44 -04:00
jeremystretch
6b2deaeced Closes #8485: Enable journaling for all organizational models 2022-11-03 13:31:51 -04:00
jeremystretch
13afc52617 Closes #10543: Introduce get_plugin_config() utility function 2022-11-03 13:18:58 -04:00
jeremystretch
e7f54c5867 Reorganize plugin resources 2022-11-03 12:59:01 -04:00
Arthur Hanson
4ebcdd2b8f 8072 move js code from template to static file (#10824) 2022-11-03 09:29:45 -04:00
jeremystretch
07730ccd33 #10820: Fix zoneinfo import for py3.9+ 2022-11-02 16:29:42 -04:00
jeremystretch
0ad7ae2837 Closes #10698: Omit app label from content type in table columns 2022-11-02 16:26:26 -04:00
jeremystretch
8fb91a1f8c Closes #10821: Enable data localization 2022-11-02 15:55:39 -04:00
jeremystretch
3b0a84969b Closes #10820: Switch timezone library from pytz to zoneinfo 2022-11-02 15:54:41 -04:00
jeremystretch
81c0dce5a3 Closes #10697: Move application registry into core app 2022-11-02 15:25:22 -04:00
Arthur Hanson
816fedb78d 8853 Prevent the retrieval of API tokens after creation (#10645)
* 8853 hide api token

* 8853 hide key on edit

* 8853 add key display

* 8853 cleanup html

* 8853 make token view accessible only once on POST

* Clean up display of tokens in views

* Honor ALLOW_TOKEN_RETRIEVAL in API serializer

* Add docs & tweak default setting

* Include token key when provisioning with user credentials

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-11-02 12:45:00 -04:00
Jeremy Stretch
484efdaf75 Closes #9623: Implement saved filters (#10801)
* Initial work on saved filters

* Return only enabled/shared filters

* Add tests

* Clean up filtering of usable SavedFilters
2022-11-02 12:27:53 -04:00
jeremystretch
ea61a540cd Closes #10816: Pass the current request when instantiating a FilterSet within UI views 2022-11-02 11:00:09 -04:00
jeremystretch
0b24d3d892 Merge branch 'develop' into feature 2022-11-01 17:13:11 -04:00
jeremystretch
2af8891f70 PRVB 2022-11-01 17:11:55 -04:00
jeremystretch
4e39021b6f Merge branch 'master' into develop 2022-11-01 17:10:18 -04:00
jeremystretch
2cd5fce62d Release v3.3.7 2022-11-01 17:09:55 -04:00
jeremystretch
ade307bc03 Fixes #10809: Permit nullifying site time_zone via REST API 2022-11-01 17:09:55 -04:00
jeremystretch
c8be4ef8e2 Fixes #10791: Permit nullifying VLAN group scope_type via REST API 2022-11-01 17:09:55 -04:00
jeremystretch
816214361d Fixes #10803: Fix exception when ordering contacts by number of assignments 2022-11-01 17:09:55 -04:00
jeremystretch
d1970ca85b Changelog for #10282, #10770 2022-11-01 17:09:55 -04:00
Arthur
8001694a4c 10282 fix race condition in API IP creation 2022-11-01 17:09:55 -04:00
Arthur
10e258739f 10770 fix social auth 2022-11-01 17:09:55 -04:00
jeremystretch
f3fdf03661 Changelog for #10666 (missed in v3.3.6) 2022-11-01 17:09:55 -04:00
jeremystretch
44814f759c PRVB 2022-11-01 17:09:55 -04:00
jeremystretch
4f5caa5ed2 Release v3.3.7 2022-11-01 16:48:40 -04:00
jeremystretch
aa7f04bf1b Fixes #10809: Permit nullifying site time_zone via REST API 2022-11-01 16:45:32 -04:00
jeremystretch
aaf1ea52b7 Fixes #10791: Permit nullifying VLAN group scope_type via REST API 2022-11-01 15:38:10 -04:00
jeremystretch
7990cfb078 Fixes #10803: Fix exception when ordering contacts by number of assignments 2022-11-01 15:27:35 -04:00
jeremystretch
675a5f8687 Changelog for #10781 2022-10-31 15:17:24 -04:00
jeremystretch
a25ee66150 Changelog for #10282, #10770 2022-10-31 15:15:45 -04:00
Arthur Hanson
13c27b00d3 10781 add python 3.11 support (#10782)
* 10781 add python 3.11 support

* 10781 update Django to latest
2022-10-31 15:05:34 -04:00
Arthur
867af61875 10282 fix race condition in API IP creation 2022-10-31 15:04:43 -04:00
Arthur
8f4fa065f9 10770 fix social auth 2022-10-31 15:02:57 -04:00
Arthur
7b5f5ca6bb Merge branch 'develop' into feature 2022-10-27 14:25:27 -07:00
jeremystretch
a176e9452f Changelog for #7961 2022-10-27 13:24:20 -04:00
Arthur Hanson
cb815ede60 7961 CSV bulk update (#10715)
* 7961 add csv bulk update

* temp checkin - blocked

* 7961 bugfix and cleanup

* 7961 change to id, add docs

* 7961 add tests cases

* 7961 fix does not exist validation error

* 7961 fix does not exist validation error

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 update tests

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 make test cases more explicit

* 7961 optimize loading csv test data

* 7961 update tests remove redundant code

* 7961 avoid MPTT issue in test cases
2022-10-27 13:10:18 -04:00
jeremystretch
d773f4e62a Closes #9832: Add mounting_depth field to rack model 2022-10-27 10:50:54 -04:00
jeremystretch
dbe66596f9 Closes #9887: Inspect docs_url property to determine link to model documentation 2022-10-27 09:44:09 -04:00
jeremystretch
ec4e2a8e16 #8274, #10761: Fix content types display in object lists 2022-10-26 17:07:16 -04:00
jeremystretch
7e7f68923d #10761: Fix ExportTemplate resolution for REST API requests 2022-10-26 17:05:09 -04:00
jeremystretch
edb5220228 Changelog for #10666 (missed in v3.3.6) 2022-10-26 15:11:44 -04:00
Jeremy Stretch
ac373d2376 Merge pull request #10763 from netbox-community/10761-exporttemplate-content-types
Closes #10761: Enable associating an export template with multiple objects
2022-10-26 14:14:34 -04:00
jeremystretch
16919cc1d9 Closes #10761: Enable associating an export template with multiple object types 2022-10-26 13:30:45 -04:00
Jeremy Stretch
7a155407f6 Merge pull request #10760 from netbox-community/8274-customlink-content-types
Closes #8274: Enable associating a custom link with multiple object types
2022-10-26 12:22:56 -04:00
jeremystretch
9e8234bb45 Closes #8274: Enable associating a custom link with multiple object types 2022-10-26 11:39:26 -04:00
jeremystretch
c4dcd34ce9 Merge branch 'develop' into feature 2022-10-26 10:25:49 -04:00
jeremystretch
18332bdbf1 PRVB 2022-10-26 10:23:50 -04:00
Jeremy Stretch
f1a7bceef2 Merge pull request #10758 from netbox-community/develop
Release v3.3.6
2022-10-26 10:18:44 -04:00
jeremystretch
eac2ace80b Release v3.3.6 2022-10-26 09:58:31 -04:00
Kevin Petremann
174ba6cf0f Fix LDAP auth: user never updated if inactive 2022-10-26 09:40:05 -04:00
jeremystretch
658c9347f3 Fixes #10682: Correct home view links to connection lists 2022-10-26 09:32:29 -04:00
jeremystretch
7b3ef2ade5 Fixes #10719: Prevent user without sufficient permission from creating an IP address via FHRP group creation 2022-10-26 08:44:20 -04:00
jeremystretch
2a62b628cf Fixes #10723: Distinguish between inside/outside NAT assignments for device/VM primary IPs 2022-10-26 08:23:50 -04:00
Arthur
d8c07abd68 10610 interface_id query on lag return vc interfaces 2022-10-26 08:10:03 -04:00
Arthur Hanson
8d486c5838 10716 add left-right plugins to tags page (#10744)
* 10716 add left-right plugins to tags page

* 10716 add back plugin_full_width
2022-10-26 08:05:15 -04:00
jeremystretch
eb91934d70 Fixes #10745: Correct display of status field in clusters list 2022-10-25 16:41:07 -04:00
jeremystretch
01654765e8 Fixes #10746: Add missing status attribute to cluster view 2022-10-25 16:38:32 -04:00
jeremystretch
91c6bbcd78 Closes #10695: Rename forms/models.py to forms/model_forms.py 2022-10-25 16:26:05 -04:00
jeremystretch
b2e2e3be35 Closes #10739: Introduce get_queryset() method on generic views 2022-10-25 11:33:20 -04:00
Jeremy Stretch
9628dead07 Closes #10560: New global search (#10676)
* Initial work on new search backend

* Clean up search backends

* Return only the most relevant result per object

* Clear any pre-existing cached entries on cache()

* #6003: Implement global search functionality for custom field values

* Tweak field weights & document guidance

* Extend search() to accept a lookup type

* Move get_registry() out of SearchBackend

* Enforce object permissions when returning search results

* Add indexers for remaining models

* Avoid calling remove() on non-cacheable objects

* Use new search backend by default

* Extend search backend to filter by object type

* Clean up search view form

* Enable specifying lookup logic

* Add indexes for value field

* Remove object type selector from search bar

* Introduce SearchTable and enable HTMX for results

* Enable pagination

* Remove legacy search backend

* Cleanup

* Use a UUID for CachedValue primary key

* Refactoring search methods

* Define max search results limit

* Extend reindex command to support specifying particular models

* Add clear() and size to SearchBackend

* Optimize bulk caching performance

* Highlight matched portion of field value

* Performance improvements for reindexing

* Started on search tests

* Cleanup & docs

* Documentation updates

* Clean up SearchIndex

* Flatten search registry to register by app_label.model_name

* Clean up search backend classes

* Clean up RestrictedGenericForeignKey and RestrictedPrefetch

* Resolve migrations conflict
2022-10-21 13:16:16 -04:00
jeremystretch
4c504870e0 Tweak PR template language 2022-10-21 12:47:19 -04:00
jeremystretch
3d687a6c2d Closes #10718: Optimize object-based permissions enforcement 2022-10-21 12:43:36 -04:00
Jeremy Stretch
5d56d95fda Merge pull request #10417 from kkthxbye-code/8366-job-scheduling
Fixes #8366 - Add job scheduling
2022-10-21 11:22:05 -04:00
kkthxbye-code
5e5228ff12 Fix JobResultFilterset to use DateTimeField to perserve bc compat 2022-10-21 15:53:39 +02:00
kkthxbye-code
72ba57052a PEP8 fix 2022-10-21 10:42:49 +02:00
kkthxbye-code
ed2f7f1236 Job scheduling review changes 2022-10-21 10:31:30 +02:00
jeremystretch
893925436d Merge branch 'feature' into 8366-job-scheduling 2022-10-20 17:03:57 -04:00
jeremystretch
96c4696417 Changelog for #9584, #10580, #10639 2022-10-20 16:31:52 -04:00
Arthur Hanson
e7659a5f99 9584 add device type (slug) to filter list (#10630)
* 9584 add device type (slug) to filter list

* 9584 add test
2022-10-20 16:27:51 -04:00
Craig Pund
53c9c3cf8d Fixes #10580 (#10687)
* change IP address accessor to parent object

* set IP assigned check to link to interface

* Fix Assigned not being orderable

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>

Co-authored-by: Craig Pund <cpund@iuhealth.org>
Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-10-20 16:26:26 -04:00
Patrick Rauscher
f60312febf Set *_COOKIE_PATH according to BASE_PATH
As discussed in #10639, all three `COOKIE_PATH`s should be set accordingly with the netbox-`BASE_PATH` to improve coexistance with other Django-projects probably hosted on the same Host
2022-10-20 16:24:38 -04:00
jeremystretch
bd79a27e4d Merge branch 'develop' into feature 2022-10-20 16:07:03 -04:00
jeremystretch
7505baf3a1 Fixes #10712: Fix ModuleNotFoundError exception when generating API schema under Python 3.9+ 2022-10-20 15:49:13 -04:00
kkthxbye-code
4f95c5a72c Allow scheduling jobs via. the API 2022-10-20 21:36:43 +02:00
jeremystretch
85a4b1f881 Closes #10699: Remove custom import_object() function 2022-10-19 10:40:39 -04:00
jeremystretch
33c6142365 Update documentation section options for new issues 2022-10-19 09:52:10 -04:00
jeremystretch
10e874039f Changelog for #10643, #10646 2022-10-19 09:02:09 -04:00
jeremystretch
060ee2dd96 Revert PR #10621 2022-10-19 08:55:30 -04:00
jeremystretch
43d1182b4b Fix styling for power input, rear port connection links 2022-10-19 08:47:14 -04:00
Arthur
d53da57f63 10646 fix cable power feed filter 2022-10-19 08:42:55 -04:00
Arthur Hanson
028b4b7ea7 10643 add fieldset to device role for improved add/edit form display (#10680)
* 10643 add fieldset to device role for improved add/edit form display

* 10643 update other forms

* 10643 update other forms

* Specify fieldsets for additional models

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-10-19 08:35:23 -04:00
jeremystretch
4cb0230878 Closes #10685: Position A/Z termination cards above the fold under circuit view 2022-10-18 16:51:37 -04:00
Arthur Hanson
2fe8df3cbb 10655 fix contacts display in list views (#10681)
* 10655 fix contacts display in list views

* 10655 review changes
2022-10-18 16:47:14 -04:00
Arthur
64d67e3b00 10584 add clone fields to ipam-service 2022-10-18 16:06:31 -04:00
kkthxbye-code
83ff99a130 Added delete button to script/report result 2022-10-17 09:54:23 +02:00
kkthxbye-code
52faeb6f60 Added documentation describing job scheduling 2022-10-16 18:15:45 +02:00
kkthxbye-code
f797b5ed97 Add scheduled_time to JobResultSerializer 2022-10-16 15:27:33 +02:00
kkthxbye-code
e143038df8 Remove JobResult view from admin panel 2022-10-16 15:20:38 +02:00
kkthxbye-code
074082d1f1 Allow export of JobResult table 2022-10-16 15:18:54 +02:00
kkthxbye-code
d647983003 Always activate scheduler functionality when running the rqworker management command 2022-10-16 13:47:15 +02:00
kkthxbye-code
1d9808a92a Added scheduled_time field to JobResult model 2022-10-16 13:42:28 +02:00
Arthur
a44eed5001 10631 add extra GraphQL documentation 2022-10-13 08:08:26 -04:00
jeremystretch
f2407afc9f Changelog for #8245 2022-10-12 13:43:31 -04:00
Arthur Hanson
99cf1b1671 8245 add graphql filtering at all levels (#10618)
* 8245 monkey-patch graphene-django to support filtering at all levels

* 8245 fix tests

* 8245 fix tests
2022-10-12 13:21:34 -04:00
jeremystretch
aaf829898b Changelog for #10575, #10596 2022-10-12 08:41:41 -04:00
Arthur
8481cf66e3 10575 add requirements for openid connect packages 2022-10-12 08:39:14 -04:00
Arthur Hanson
bb150379a2 10571 replace deprecated mkdoc settings (#10622)
* 10571 replace deprecated mkdoc settings

* Omit landing page from docs nav menu

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-10-12 08:36:02 -04:00
Arthur Hanson
cc811e5a56 10596 add overflow-auto to card-body (#10621)
* 10596 add overflow-auto to card-body

* 10596 add overflow-auto to card-body
2022-10-12 08:31:02 -04:00
jeremystretch
e8c5a4724a Changelog for #9817, #10595 2022-10-11 12:35:50 -04:00
Arthur Hanson
9ca4c7315b 10595 extend graphql relationships (#10603)
* 9817 add graphql l2vpntermination assigned_object

* 9817 add graphql ipaddressassignment assigned_object

* 9817 ipan graphql gfk

* 9817 dcim graphql gfk

* 9817 dcim graphql gfk

* 9817 fix tests

* 10595 cable a_terminations to graphql

* 10595 add contacts to graphql

* 10595 move contacts to Provider
2022-10-11 12:26:18 -04:00
Arthur Hanson
ffce5d968d 8927 plugin search (#10489)
* #7016 base search classes

* 7016 add search indexes

* 7016 add search indexes

* 7016 add search indexes

* 7016 add search indexes

* 7016 add search indexes

* 7016 add search indexes

* 8927 refactor search

* 8927 refactor search

* 8927 refactor search

* 8927 refactor search

* 8927 get search choices working

* 8927 cleanup - optimize

* 8927 use backend search function

* 8927 fix for plugin search

* 8927 add docs

* Move search app to a module under netbox/

* Utilize global registry to register model search classes

* Build search form options from registry

* Determine search categories from model app by default

* Enable dynamic search registration for plugins

* Update docs & improve plugin support

* Clean up search backend class

* Docs for #8927

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-10-10 14:00:59 -04:00
jeremystretch
656f0b7d82 #9072: Add hide_if_empty argument to ViewTab 2022-10-10 08:11:29 -04:00
kkthxbye-code
ef0b455b05 Called super delete method before deleting JobResult task.
Done to avoid having deleted a task on accident if the deleting of the JobResult fails.
2022-10-09 21:16:26 +02:00
kkthxbye-code
679a9e839b Work on job scheduling:
* Added JobResult form filtersets
* Change housekeeping cleanup delete from `_raw_delete` to `delete` to make sure scheduled tasks are cancelled
* Change default sort of JobResult table to -created
* Added `delete` override to `JobResult` to remove scheduled tasks from RQ when a JobResult is deleted
* Updated js/css dist files. Will need to be redone when develop is merged to feature.
2022-10-09 21:05:31 +02:00
kkthxbye-code
53c8a48244 Merge branch 'feature' into 8366-job-scheduling
Sync with upstream
2022-10-09 11:18:47 +02:00
Jeremy Stretch
3f37914b3c Merge pull request #10609 from netbox-community/10608-registered-model-views
Closes #10608: Register all core model views using register_model_view()
2022-10-07 17:58:07 -04:00
jeremystretch
b0ba9bd83d Closes #10608: Register all core model views using register_model_view() 2022-10-07 17:17:58 -04:00
Jeremy Stretch
a3dbf4023c Merge pull request #10597 from netbox-community/9072-plugin-view-tabs
#9072: Custom model view tabs for plugins
2022-10-07 15:22:04 -04:00
jeremystretch
053c97b7a8 Docs and test for #9072 2022-10-07 15:03:52 -04:00
jeremystretch
1fc8de85a3 Add device NAPALM view tabs 2022-10-07 14:17:18 -04:00
jeremystretch
5e1a0733e4 Replace active_tab context for object views 2022-10-07 12:14:19 -04:00
jeremystretch
bfe26b46a6 Wrap model detail views with register_model_view() 2022-10-07 11:36:14 -04:00
jeremystretch
4c999daacd Introduce ViewTab 2022-10-07 10:54:34 -04:00
jeremystretch
663652f45e Changelog for #9478 2022-10-06 16:54:19 -04:00
Arthur Hanson
10bb8fa10a 9478 link peers to GraphQL (#10574)
* 9468 add link_peer to GraphQL

* 9478 add class_type

* 9478 fix tests

* 9478 fix tests

* 9478 fix tests
2022-10-06 16:50:53 -04:00
jeremystretch
a0bae06ff7 Replace static journaling, changelog URL paths with dynamic resolution 2022-10-06 16:21:23 -04:00
jeremystretch
0d7851ed9d #9072: Implement a mechanism for dynamically registering model detail views 2022-10-06 16:20:35 -04:00
jeremystretch
664d5db5eb Changelog for #10556 2022-10-05 15:53:50 -04:00
Jeremy Stretch
a1cc15a604 Merge pull request #10557 from netbox-community/10556-graphql-display
#10556 add display to GraphQL
2022-10-05 15:51:54 -04:00
Arthur Hanson
24ba840be7 10472 graphene 3 (#10473)
* update to Graphene 3.0.0

* 10472 exempt view permissions on tests

* 10472 exempt permission check on graphql tests
2022-10-05 15:50:17 -04:00
jeremystretch
a9e583a693 Changelog for #9669, #9722 2022-10-05 12:04:47 -04:00
Jeremy Stretch
3a3ff474cb Merge pull request #10567 from scanplus/ldap-ca-cert
Added LDAP_CA_CERT_* to LDAP settings
2022-10-05 12:01:39 -04:00
Arthur Hanson
cc00789d35 9669 sanitize social auth usernames (#10549) 2022-10-05 11:50:47 -04:00
Jeremy Stretch
689f11a573 Merge pull request #10555 from kkthxbye-code/10527-update-js-dependencies
Fixes #10527 - Update JS dependencies
2022-10-05 11:04:37 -04:00
jeremystretch
c481a1b6a2 Merge branch 'develop' into feature 2022-10-05 10:28:48 -04:00
jeremystretch
ae90ad1fb7 PRVB 2022-10-05 10:13:02 -04:00
Jeremy Stretch
56d9725c39 Merge pull request #10570 from netbox-community/develop
Release v3.3.5
2022-10-05 10:10:44 -04:00
jeremystretch
1c69bfaf2c Release v3.3.5 2022-10-05 09:47:55 -04:00
Tobias Genannt
5e37f82b2f Added LDAP_CA_CERT_* to LDAP settings
These options can be used to specify a CA certificate to validate the LDAP
server certificate
2022-10-05 14:28:30 +02:00
jeremystretch
bdefd8ea8c Fixes #10562: Correct URL for contacts table tags column 2022-10-05 08:13:33 -04:00
kkthxbye-code
eabd405845 Fix graphiql by pinning esbuild 2022-10-04 22:00:32 +02:00
jeremystretch
03946f2ca8 Fixes #10559: Permit the pinning of a VM to a particular device within a cluster which has no site assignment 2022-10-04 15:46:55 -04:00
jeremystretch
fec8d1bc2f Fixes #10423: Enforce object type validation when creating journal entries 2022-10-04 15:26:52 -04:00
jeremystretch
53f5f46037 #10460: Fix PowerFeed details 2022-10-04 14:36:14 -04:00
Arthur
81d99a0061 #10556 add display to GraphQL 2022-10-04 10:50:34 -07:00
kkthxbye-code
b227757b9a Update JS dependencies WIP 2022-10-04 15:02:37 +02:00
jeremystretch
eef5cefb5d Fixes #10460: Restore missing connection details for device components 2022-10-03 16:11:24 -04:00
jeremystretch
7712b81ab9 Fixes #10517: Automatically inherit site assignment from cluster when creating a virtual machine 2022-10-03 15:35:45 -04:00
jeremystretch
7feb86fe55 Changelog for #10352 2022-10-03 15:03:28 -04:00
PieterL75
d1efbf6620 Issue10352 removegetvariables (#10475)
* Add javascript to disable empty form fields

* add js cleanGetUrl

* use addEventListener submit

* use addEventListener

* update collectstatics

* Use FormData to remove empty fields

* optimeze ts-ignore

* update ts-ignore comment

* oneline of ts-ignore

* one line of ts-ingnore

* fix tsc errors by adding types (as per kkthxbye)

Co-authored-by: Pieter Lambrecht <pieter.lambrecht@sentia.com>
2022-10-03 14:32:01 -04:00
jeremystretch
aabee05a6a Changelog for #8424, #10491 2022-10-03 13:58:04 -04:00
jeremystretch
cf062b5b6a Closes #10346: Document how to access plugin config parameters 2022-10-03 13:56:46 -04:00
Arthur Hanson
0b6a3898fe 8424 device location (#10544)
* 8424 fix merge

* 8424 fix merge

* 8424 fix merge

* 8424 fix merge
2022-10-03 13:55:05 -04:00
Jeremy Stretch
517ebcfbcd Merge pull request #10525 from netbox-community/10491-delete-dependant
10491 improve error message for ProtectedError on contact assignment
2022-10-03 13:27:34 -04:00
jeremystretch
9ef24d3f43 Fixes #10513: Disable the reassignment of a module to a new device 2022-10-03 11:11:51 -04:00
jeremystretch
568e0c7ff6 Changelog for #9880 2022-09-30 17:30:18 -04:00
Jeremy Stretch
a454a3f74e Merge pull request #10502 from jsenecal/9880-allow-plugins-to-register-apps
Allow Plugins to register a list of Django apps to be appended to INSTALLED_APPS
2022-09-30 17:28:56 -04:00
jeremystretch
f7860138c7 Rename plugin_apps to django_apps for clarity 2022-09-30 17:18:12 -04:00
jeremystretch
0607295081 Docs cleanup 2022-09-30 17:18:12 -04:00
Jonathan Senecal
d4a7af8a89 Update plugins development docs 2022-09-30 17:18:12 -04:00
Jonathan Senecal
5c1417c4c7 PEP8 fixes 2022-09-30 17:18:12 -04:00
Jonathan Senecal
dc522a0135 Initial implementation
- Allows to specify a list of django-apps to be "installed" alongside the plugin.

(cherry picked from commit 6c7296200d756d2acbba3a589a7759f3a690cc48)
2022-09-30 17:18:12 -04:00
Jonathan Senecal
ac7db3cc88 Tidy-up imports and typing
(cherry picked from commit adee5cf6a8856ceda0170a4382cec8fd784be93b)
2022-09-30 17:18:12 -04:00
Patrick Hurrelmann
5cc55d1e99 Fixes: #10465 Format all remaining displayed rackunits with floatformat (#10481)
* Fixes: #10465 Try to finish #10268 and format all remaining displayed rackunits with floatformat

* #10465: PEP8 fix

Co-authored-by: Patrick Hurrelmann <patrick.hurrelmann@nfon.com>
Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-09-30 17:18:12 -04:00
jeremystretch
10352ff5ad Merge branch 'develop' into feature 2022-09-30 17:17:18 -04:00
jeremystretch
97d561ac33 Changelog for #9654, #10348 2022-09-30 16:37:07 -04:00
Arthur Hanson
204c10c053 9654 device weight (#10448)
* 9654 add weight fields to devices

* 9654 changes from code review

* 9654 change _abs_weight to grams

* Resolve migrations conflict

* 9654 code-review changes

* 9654 total weight on devices

* Misc cleanup

Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-09-30 16:31:04 -04:00
Arthur Hanson
af8bb0c4b9 10348 add decimal custom field (#10422)
* 10348 add decimal custom field

* 10348 fix tests

* 10348 add documentation

* Rearrange custom fields to be ordered consistently

* Rename number_field to integer_field for clarity

* Clean up validation logic

* Apply suggested changes from PR

* Store decimal custom field values natively

* Fix filter test

* Update custom field model migrations to use new encoder

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-09-30 16:03:24 -04:00
jeremystretch
ada5c58acf Closes #10529: Run validation on each value of a multi-value filter 2022-09-30 15:05:13 -04:00
Arthur
02ffc2ddee 10491 improve error message for ProtectedError on contact assignment 2022-09-30 09:09:21 -07:00
jeremystretch
62820ea2b8 Add workflow_dispatch event 2022-09-29 12:36:10 -04:00
jeremystretch
04738587e8 Move permissions block to root 2022-09-29 12:17:10 -04:00
jeremystretch
cbbfcd0e7b Bump stale to v6 2022-09-29 12:00:44 -04:00
jeremystretch
309a70df89 Tweak workflow permissions 2022-09-29 11:59:15 -04:00
Alex
4cb6984a65 GitHub Workflows security hardening (#10456)
* build: harden lock.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden stale.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden ci.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

Signed-off-by: Alex <aleksandrosansan@gmail.com>
2022-09-29 11:41:33 -04:00
jeremystretch
d486fa8452 Changelog for #9045, #9046, #9071 2022-09-28 17:18:31 -04:00
Jeremy Stretch
c95ad5b208 Merge pull request #10441 from netbox-community/9071-plugin-menu
9071 add header to plugin menu
2022-09-28 17:08:10 -04:00
Jeremy Stretch
5382ac20b6 Merge pull request #10488 from netbox-community/9249-device-vm-names
Closes #9249: Ignore case for device/VM names
2022-09-28 17:05:57 -04:00
jeremystretch
3fbd514417 Add test for plugin menu registration 2022-09-28 16:57:40 -04:00
jeremystretch
d0465242a3 Add documentation for PluginMenu 2022-09-28 16:44:16 -04:00
jeremystretch
db90b084cf Enable plugins to create root-level navigation menus 2022-09-28 16:08:03 -04:00
jeremystretch
00d2dcda68 Refactor navigation resources and menu 2022-09-28 15:56:09 -04:00
Arthur Hanson
20e3fdc782 #9045 #9046 - remove legacy fields from Provider (#10377)
* #9045 - remove legacy fields from Provider

* Add safegaurd for legacy data to migration

* 9045 remove fields from forms and tables

* Update unrelated tests to use ASN model instead of Provider

* Fix migrations collision

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-09-28 15:22:19 -04:00
jeremystretch
3c32c09a5a Fixes #10496: Use page.canonical_url to identify ReadTheDocs builds 2022-09-28 09:30:38 -04:00
jeremystretch
ad6a7086c4 Changelog for #9249 2022-09-27 16:52:14 -04:00
jeremystretch
e977333177 Update device/VM name filters to be case-insensitive 2022-09-27 16:48:39 -04:00
jeremystretch
1d4f828b93 Device/VM unique constraints ignore case for name field 2022-09-27 16:47:56 -04:00
Jeremy Stretch
c349e06346 Merge pull request #10368 from netbox-community/10361-unique-constraints
Closes #10361: Migrate from unique_together to UniqueConstraints
2022-09-27 15:55:44 -04:00
jeremystretch
7ff2cb75a8 Use templated app & model names for all unique constraints 2022-09-27 15:44:38 -04:00
jeremystretch
f51415cf2c Replace unique_together with UniqueConstraints 2022-09-27 15:35:24 -04:00
jeremystretch
ec6457bcd3 Remove custom validate_unique() methods 2022-09-27 14:28:21 -04:00
jeremystretch
2d9852d6f1 Fixes #10408: Fix validation when attempting to add redundant contact assignments 2022-09-27 13:11:57 -04:00
jeremystretch
05542324fc Changelog for #10465, #10480 2022-09-27 11:53:11 -04:00
Patrick Hurrelmann
669e86f96e Fixes: #10465 Format all remaining displayed rackunits with floatformat (#10481)
* Fixes: #10465 Try to finish #10268 and format all remaining displayed rackunits with floatformat

* #10465: PEP8 fix

Co-authored-by: Patrick Hurrelmann <patrick.hurrelmann@nfon.com>
Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-09-27 11:24:19 -04:00
Jeremy Stretch
cbf928f363 Merge pull request #10482 from phurrelmann/10480-fix-link-target-on-cable-svg
Fixes: #10480 Fix link-target on cable-trace svg
2022-09-27 11:07:14 -04:00
jeremystretch
6016e1b15d Changelog & cleanup for #9892 2022-09-27 09:55:35 -04:00
Jeremy Stretch
d08d5620da Merge pull request #10424 from netbox-community/9892-fhrpgroup-name
9892 fhrpgroup name
2022-09-27 09:48:11 -04:00
Patrick Hurrelmann
43b18c13e3 Fixes: #10480 Fix link-target on cable-trace svg to open link in the same window. 2022-09-27 13:23:51 +02:00
Arthur
7deb9fde9e 9071 add documentation 2022-09-26 14:41:46 -07:00
Arthur
b134d2a7b0 9071 fix test 2022-09-26 14:23:53 -07:00
Arthur
36f31228ff Merge branch 'feature' into 9071-plugin-menu 2022-09-26 14:09:44 -07:00
Arthur
8103ad3b9e 9892 add name to str 2022-09-26 13:57:09 -07:00
Arthur
10cb3c2c3d 9892 add name to str 2022-09-26 13:54:49 -07:00
jeremystretch
dda193247a Fixes #10470: Omit read-only custom fields from CSV import forms 2022-09-26 16:47:34 -04:00
jeremystretch
2463e4efd3 Fixes #10461: Enable filtering by read-only custom fields in the UI 2022-09-26 16:42:11 -04:00
Arthur
5ce805db2e 9892 doh - fix tests 2022-09-26 12:56:16 -07:00
jeremystretch
a0b17887fd Fixes #10445: Avoid rounding virtual machine memory values 2022-09-26 15:45:58 -04:00
Arthur
3eeb31d577 9892 doh - fix tests 2022-09-26 11:49:51 -07:00
Arthur
e11d594122 9892 add supporting tests, form fields 2022-09-26 11:39:43 -07:00
Arthur
600c437af5 Merge branch 'feature' into 9892-fhrpgroup-name 2022-09-26 11:10:25 -07:00
jeremystretch
0280ddcbe9 Merge branch 'develop' into feature 2022-09-26 11:55:58 -04:00
jeremystretch
96784640e3 Changelog for #10435, #10439 2022-09-26 10:27:35 -04:00
Jeremy Stretch
b75d12fe05 Merge pull request #10442 from netbox-community/10435-untagged-vlan
10435 check if vm.cluster in qs
2022-09-26 10:25:48 -04:00
Jeremy Stretch
5e389c32ed Merge pull request #10463 from netbox-community/revert-10410-10408-add-contact
Revert "10408 add error message if already exists"
2022-09-26 10:24:54 -04:00
Jeremy Stretch
fd89ef04b6 Revert "10408 add error message if already exists" 2022-09-26 10:24:40 -04:00
Jeremy Stretch
abcc10e938 Merge pull request #10410 from netbox-community/10408-add-contact
10408 add error message if already exists
2022-09-26 10:24:23 -04:00
jeremystretch
3ad337dd15 Filter VLANs and VLANGroups by site or cluster site for VM 2022-09-26 10:08:54 -04:00
Jeremy Stretch
a527767caa Merge pull request #10455 from miaow2/10439-airlow-widget
10439 Add widget for Airflow field in DeviceTypeForm
2022-09-26 09:20:48 -04:00
Arthur Hanson
39129ecedf 10407 fix documentation link to requests (#10409)
* 10407 fix documentation link to requests

* Append page heading to URL

Co-authored-by: jeremystretch <jstretch@ns1.com>
2022-09-26 09:17:02 -04:00
Artem I. Kotik
c97d2d4fe9 Add widget for Airflow field in DeviceTypeForm 2022-09-24 15:49:23 +04:00
Arthur
5a018afbc4 Merge branch 'develop' into feature 2022-09-23 12:37:19 -07:00
kkthxbye-code
06dea8ef3f WIP: Moving JobResults out of the admin panel 2022-09-23 13:44:24 +02:00
kkthxbye-code
cbb3378d10 Job Scheduling WIP 2022-09-23 06:45:40 +02:00
Arthur
7735634649 10435 check if vm.cluster in qs 2022-09-22 10:34:37 -07:00
Arthur
e074570b8f 9071 add header to plugin menu 2022-09-22 10:01:19 -07:00
Jonathan Senecal
148c6a6c23 Merge pull request #10432 from netbox-community/10431-pylance-is-no-longer-working-by-default-in-vscode
Add [tool.pyright] to pyproject.toml and fix #10431
2022-09-21 15:33:25 -04:00
Jonathan Senecal
360172cad0 Add [tool.pyright] to pyproject.toml 2022-09-21 15:19:40 -04:00
Arthur
a5421ae170 9892 add FHRP group name 2022-09-20 16:13:01 -07:00
Arthur
5d07f2c837 9892 add FHRP group name 2022-09-20 16:03:55 -07:00
Arthur
e95708fe08 Merge branch 'develop' into feature 2022-09-20 08:52:37 -07:00
Daniel Sheppard
75c91232b4 Update changelog for #9497 2022-09-20 09:49:46 -05:00
Daniel Sheppard
0190c0225e Merge pull request #10420 from netbox-community/9497-fix-site-location-nonracked-device-display
Fixes #9497 - Change non-racked filter for sites/locations
2022-09-20 09:48:09 -05:00
Daniel Sheppard
86d366be4d Fixes #9651 - Document Pre-Change process for scripts 2022-09-20 09:46:23 -05:00
Daniel Sheppard
71d71a6b1b Fixes #9497 - Change filter for sites/locations 2022-09-20 09:26:40 -05:00
kkthxbye
c8671ce8e8 Update yarn.lock (flatpickr bump) 2022-09-20 08:53:57 +02:00
Arthur
ed3d04c7ba Merge branch 'develop' into feature 2022-09-19 15:51:54 -07:00
Arthur
695ad47fe9 10408 add error message if already exists 2022-09-19 10:46:16 -07:00
kkthxbye
25ac1edb48 Merge branch 'netbox-community:develop' into 8366-job-scheduling 2022-09-18 15:08:11 +02:00
kkthxbye-code
824b4e0923 Add scheduling for reports and scripts 2022-09-18 15:06:28 +02:00
jeremystretch
1b62c11db5 PRVB 2022-09-16 13:41:09 -04:00
Jeremy Stretch
83a66a672d Merge pull request #10391 from netbox-community/develop
Release v3.3.4
2022-09-16 13:39:06 -04:00
jeremystretch
30b9ddc251 Release v3.3.4 2022-09-16 13:14:14 -04:00
jeremystretch
4a9831bd23 Fixes #10383: Fix assignment of component templates to module types via web UI 2022-09-16 08:30:46 -04:00
jeremystretch
59388d89a0 Fixes #10387: Fix MultiValueDictKeyError exception when editing a device interface 2022-09-16 08:20:24 -04:00
jeremystretch
1d033bd286 Update lock threads action; lock closed PRs after 30 days 2022-09-15 16:08:43 -04:00
jeremystretch
1eb0e5d307 Merge branch 'develop' into feature 2022-09-15 14:30:24 -04:00
jeremystretch
935f008c16 PRVB 2022-09-15 14:29:43 -04:00
jeremystretch
4208dbd514 Closes #10358: Raise minimum required PostgreSQL version from 10 to 11 2022-09-14 17:10:14 -04:00
jeremystretch
6a9274a95f Closes #10314: Move clone() method from NetBoxModel to CloningMixin 2022-09-13 14:36:37 -04:00
jeremystretch
87af94a7d2 Merge branch 'develop' into feature 2022-09-13 14:24:58 -04:00
Jeremy Stretch
cd5581aada Merge pull request #10341 from netbox-community/10172-upgrade-django
10172 upgrade django
2022-09-13 13:38:27 -04:00
Arthur
ce6bf9e5c1 #10172 fixes for Django 4.1 2022-09-12 09:59:37 -07:00
Arthur
27d72746ca #10172 upgrade Django to 4.1.1 2022-09-08 13:20:27 -07:00
547 changed files with 19430 additions and 10709 deletions

View File

@@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.3.3
placeholder: v3.4.3
validations:
required: true
- type: dropdown
@@ -25,6 +25,7 @@ body:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
validations:
required: true
- type: textarea

View File

@@ -19,11 +19,15 @@ body:
label: Area
description: To what section of the documentation does this change primarily pertain?
options:
- Installation instructions
- Configuration parameters
- Functionality/features
- REST API
- Administration/development
- Features
- Installation/upgrade
- Getting started
- Configuration
- Customization
- Integrations/API
- Plugins
- Administration
- Development
- Other
validations:
required: true

View File

@@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.3.3
placeholder: v3.4.3
validations:
required: true
- type: dropdown

View File

@@ -1,13 +1,14 @@
<!--
Thank you for your interest in contributing to NetBox! Please note that
our contribution policy requires that a feature request or bug report be
approved and assigned prior to filing a pull request. This helps avoid
wasting time and effort on something that we might not be able to accept.
approved and assigned prior to opening a pull request. This helps avoid
waste time and effort on a proposed change that we might not be able to
accept.
IF YOUR PULL REQUEST DOES NOT REFERENCE AN ISSUE WHICH HAS BEEN ASSIGNED
TO YOU, IT WE BE CLOSED AUTOMATICALLY.
TO YOU, IT WILL BE CLOSED AUTOMATICALLY.
Specify your assigned issue number on the line below.
Please specify your assigned issue number on the line below.
-->
### Fixes: #1234

View File

@@ -1,5 +1,7 @@
name: CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -7,7 +9,7 @@ jobs:
NETBOX_CONFIGURATION: netbox.configuration_testing
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10', '3.11']
node-version: ['14.x']
services:
redis:

View File

@@ -4,18 +4,18 @@ name: 'Lock threads'
on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
- uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '90'
issue-exclude-created-before: ''
issue-exclude-labels: ''
issue-lock-labels: ''
issue-lock-comment: ''
issue-inactive-days: 90
pr-inactive-days: 30
issue-lock-reason: 'resolved'
process-only: 'issues'

View File

@@ -1,14 +1,21 @@
# close-stale-issues (https://github.com/marketplace/actions/close-stale-issues)
name: 'Close stale issues/PRs'
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
- uses: actions/stale@v6
with:
close-issue-message: >
This issue has been automatically closed due to lack of activity. In an

View File

@@ -1,188 +1,115 @@
## Getting Help
**Looking for help?** NetBox has a vast, active community of fellow users that may be able to provide assistance. Just [start a discussion](https://github.com/netbox-community/netbox/discussions/new) right here on GitHub! Or if you'd prefer to chat, join us live in the `#netbox` channel on the [NetDev Community Slack](https://netdev.chat/)!
If you encounter any issues installing or using NetBox, try one of the
following resources to get assistance. Please **do not** open a GitHub issue
except to report bugs or request features.
<div align="center">
<h3>
:bug: <a href="#bug-reporting-bugs">Report a bug</a> &middot;
:bulb: <a href="#bulb-feature-requests">Suggest a feature</a> &middot;
:arrow_heading_up: <a href="#arrow_heading_up-submitting-pull-requests">Submit a pull request</a>
</h3>
<h3>
:jigsaw: <a href="#jigsaw-creating-plugins">Create a plugin</a> &middot;
:rescue_worker_helmet: <a href="#rescue_worker_helmet-become-a-maintainer">Become a maintainer</a> &middot;
:heart: <a href="#heart-other-ways-to-contribute">Other ideas</a>
</h3>
</div>
<h3></h3>
### GitHub Discussions
Some general tips for engaging here on GitHub:
GitHub's discussions are the best place to get help or propose rough ideas for
new functionality. Their integration with GitHub allows for easily cross-
referencing and converting posts to issues as needed. There are several
categories for discussions:
* Register for a free [GitHub account](https://github.com/signup) if you haven't already.
* You can use [GitHub Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) for formatting text and adding images.
* To help mitigate notification spam, please avoid "bumping" issues with no activity. (To vote an issue up or down, use a :thumbsup: or :thumbsdown: reaction.)
* Please avoid pinging members with `@` unless they've previously expressed interest or involvement with that particular issue.
* **General** - General community discussion
* **Ideas** - Ideas for new functionality that isn't yet ready for a formal
feature request
* **Q&A** - Request help with installing or using NetBox
## :bug: Reporting Bugs
### Slack
* First, ensure that you're running the [latest stable version](https://github.com/netbox-community/netbox/releases) of NetBox. If you're running an older version, it's likely that the bug has already been fixed.
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.
* Next, search our [issues list](https://github.com/netbox-community/netbox/issues?q=is%3Aissue) to see if the bug you've found has already been reported. If you come across a bug report that seems to match, please click "add a reaction" in the top right corner of the issue and add a thumbs up (:thumbsup:). This will help draw more attention to it. Any comments you can add to provide additional information or context would also be much appreciated.
## Reporting Bugs
* If you can't find any existing issues (open or closed) that seem to match yours, you're welcome to [submit a new bug report](https://github.com/netbox-community/netbox/issues/new?label=type%3A+bug&template=bug_report.yaml). Be sure to complete the entire report template, including detailed steps that someone triaging your issue can follow to confirm the reported behavior. (If we're not able to replicate the bug based on the information provided, we'll ask for additional detail.)
* First, ensure that you're running the [latest stable version](https://github.com/netbox-community/netbox/releases)
of NetBox. If you're running an older version, it's possible that the bug has
already been fixed.
* Next, check the GitHub [issues list](https://github.com/netbox-community/netbox/issues)
to see if the bug you've found has already been reported. If you think you may
be experiencing a reported issue that hasn't already been resolved, please
click "add a reaction" in the top right corner of the issue and add a thumbs
up (+1). You might also want to add a comment describing how it's affecting your
installation. This will allow us to prioritize bugs based on how many users are
affected.
* When submitting an issue, please be as descriptive as possible. Be sure to
provide all information request in the issue template, including:
* The environment in which NetBox is running
* The exact steps that can be taken to reproduce the issue
* Expected and observed behavior
* Any error messages generated
* Screenshots (if applicable)
* Please avoid prepending any sort of tag (e.g. "[Bug]") to the issue title.
The issue will be reviewed by a maintainer after submission and the appropriate
labels will be applied for categorization.
* Keep in mind that we prioritize bugs based on their severity and how much
work is required to resolve them. It may take some time for someone to address
your issue.
* Some other tips to keep in mind:
* Error messages and screenshots are especially helpful.
* Don't prepend your issue title with a label like `[Bug]`; the proper label will be assigned automatically.
* Ensure that your reproduction instructions don't reference data in our [demo instance](https://demo.netbox.dev/), which gets rebuilt nightly.
* Verify that you have GitHub notifications enabled and are subscribed to your issue after submitting.
* We appreciate your patience as bugs are prioritized by their severity, impact, and difficulty to resolve.
* For more information on how bug reports are handled, please see our [issue
intake policy](https://github.com/netbox-community/netbox/wiki/Issue-Intake-Policy).
## Feature Requests
## :bulb: Feature Requests
* First, check the GitHub [issues list](https://github.com/netbox-community/netbox/issues)
to see if the feature you're requesting is already listed. (Be sure to search
closed issues as well, since some feature requests have been rejected.) If the
feature you'd like to see has already been requested and is open, click "add a
reaction" in the top right corner of the issue and add a thumbs up (+1). This
ensures that the issue has a better chance of receiving attention. Also feel
free to add a comment with any additional justification for the feature.
(However, note that comments with no substance other than a "+1" will be
deleted. Please use GitHub's reactions feature to indicate your support.)
* First, check the GitHub [issues list](https://github.com/netbox-community/netbox/issues?q=is%3Aissue) to see if the feature you have in mind has already been proposed. If you happen to find an open feature request that matches your idea, click "add a reaction" in the top right corner of the issue and add a thumbs up (:thumbsup:). This ensures that the issue has a better chance of receiving attention. Also feel free to add a comment with any additional justification for the feature.
* Before filing a new feature request, consider raising your idea in a
[GitHub discussion](https://github.com/netbox-community/netbox/discussions)
first. Feedback you receive there will help validate and shape the proposed
feature before filing a formal issue.
* If you have a rough idea that's not quite ready for formal submission yet, start a [GitHub discussion](https://github.com/netbox-community/netbox/discussions) instead. This is a great way to test the viability and narrow down the scope of a new feature prior to submitting a formal proposal, and can serve to generate interest in your idea from other community members.
* Good feature requests are very narrowly defined. Be sure to thoroughly
describe the functionality and data model(s) being proposed. The more effort
you put into writing a feature request, the better its chance is of being
implemented. Overly broad feature requests will be closed.
* Once you're ready, submit a feature request [using this template](https://github.com/netbox-community/netbox/issues/new?label=type%3A+feature&template=feature_request.yaml). Be sure to provide sufficient context and detail to convey exactly what you're proposing and why. The stronger your use case, the better chance your proposal has of being accepted.
* When submitting a feature request on GitHub, be sure to include all
information requested by the issue template, including:
* Some other tips to keep in mind:
* Don't prepend your issue title with a label like `[Feature]`; the proper label will be assigned automatically.
* Try to anticipate any likely questions about your proposal and provide that information proactively.
* Verify that you have GitHub notifications enabled and are subscribed to your issue after submitting.
* You're welcome to volunteer to implement your FR, but don't submit a pull request until it has been approved.
* A detailed description of the proposed functionality
* A use case for the feature; who would use it and what value it would add
to NetBox
* A rough description of changes necessary to the database schema (if
applicable)
* Any third-party libraries or other resources which would be involved
* For more information on how feature requests are handled, please see our [issue intake policy](https://github.com/netbox-community/netbox/wiki/Issue-Intake-Policy).
* Please avoid prepending any sort of tag (e.g. "[Feature]") to the issue
title. The issue will be reviewed by a moderator after submission and the
appropriate labels will be applied for categorization.
## :arrow_heading_up: Submitting Pull Requests
* For more information on how feature requests are handled, please see our
[issue intake policy](https://github.com/netbox-community/netbox/wiki/Issue-Intake-Policy).
* [Pull requests](https://docs.github.com/en/pull-requests) (a feature of GitHub) are used to propose changes to NetBox's code base. Our process generally goes like this:
* A user opens a new issue (bug report or feature request)
* A maintainer triages the issue and may mark it as needing an owner
* The issue's author can volunteer to own it, or someone else can
* A maintainer assigns the issue to whomever volunteers
* The issue owner submits a pull request that will resolve the issue
* A maintainer reviews and merges the pull request, closing the issue
## Submitting Pull Requests
* It's very important that you not submit a pull request until a relevant issue has been opened **and** assigned to you. Otherwise, you risk wasting time on work that may ultimately not be needed.
* If you're interested in contributing to NetBox, be sure to check out our
[getting started](https://docs.netbox.dev/en/stable/development/getting-started/)
documentation for tips on setting up your development environment.
* New pull requests should generally be based off of the `develop` branch, rather than `master`. The `develop` branch is used for ongoing development, while `master` is used for tracking stable releases. (If you're developing for an upcoming minor release, use `feature` instead.)
* Be sure to open an issue and wait for it to be assigned to you **before**
starting work on a pull request, and discuss your idea with the NetBox
maintainers before beginning work. This will help prevent wasting time on
proposed changes that we might not be able to accept. When suggesting a new
feature, also make sure it won't conflict with any work that's already in
progress.
* In most cases, it is not necessary to add a changelog entry: A maintainer will take care of this when the PR is merged. (This helps avoid merge conflicts resulting from multiple PRs being submitted simultaneously.)
* Once you've opened or identified an issue you'd like to work on, ask that it
be assigned to you so that others are aware it's being worked on. If it meets
the acceptance criteria, a maintainer will then mark the issue as "accepted"
and assign it to you. (Note that GitHub requires that a user first comment on
an issue before it can be assigned to that user.)
* Any pull request which does not relate to an **assigned** issue will be
closed.
* All new functionality must include relevant tests where applicable.
* When submitting a pull request, please be sure to work off of the `develop`
branch, rather than `master`. The `develop` branch is used for ongoing
development, while `master` is used for tagging stable releases. (If you're
developing for the next minor release, use `feature` instead.)
* In most cases, it is not necessary to add a changelog entry: A maintainer will
take care of this when the PR is merged. (This helps avoid merge conflicts
resulting from multiple PRs being submitted simultaneously.)
* All code submissions should meet the following criteria (CI will enforce
these checks):
* Python syntax is valid
* All tests pass when run with `./manage.py test`
* PEP 8 compliance is enforced, with the exception that lines may be
* All code submissions should meet the following criteria (CI will enforce these checks):
* Python syntax is valid
* All tests pass when run with `./manage.py test`
* PEP 8 compliance is enforced, with the exception that lines may be
greater than 80 characters in length
## Commenting
* Some other tips to keep in mind:
* If you'd like to volunteer for someone else's issue, please post a comment on that issue letting us know. (This will allow the maintainers to assign it to you.)
* Check out our [developer docs](https://docs.netbox.dev/en/stable/development/getting-started/) for tips on setting up your development environment.
* All new functionality must include relevant tests where applicable.
Only comment on an issue if you are sharing a relevant idea or constructive
feedback. **Do not** comment on an issue just to show your support (give the
top post a :+1: instead) or to ask for an update. Doing so generates
unnecessary noise in the discussion, and is especially annoying for people who
have subscribed to updates for the issue. Any comments without substance
relevant to the discussion will be deleted.
## :jigsaw: Creating Plugins
## Issue Lifecycle
Do you have an idea for something you'd like to build in NetBox, but might not be right for the core project? NetBox includes a powerful and extensive [plugins framework](https://docs.netbox.dev/en/stable/plugins/) that enables users to develop their own custom data models and integrations.
New issues are handled according to our [issue intake policy](https://github.com/netbox-community/netbox/wiki/Issue-Intake-Policy).
Maintainers will assign label(s) and/or close new issues as the policy
dictates. This helps ensure a productive development environment and avoid
accumulating a large backlog of work.
Check out our [plugin development tutorial](https://github.com/netbox-community/netbox-plugin-tutorial) to get started!
The core maintainers group has chosen to make use of GitHub's [Stale bot](https://github.com/apps/stale)
to aid in issue management.
## :rescue_worker_helmet: Become a Maintainer
* Issues will be marked as stale after 60 days of no activity.
* If the stable label is not removed in the following 30 days, the issue will
be closed automatically.
* Any issue bearing one of the following labels will be exempt from all Stale
bot actions:
* `status: accepted`
* `status: blocked`
* `status: needs milestone`
We're always looking for motivated individuals to join the maintainers team and help drive NetBox's long-term development. Some of our most sought-after skills include:
It is natural that some new issues get more attention than others. The stale
bot helps bring renewed attention to potentially valuable issues that may have
been overlooked. **Do not** comment on a stale issue merely to "bump" it in an
effort to circumvent the bot: This will result in the immediate closure of the
issue, and you may be barred from participating in future discussions.
* Python development with a strong focus on the [Django](https://www.djangoproject.com/) framework
* Expertise working with PostgreSQL databases
* Javascript & TypeScript proficiency
* A knack for web application design (HTML & CSS)
* Familiarity with git and software development best practices
* Excellent attention to detail
* Working experience in the field of network operations & engineering
## Maintainer Guidance
We generally ask that maintainers dedicate around four hours of work to the project each week on average, which includes both hands-on development and project management tasks such as issue triage. Maintainers are also encouraged (but not required) to attend our bi-weekly Zoom call to catch up on recent items.
* Maintainers are expected to contribute at least four hours per week to the
project on average. This can be employer-sponsored or individual time, with
the understanding that all contributions are submitted under the Apache 2.0
license and that your employer may not make claim to any contributions.
Contributions include code work, issue management, and community support. All
development must be in accordance with our [development guidance](https://docs.netbox.dev/en/stable/development/).
Many maintainers petition their employer to grant some of their paid time to work on NetBox. In doing so, your employer becomes eligible to be featured as a [NetBox sponsor](https://github.com/netbox-community/netbox/wiki/Sponsorship).
* Maintainers are expected to attend (where feasible) our biweekly ~30-minute
sync to review agenda items. This meeting provides opportunity to present and
discuss pressing topics. Meetings are held as virtual audio/video conferences.
Interested? You can contact our lead maintainer, Jeremy Stretch, at jeremy@netbox.dev or on the [NetDev Community Slack](https://netdev.chat/). We'd love to have you on the team!
* Maintainers with no substantial recorded activity in a 60-day period will be
removed from the project.
## :heart: Other Ways to Contribute
You don't have to be a developer to contribute to NetBox: There are plenty of other ways you can add value to the community! Below are just a few examples:
* Help answer questions and provide feedback in our [GitHub discussions](https://github.com/netbox-community/netbox/discussions) and on [Slack](https://netdev.chat/).
* Write a blog article or record a YouTube video demonstrating how NetBox is used at your organization.
* Help grow our [library of device & module type definitions](https://github.com/netbox-community/devicetype-library).

View File

@@ -19,7 +19,7 @@ employed by thousands of organizations around the world.
## About NetBox
![Screenshot of Netbox UI](docs/media/screenshots/netbox-ui.png "NetBox UI")
![Screenshot of NetBox UI](docs/media/screenshots/netbox-ui.png "NetBox UI")
Myriad infrastructure components can be modeled in NetBox, including:

View File

@@ -4,7 +4,7 @@ bleach
# The Python web framework on which NetBox is built
# https://github.com/django/django
Django<4.1
Django<4.2
# Django middleware which permits cross-domain API requests
# https://github.com/OttoYiu/django-cors-headers
@@ -80,7 +80,8 @@ Jinja2
# Simple markup language for rendering HTML
# https://github.com/Python-Markdown/markdown
Markdown
# mkdocs currently requires Markdown v3.3
Markdown<3.4
# File inclusion plugin for Python-Markdown
# https://github.com/cmacmackin/markdown-include

View File

@@ -1,4 +1,4 @@
# The IP address (typically localhost) and port that the Netbox WSGI process should listen on
# The IP address (typically localhost) and port that the NetBox WSGI process should listen on
bind = '127.0.0.1:8001'
# Number of gunicorn workers to spawn. This should typically be 2n+1, where

View File

@@ -2,8 +2,8 @@
{% block site_meta %}
{{ super() }}
{# Disable search indexing unless we're building for ReadTheDocs #}
{% if not config.extra.readthedocs %}
{# Disable search indexing unless we're building for ReadTheDocs (see #10496) #}
{% if page.canonical_url != 'https://docs.netbox.dev/' %}
<meta name="robots" content="noindex">
{% endif %}
{% endblock %}

View File

@@ -58,9 +58,11 @@ The following model fields support configurable choices:
* `circuits.Circuit.status`
* `dcim.Device.status`
* `dcim.Location.status`
* `dcim.Module.status`
* `dcim.PowerFeed.status`
* `dcim.Rack.status`
* `dcim.Site.status`
* `dcim.VirtualDeviceContext.status`
* `extras.JournalEntry.kind`
* `ipam.IPAddress.status`
* `ipam.IPRange.status`
@@ -68,6 +70,7 @@ The following model fields support configurable choices:
* `ipam.VLAN.status`
* `virtualization.Cluster.status`
* `virtualization.VirtualMachine.status`
* `wireless.WirelessLAN.status`
The following colors are supported:

View File

@@ -141,6 +141,22 @@ When determining the primary IP address for a device, IPv6 is preferred over IPv
---
## QUEUE_MAPPINGS
Allows changing which queues are used internally for background tasks.
```python
QUEUE_MAPPINGS = {
'webhook': 'low',
'report': 'high',
'script': 'high',
}
```
If no queue is defined the queue named `default` will be used.
---
## RELEASE_CHECK_URL
Default: None (disabled)

View File

@@ -25,7 +25,7 @@ ALLOWED_HOSTS = ['*']
## DATABASE
NetBox requires access to a PostgreSQL 10 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary:
NetBox requires access to a PostgreSQL 11 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary:
* `NAME` - Database name
* `USER` - PostgreSQL username
@@ -63,6 +63,7 @@ Redis is configured using a configuration setting similar to `DATABASE` and thes
* `HOST` - Name or IP address of the Redis server (use `localhost` if running locally)
* `PORT` - TCP port of the Redis service; leave blank for default port (6379)
* `USERNAME` - Redis username (if set)
* `PASSWORD` - Redis password (if set)
* `DATABASE` - Numeric database ID
* `SSL` - Use SSL connection to Redis
@@ -75,6 +76,7 @@ REDIS = {
'tasks': {
'HOST': 'redis.example.com',
'PORT': 1234,
'USERNAME': 'netbox'
'PASSWORD': 'foobar',
'DATABASE': 0,
'SSL': False,
@@ -82,6 +84,7 @@ REDIS = {
'caching': {
'HOST': 'localhost',
'PORT': 6379,
'USERNAME': ''
'PASSWORD': '',
'DATABASE': 1,
'SSL': False,

View File

@@ -1,5 +1,13 @@
# Security & Authentication Parameters
## ALLOW_TOKEN_RETRIEVAL
Default: True
If disabled, the values of API tokens will not be displayed after each token's initial creation. A user **must** record the value of a token immediately upon its creation, or it will be lost. Note that this affects _all_ users, regardless of assigned permissions.
---
## ALLOWED_URL_SCHEMES
!!! tip "Dynamic Configuration Parameter"
@@ -129,6 +137,14 @@ The lifetime (in seconds) of the authentication cookie issued to a NetBox user u
---
## LOGOUT_REDIRECT_URL
Default: `'home'`
The view name or URL to which a user is redirected after logging out.
---
## SESSION_COOKIE_NAME
Default: `sessionid`

View File

@@ -12,6 +12,17 @@ BASE_PATH = 'netbox/'
---
## DEFAULT_LANGUAGE
Default: `en-us` (US English)
Defines the default preferred language/locale for requests that do not specify one. This is used to alter e.g. the display of dates and numbers to fit the user's locale. See [this list](http://www.i18nguy.com/unicode/language-identifiers.html) of standard language codes. (This parameter maps to Django's [`LANGUAGE_CODE`](https://docs.djangoproject.com/en/stable/ref/settings/#language-code) internal setting.)
!!! note
Altering this parameter will *not* change the language used in NetBox. We hope to provide translation support in a future NetBox release.
---
## DOCS_ROOT
Default: `$INSTALL_ROOT/docs/`
@@ -54,11 +65,19 @@ Email is sent from NetBox only for critical events or if configured for [logging
---
## ENABLE_LOCALIZATION
Default: False
Determines if localization features are enabled or not. This should only be enabled for development or testing purposes as netbox is not yet fully localized. Turning this on will localize numeric and date formats (overriding what is set for DATE_FORMAT) based on the browser locale as well as translate certain strings from third party modules.
---
## HTTP_PROXIES
Default: None
A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://2.python-requests.org/en/master/user/advanced/). For example:
A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies). For example:
```python
HTTP_PROXIES = {
@@ -157,6 +176,14 @@ The file path to the location where [custom scripts](../customization/custom-scr
---
## SEARCH_BACKEND
Default: `'netbox.search.backends.CachedValueSearchBackend'`
The dotted path to the desired search backend class. `CachedValueSearchBackend` is currently the only search backend provided in NetBox, however this setting can be used to enable a custom backend.
---
## STORAGE_BACKEND
Default: None (local storage)

View File

@@ -13,6 +13,7 @@ Custom fields may be created by navigating to Customization > Custom Fields. Net
* Text: Free-form text (intended for single-line use)
* Long text: Free-form of any length; supports Markdown rendering
* Integer: A whole number (positive or negative)
* Decimal: A fixed-precision decimal number (4 decimal places)
* Boolean: True or false
* Date: A date in ISO 8601 format (YYYY-MM-DD)
* URL: This will be presented as a link in the web UI

View File

@@ -129,6 +129,19 @@ The Script object provides a set of convenient functions for recording messages
Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages.
## Change Logging
To generate the correct change log data when editing an existing object, a snapshot of the object must be taken before making any changes to the object.
```python
if obj.pk and hasattr(obj, 'snapshot'):
obj.snapshot()
obj.property = "New Value"
obj.full_clean()
obj.save()
```
## Variable Reference
### Default Options
@@ -254,7 +267,7 @@ An IPv4 or IPv6 network with a mask. Returns a `netaddr.IPNetwork` object. Two a
### Via the Web UI
Custom scripts can be run via the web UI by navigating to the script, completing any required form data, and clicking the "run script" button.
Custom scripts can be run via the web UI by navigating to the script, completing any required form data, and clicking the "run script" button. It is possible to schedule a script to be executed at specified time in the future. A scheduled script can be canceled by deleting the associated job result object.
### Via the API
@@ -269,6 +282,8 @@ http://netbox/api/extras/scripts/example.MyReport/ \
--data '{"data": {"foo": "somevalue", "bar": 123}, "commit": true}'
```
Optionally `schedule_at` can be passed in the form data with a datetime string to schedule a script at the specified date and time.
### Via the CLI
Scripts can be run on the CLI by invoking the management command:

View File

@@ -45,7 +45,7 @@ class DeviceConnectionsReport(Report):
# Check that every console port for every active device has a connection defined.
active = DeviceStatusChoices.STATUS_ACTIVE
for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=active):
if console_port.connected_endpoint is None:
if not console_port.connected_endpoints:
self.log_failure(
console_port.device,
"No console connection defined for {}".format(console_port.name)
@@ -64,7 +64,7 @@ class DeviceConnectionsReport(Report):
for device in Device.objects.filter(status=DeviceStatusChoices.STATUS_ACTIVE):
connected_ports = 0
for power_port in PowerPort.objects.filter(device=device):
if power_port.connected_endpoint is not None:
if power_port.connected_endpoints:
connected_ports += 1
if not power_port.path.is_active:
self.log_warning(
@@ -136,7 +136,7 @@ Once you have created a report, it will appear in the reports list. Initially, r
### Via the Web UI
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Once a report has been run, its associated results will be included in the report view.
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Once a report has been run, its associated results will be included in the report view. It is possible to schedule a report to be executed at specified time in the future. A scheduled report can be canceled by deleting the associated job result object.
### Via the API
@@ -152,6 +152,8 @@ Our example report above would be called as:
POST /api/extras/reports/devices.DeviceConnectionsReport/run/
```
Optionally `schedule_at` can be passed in the form data with a datetime string to schedule a script at the specified date and time.
### Via the CLI
Reports can be run on the CLI by invoking the management command:

View File

@@ -60,7 +60,7 @@ Create the HTML template for the object view. (The other views each typically em
## 10. Add the model to the navigation menu
Add the relevant navigation menu items in `netbox/netbox/navigation_menu.py`.
Add the relevant navigation menu items in `netbox/netbox/navigation/menu.py`.
## 11. REST API components

View File

@@ -56,11 +56,15 @@ If the new field should be filterable, add it to the `FilterSet` for the model.
If the new field will be included in the object list view, add a column to the model's table. For simple fields, adding the field name to `Meta.fields` will be sufficient. More complex fields may require declaring a custom column. Also add the field name to `default_columns` if the column should be present in the table by default.
## 8. Update the UI templates
## 8. Update the SearchIndex
Where applicable, add the new field to the model's SearchIndex for inclusion in global search.
## 9. Update the UI templates
Edit the object's view template to display the new field. There may also be a custom add/edit form template that needs to be updated.
## 9. Create/extend test cases
## 10. Create/extend test cases
Create or extend the relevant test cases to verify that the new field and any accompanying validation logic perform as expected. This is especially important for relational fields. NetBox incorporates various test suites, including:
@@ -72,6 +76,6 @@ Create or extend the relevant test cases to verify that the new field and any ac
Be diligent to ensure all of the relevant test suites are adapted or extended as necessary to test any new functionality.
## 10. Update the model's documentation
## 11. Update the model's documentation
Each model has a dedicated page in the documentation, at `models/<app>/<model>.md`. Update this file to include any relevant information about the new field.

View File

@@ -40,6 +40,7 @@ The Django [content types](https://docs.djangoproject.com/en/stable/ref/contrib/
* [dcim.RackReservation](../models/dcim/rackreservation.md)
* [dcim.Site](../models/dcim/site.md)
* [dcim.VirtualChassis](../models/dcim/virtualchassis.md)
* [dcim.VirtualDeviceContext](../models/dcim/virtualdevicecontext.md)
* [ipam.Aggregate](../models/ipam/aggregate.md)
* [ipam.ASN](../models/ipam/asn.md)
* [ipam.FHRPGroup](../models/ipam/fhrpgroup.md)

View File

@@ -0,0 +1,37 @@
# Search
NetBox v3.4 introduced a new global search mechanism, which employs the `extras.CachedValue` model to store discrete field values from many models in a single table.
## SearchIndex
To enable search support for a model, declare and register a subclass of `netbox.search.SearchIndex` for it. Typically, this will be done within an app's `search.py` module.
```python
from netbox.search import SearchIndex, register_search
@register_search
class MyModelIndex(SearchIndex):
model = MyModel
fields = (
('name', 100),
('description', 500),
('comments', 5000),
)
```
A SearchIndex subclass defines both its model and a list of two-tuples specifying which model fields to be indexed and the weight (precedence) associated with each. Guidance on weight assignment for fields is provided below.
### Field Weight Guidance
| Weight | Field Role | Examples |
|--------|--------------------------------------------------|----------------------------------------------------|
| 50 | Unique serialized attribute | Device.asset_tag |
| 60 | Unique serialized attribute (per related object) | Device.serial |
| 100 | Primary human identifier | Device.name, Circuit.cid, Cable.label |
| 110 | Slug | Site.slug |
| 200 | Secondary identifier | Provider.account, DeviceType.part_number |
| 300 | Highly unique descriptive attribute | CircuitTermination.xconnect_id, IPAddress.dns_name |
| 500 | Description | Site.description |
| 1000 | Custom field default | - |
| 2000 | Other discrete attribute | CircuitTermination.port_speed |
| 5000 | Comment field | Site.comments |

View File

@@ -71,13 +71,13 @@ To learn more about this feature, check out the [export template documentation](
NetBox administrators can install custom Python scripts, known as _reports_, which run within NetBox and can be executed and analyzed within the NetBox UI. Reports are a great way to evaluate NetBox objects against a set of arbitrary rules. For example, you could write a report to check that every router has a loopback interface with an IP address assigned, or that every site has a minimum set of VLANs defined.
When a report runs, its logs messages pertaining to the operations being performed, and will ultimately result in either a pass or fail. Reports can be executed via the UI, REST API, or CLI (as a management command).
When a report runs, its logs messages pertaining to the operations being performed, and will ultimately result in either a pass or fail. Reports can be executed via the UI, REST API, or CLI (as a management command). They can be run immediately or scheduled to run at a future time.
To learn more about this feature, check out the [documentation for reports](../customization/reports.md).
## Custom Scripts
Custom scripts are similar to reports, but more powerful. A custom script can prompt the user for input via a form (or API data), and is built to do much more than just reporting. Custom scripts are generally used to automate tasks, such as the population of new objects in NetBox, or exchanging data with external systems.
Custom scripts are similar to reports, but more powerful. A custom script can prompt the user for input via a form (or API data), and is built to do much more than just reporting. Custom scripts are generally used to automate tasks, such as the population of new objects in NetBox, or exchanging data with external systems. As with reports, they can be run via the UI, REST API, or CLI, and be scheduled to execute at a future time.
The complete Python environment is available to a custom script, including all of NetBox's internal mechanisms: There are no artificial restrictions on what a script can do. As such, custom scripting is considered an advanced feature and requires sufficient familiarity with Python and NetBox's data model.

View File

@@ -65,6 +65,10 @@ Each device can have an operational status, functional role, and software platfo
Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master.
### Virtual Device Contexts
A virtual device context (VDC) is a logical partition within a device. Each VDC operates autonomously but shares a common pool of resources. Each interface can be assigned to one or more VDCs on its device.
## Module Types & Modules
Much like device types and devices, module types can instantiate discrete modules, which are hardware components installed within devices. Modules often have their own child components, which become available to the parent device. For example, when modeling a chassis-based switch with multiple line cards in NetBox, the chassis would be created (from a device type) as a device, and each of its line cards would be instantiated from a module type as a module installed in one of the device's module bays.

View File

@@ -1,5 +1,5 @@
# Journaling
All primary objects in NetBox support journaling. A journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after a configurable period of time, journal entries persist for the life of their associated object.
All primary and organizational models in NetBox support journaling. A journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after a configurable period of time, journal entries persist for the life of their associated object.
Each journal entry has a selectable kind (info, success, warning, or danger) and a user-populated `comments` field. Each entry automatically records the date, time, and associated user upon being created.

27
docs/features/search.md Normal file
View File

@@ -0,0 +1,27 @@
# Search
## Global Search
NetBox includes a powerful global search engine, providing a single convenient interface to search across its complex data model. Relevant fields on each model are indexed according to their precedence, so that the most relevant results are returned first. When objects are created or modified, the search index is updated immediately, ensuring real-time accuracy.
When entering a search query, the user can choose a specific lookup type: exact match, partial match, etc. When a partial match is found, the matching portion of the applicable field value is included with each result so that the user can easily determine its relevance.
Custom fields defined by NetBox administrators are also included in search results if configured with a search weight. Additionally, NetBox plugins can register their own custom models for inclusion alongside core models.
## Saved Filters
Each type of object in NetBox is accompanied by an extensive set of filters, each tied to a specific attribute, which enable the creation of complex queries. Often you'll find that certain queries are used routinely to apply some set of prescribed conditions to a query. Once a set of filters has been applied, NetBox offers the option to save it for future use.
For example, suppose you often need to locate all planned devices of a certain type within a region. The applicable filters can be applied and then saved as custom named filter for reuse, such that
```
?status=planned&device_type_id=78&region_id=12
```
becomes
```
?filter=my-custom-filter
```
These saved filters can be used both within the UI and for API queries.

View File

@@ -20,12 +20,14 @@ To create a new object in NetBox, find the object type in the navigation menu an
## Bulk Import (CSV/YAML)
NetBox supports the bulk import of new objects using CSV-formatted data. This method can be ideal for importing spreadsheet data, which is very easy to convert to CSV data. CSV data can be imported either as raw text using the form field, or by uploading a properly formatted CSV file.
NetBox supports the bulk import of new objects, and updating of existing objects using CSV-formatted data. This method can be ideal for importing spreadsheet data, which is very easy to convert to CSV data. CSV data can be imported either as raw text using the form field, or by uploading a properly formatted CSV file.
When viewing the CSV import form for an object type, you'll notice that the headers for the required columns have been pre-populated. Each form has a table beneath it titled "CSV Field Options," which lists _all_ supported columns for your reference. (Generally, these map to the fields you see in the corresponding creation form for individual objects.)
<!-- TODO: Screenshot -->
If an "id" field is added the data will be used to update existing records instead of importing new objects.
Note that some models (namely device types and module types) do not support CSV import. Instead, they accept YAML-formatted data to facilitate the import of both the parent object as well as child components.
## Scripting

View File

@@ -2,8 +2,8 @@
This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md).
!!! warning "PostgreSQL 10 or later required"
NetBox requires PostgreSQL 10 or later. Please note that MySQL and other relational databases are **not** supported.
!!! warning "PostgreSQL 11 or later required"
NetBox requires PostgreSQL 11 or later. Please note that MySQL and other relational databases are **not** supported.
## Installation
@@ -35,7 +35,7 @@ sudo systemctl start postgresql
sudo systemctl enable postgresql
```
Before continuing, verify that you have installed PostgreSQL 10 or later:
Before continuing, verify that you have installed PostgreSQL 11 or later:
```no-highlight
psql -V

View File

@@ -7,7 +7,7 @@ This section of the documentation discusses installing and configuring the NetBo
Begin by installing all system packages required by NetBox and its dependencies.
!!! warning "Python 3.8 or later required"
NetBox requires Python 3.8, 3.9, or 3.10.
NetBox requires Python 3.8, 3.9, 3.10 or 3.11.
=== "Ubuntu"
@@ -36,7 +36,7 @@ This documentation provides two options for installing NetBox: from a downloadab
Download the [latest stable release](https://github.com/netbox-community/netbox/releases) from GitHub as a tarball or ZIP archive and extract it to your desired path. In this example, we'll use `/opt/netbox` as the NetBox root.
```no-highlight
sudo wget https://github.com/netbox-community/netbox/archive/vX.Y.Z.tar.gz
sudo wget https://github.com/netbox-community/netbox/archive/refs/tags/vX.Y.Z.tar.gz
sudo tar -xzf vX.Y.Z.tar.gz -C /opt
sudo ln -s /opt/netbox-X.Y.Z/ /opt/netbox
```
@@ -225,6 +225,9 @@ Once NetBox has been configured, we're ready to proceed with the actual installa
* Builds the documentation locally (for offline use)
* Aggregate static resource files on disk
!!! warning
If you still have a Python virtual environment active from a previous installation step, disable it now by running the `deactivate` command. This will avoid errors on systems where `sudo` has been configured to preserve the user's current environment.
```no-highlight
sudo /opt/netbox/upgrade.sh
```

View File

@@ -46,7 +46,7 @@ Next, create a file in the same directory as `configuration.py` (typically `/opt
### General Server Configuration
!!! info
When using Windows Server 2012 you may need to specify a port on `AUTH_LDAP_SERVER_URI`. Use `3269` for secure, or `3268` for non-secure.
When using Active Directory you may need to specify a port on `AUTH_LDAP_SERVER_URI` to authenticate users from all domains in the forest. Use `3269` for secure, or `3268` for non-secure access to the GC (Global Catalog).
```python
import ldap
@@ -67,6 +67,16 @@ AUTH_LDAP_BIND_PASSWORD = "demo"
# Note that this is a NetBox-specific setting which sets:
# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
LDAP_IGNORE_CERT_ERRORS = True
# Include this setting if you want to validate the LDAP server certificates against a CA certificate directory on your server
# Note that this is a NetBox-specific setting which sets:
# ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, LDAP_CA_CERT_DIR)
LDAP_CA_CERT_DIR = '/etc/ssl/certs'
# Include this setting if you want to validate the LDAP server certificates against your own CA.
# Note that this is a NetBox-specific setting which sets:
# ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CA_CERT_FILE)
LDAP_CA_CERT_FILE = '/path/to/example-CA.crt'
```
STARTTLS can be configured by setting `AUTH_LDAP_START_TLS = True` and using the `ldap://` URI scheme.

View File

@@ -18,7 +18,7 @@ The following sections detail how to set up a new instance of NetBox:
| Dependency | Minimum Version |
|------------|-----------------|
| Python | 3.8 |
| PostgreSQL | 10 |
| PostgreSQL | 11 |
| Redis | 4.0 |
Below is a simplified overview of the NetBox application stack for reference:

View File

@@ -20,7 +20,7 @@ NetBox v3.0 and later require the following:
| Dependency | Minimum Version |
|------------|-----------------|
| Python | 3.8 |
| PostgreSQL | 10 |
| PostgreSQL | 11 |
| Redis | 4.0 |
## 3. Install the Latest Release
@@ -28,16 +28,15 @@ NetBox v3.0 and later require the following:
As with the initial installation, you can upgrade NetBox by either downloading the latest release package or by cloning the `master` branch of the git repository.
!!! warning
Use the same method as you used to install Netbox originally
Use the same method as you used to install NetBox originally
If you are not sure how Netbox was installed originally, check with this
command:
If you are not sure how NetBox was installed originally, check with this command:
```
ls -ld /opt/netbox /opt/netbox/.git
```
If Netbox was installed from a release package, then `/opt/netbox` will be a
If NetBox was installed from a release package, then `/opt/netbox` will be a
symlink pointing to the current version, and `/opt/netbox/.git` will not
exist. If it was installed from git, then `/opt/netbox` and
`/opt/netbox/.git` will both exist as normal directories.

View File

@@ -47,7 +47,7 @@ NetBox provides both a singular and plural query field for each object type:
For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of filters) to fetch all devices.
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/).
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/) as well as the [GraphQL queries documentation](https://graphql.org/learn/queries/).
## Filtering
@@ -56,6 +56,47 @@ The GraphQL API employs the same filtering logic as the UI and REST API. Filters
```
{"query": "query {site_list(region:\"north-carolina\", status:\"active\") {name}}"}
```
In addition, filtering can be done on list of related objects as shown in the following query:
```
{
device_list {
id
name
interfaces(enabled: true) {
name
}
}
}
```
## Multiple Return Types
Certain queries can return multiple types of objects, for example cable terminations can return circuit terminations, console ports and many others. These can be queried using [inline fragments](https://graphql.org/learn/schema/#union-types) as shown below:
```
{
cable_list {
id
a_terminations {
... on CircuitTerminationType {
id
class_type
}
... on ConsolePortType {
id
class_type
}
... on ConsoleServerPortType {
id
class_type
}
}
}
}
```
The field "class_type" is an easy way to distinguish what type of object it is when viewing the returned data, or when filtering. It contains the class name, for example "CircuitTermination" or "ConsoleServerPort".
## Authentication

View File

@@ -579,6 +579,9 @@ By default, a token can be used to perform all actions via the API that a user w
Additionally, a token can be set to expire at a specific time. This can be useful if an external client needs to be granted temporary access to NetBox.
!!! warning "Restricting Token Retrieval"
The ability to retrieve the key value of a previously-created API token can be restricted by disabling the [`ALLOW_TOKEN_RETRIEVAL`](../configuration/security.md#allow_token_retrieval) configuration parameter.
#### Client IP Restriction
!!! note

View File

@@ -74,6 +74,6 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and
| HTTP service | nginx or Apache |
| WSGI service | gunicorn or uWSGI |
| Application | Django/Python |
| Database | PostgreSQL 10+ |
| Database | PostgreSQL 11+ |
| Task queuing | Redis/django-rq |
| Live device access | NAPALM (optional) |

View File

@@ -41,6 +41,10 @@ Indicates whether this is a parent type (capable of housing child devices), a ch
The default direction in which airflow circulates within the device chassis. This may be configured differently for instantiated devices (e.g. because of different fan modules).
### Weight
The numeric weight of the device, including a unit designation (e.g. 10 kilograms or 20 pounds).
### Front & Rear Images
Users can upload illustrations of the device's front and rear panels. If present, these will be used to render the device in [rack](./rack.md) elevation diagrams.

View File

@@ -18,6 +18,13 @@ The [module bay](./modulebay.md) into which the module is installed.
The [module type](./moduletype.md) which represents the physical make & model of hardware. By default, module components will be instantiated automatically from the module type when creating a new module.
### Status
The module's operational status.
!!! tip
Additional statuses may be defined by setting `Module.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
### Serial Number
The unique physical serial number assigned to this module by its manufacturer.

View File

@@ -35,3 +35,7 @@ The model number assigned to this module type by its manufacturer. Must be uniqu
### Part Number
An alternative part number to uniquely identify the module type.
### Weight
The numeric weight of the module, including a unit designation (e.g. 3 kilograms or 1 pound).

View File

@@ -65,6 +65,18 @@ The height of the rack, measured in units.
The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches.
### Mounting Depth
The maximum depth of a mounted device that the rack can accommodate, in millimeters. For four-post frames or cabinets, this is the horizontal distance between the front and rear vertical rails. (Note that this measurement does _not_ include space between the rails and the cabinet doors.)
### Weight
The numeric weight of the rack, including a unit designation (e.g. 10 kilograms or 20 pounds).
### Maximum Weight
The maximum total weight capacity for all installed devices, inclusive of the rack itself.
### Descending Units
If selected, the rack's elevation will display unit 1 at the top of the rack. (Most racks use asceneding numbering, with unit 1 assigned to the bottommost position.)
If selected, the rack's elevation will display unit 1 at the top of the rack. (Most racks use ascending numbering, with unit 1 assigned to the bottommost position.)

View File

@@ -33,7 +33,7 @@ Each site can have multiple [AS numbers](../ipam/asn.md) assigned to it.
### Time Zone
The site's local time zone. (Time zones are provided by the [pytz](https://pypi.org/project/pytz/) package.)
The site's local time zone. (Time zones are provided by the [zoneinfo](https://docs.python.org/3/library/zoneinfo.html) library.)
### Physical Address

View File

@@ -0,0 +1,33 @@
# Virtual Device Context
A virtual device context (VDC) represents a logical partition within a physical device, to which interfaces from the parent device can be allocated. Each VDC effectively provides an isolated control plane, but relies on shared resources of the parent device. A VDC is somewhat similar to a virtual machine in that it effects isolation between various components, but stops short of delivering a fully virtualized environment.
Each VDC must be assigned to a device upon creation, after which interfaces belonging to that device can be assigned to one or more of its VDCs. A VDC can have any number of interfaces assigned to it, and an interface can belong to any number of VDCs.
!!! info "A VDC by Any Other Name"
Network vendors use differing names for this concept. Cisco uses the term VDC, whereas Juniper refers to it as a _Virtual Routing Instance_, and Fortinet uses _Virtual Domain_, for instance. While there may be some nuance among the vendors' unique implementations, the general concept remains the same for each.
## Fields
### Device
The device to which this VDC belongs.
### Name
The VDC's configured name. Must be unique to the assigned device.
### Status
The operational status of the VDC.
### Identifier
A vendor-prescribed unique identifier for the VDC (optional). Must be unique to the assigned device if defined.
### Primary IPv4 & IPv6 Addresses
Each VDC may designate one primary IPv4 address and/or one primary IPv6 address for management purposes.
!!! tip
NetBox will prefer IPv6 addresses over IPv4 addresses by default. This can be changed by setting the `PREFER_IPV4` configuration parameter.

View File

@@ -0,0 +1,13 @@
# Branches
A branch is a collection of related [staged changes](./stagedchange.md) that have been prepared for merging into the active database. A branch can be merged by executing its `commit()` method. Deleting a branch will delete all its related changes.
## Fields
### Name
The branch's name.
### User
The user to which the branch belongs (optional).

View File

@@ -0,0 +1,47 @@
# Saved Filters
When filtering lists of objects in NetBox, users can save applied filters for future use. This is handy for complex filter strategies involving multiple discrete filters. For example, you might want to find all planned devices within a region that have a specific platform. Once you've applied the desired filters to the object list, simply create a saved filter with name and optional description. This filter can then be applied directly for future queries via both the UI and REST API.
## Fields
### Name
The filter's human-friendly name.
### Slug
The unique identifier by which this filter will be referenced during application (e.g. `?filter=my-slug`).
### User
The user to which this filter belongs. The current user will be assigned automatically when creating saved filters via the UI, and cannot be changed.
### Weight
A numeric weight used to override alphabetic ordering of filters by name. Saved filters with a lower weight will be listed before those with a higher weight.
### Enabled
Determines whether this filter can be used. Disabled filters will not appear as options in the UI, however they will be included in API results.
### Shared
Determines whether this filter is intended for use by all users or only its owner. Note that disabling this field does **not** hide the filter from other users; it is merely excluded from the list of available filters in UI object list views.
### Parameters
The query parameters to apply when the filter is active. These must be specified as JSON data. For example, the URL query string
```
?status=active&region_id=51&tag=alpha&tag=bravo
```
is represented in JSON as
```json
{
"tag": ["alpha", "bravo"],
"status": "active",
"region_id": 51
}
```

View File

@@ -0,0 +1,26 @@
# Staged Changes
A staged change represents the creation of a new object or the modification or deletion of an existing object to be performed at some future point. Each change must be assigned to a [branch](./branch.md).
Changes can be applied individually via the `apply()` method, however it is recommended to apply changes in bulk using the parent branch's `commit()` method.
## Fields
!!! warning
Staged changes are not typically created or manipulated directly, but rather effected through the use of the [`checkout()`](../../plugins/development/staged-changes.md) context manager.
### Branch
The [branch](./branch.md) to which this change belongs.
### Action
The type of action this change represents: `create`, `update`, or `delete`.
### Object
A generic foreign key referencing the existing object to which this change applies.
### Data
JSON representation of the changes being made to the object (not applicable for deletions).

View File

@@ -19,6 +19,10 @@ The wire protocol employed by cooperating servers to maintain the virtual [IP ad
The group's numeric identifier.
### Name
An optional name for the FHRP group.
### Authentication Type
The type of authentication employed by group nodes, if any.

View File

@@ -23,7 +23,7 @@ The IPv4 or IPv6 address and mask, in CIDR notation (e.g. `192.0.2.0/24`).
The operational status of the IP address.
!!! tip
Additional statuses may be defined by setting `IPAddress.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
Additional statuses may be defined by setting `ipam.IPAddress.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
### Role

View File

@@ -12,6 +12,13 @@ The service set identifier (SSID) for the wireless network.
The [wireless LAN group](./wirelesslangroup.md) to which this wireless LAN is assigned (if any).
### Status
The operational status of the wireless network.
!!! tip
Additional statuses may be defined by setting `WirelessLAN.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
### VLAN
Each wireless LAN can optionally be mapped to a [VLAN](../ipam/vlan.md), to model a bridge between wired and wireless segments.

View File

@@ -4,11 +4,11 @@
NetBox provides several base form classes for use by plugins.
| Form Class | Purpose |
|---------------------------|--------------------------------------|
| `NetBoxModelForm` | Create/edit individual objects |
| `NetBoxModelCSVForm` | Bulk import objects from CSV data |
| `NetBoxModelBulkEditForm` | Edit multiple objects simultaneously |
| Form Class | Purpose |
|----------------------------|--------------------------------------|
| `NetBoxModelForm` | Create/edit individual objects |
| `NetBoxModelImportForm` | Bulk import objects from CSV data |
| `NetBoxModelBulkEditForm` | Edit multiple objects simultaneously |
| `NetBoxModelFilterSetForm` | Filter objects within a list view |
### `NetBoxModelForm`
@@ -45,19 +45,20 @@ class MyModelForm(NetBoxModelForm):
!!! tip "Comment fields"
If your form has a `comments` field, there's no need to list it; this will always appear last on the page.
### `NetBoxModelCSVForm`
### `NetBoxModelImportForm`
This form facilitates the bulk import of new objects from CSV data. As with model forms, you'll need to declare a `Meta` subclass specifying the associated `model` and `fields`. NetBox also provides several form fields suitable for import various types of CSV data, listed below.
This form facilitates the bulk import of new objects from CSV, JSON, or YAML data. As with model forms, you'll need to declare a `Meta` subclass specifying the associated `model` and `fields`. NetBox also provides several form fields suitable for import various types of CSV data, listed below.
**Example**
```python
from dcim.models import Site
from netbox.forms import NetBoxModelCSVForm
from netbox.forms import NetBoxModelImportForm
from utilities.forms import CSVModelChoiceField
from .models import MyModel
class MyModelCSVForm(NetBoxModelCSVForm):
class MyModelImportForm(NetBoxModelImportForm):
site = CSVModelChoiceField(
queryset=Site.objects.all(),
to_field_name='name',
@@ -69,6 +70,9 @@ class MyModelCSVForm(NetBoxModelCSVForm):
fields = ('name', 'status', 'site', 'comments')
```
!!! note "Previously NetBoxModelCSVForm"
This form class was previously named `NetBoxModelCSVForm`. It was renamed in NetBox v3.4 to convey support for JSON and YAML formats in addition to CSV. The `NetBoxModelCSVForm` class has been retained for backward compatibility and functions exactly the same as `NetBoxModelImportForm`. However, plugin authors should be aware that this backward compatability will be removed in NetBox v3.5.
### `NetBoxModelBulkEditForm`
This form facilitates editing multiple objects in bulk. Unlike a model form, this form does not have a child `Meta` class, and must explicitly define each field. All fields in a bulk edit form are generally declared with `required=False`.
@@ -84,11 +88,12 @@ This form facilitates editing multiple objects in bulk. Unlike a model form, thi
```python
from django import forms
from dcim.models import Site
from netbox.forms import NetBoxModelCSVForm
from netbox.forms import NetBoxModelImportForm
from utilities.forms import CommentField, DynamicModelChoiceField
from .models import MyModel, MyModelStatusChoices
class MyModelEditForm(NetBoxModelCSVForm):
class MyModelEditForm(NetBoxModelImportForm):
name = forms.CharField(
required=False
)
@@ -144,73 +149,73 @@ class MyModelFilterForm(NetBoxModelFilterSetForm):
In addition to the [form fields provided by Django](https://docs.djangoproject.com/en/stable/ref/forms/fields/), NetBox provides several field classes for use within forms to handle specific types of data. These can be imported from `utilities.forms.fields` and are documented below.
::: utilities.forms.ColorField
selection:
options:
members: false
::: utilities.forms.CommentField
selection:
options:
members: false
::: utilities.forms.JSONField
selection:
options:
members: false
::: utilities.forms.MACAddressField
selection:
options:
members: false
::: utilities.forms.SlugField
selection:
options:
members: false
## Choice Fields
::: utilities.forms.ChoiceField
selection:
options:
members: false
::: utilities.forms.MultipleChoiceField
selection:
options:
members: false
## Dynamic Object Fields
::: utilities.forms.DynamicModelChoiceField
selection:
options:
members: false
::: utilities.forms.DynamicModelMultipleChoiceField
selection:
options:
members: false
## Content Type Fields
::: utilities.forms.ContentTypeChoiceField
selection:
options:
members: false
::: utilities.forms.ContentTypeMultipleChoiceField
selection:
options:
members: false
## CSV Import Fields
::: utilities.forms.CSVChoiceField
selection:
options:
members: false
::: utilities.forms.CSVMultipleChoiceField
selection:
options:
members: false
::: utilities.forms.CSVModelChoiceField
selection:
options:
members: false
::: utilities.forms.CSVContentTypeField
selection:
options:
members: false
::: utilities.forms.CSVMultipleContentTypeField
selection:
options:
members: false

View File

@@ -32,11 +32,11 @@ schema = MyQuery
NetBox provides two object type classes for use by plugins.
::: netbox.graphql.types.BaseObjectType
selection:
options:
members: false
::: netbox.graphql.types.NetBoxObjectType
selection:
options:
members: false
## GraphQL Fields
@@ -44,9 +44,9 @@ NetBox provides two object type classes for use by plugins.
NetBox provides two field classes for use by plugins.
::: netbox.graphql.fields.ObjectField
selection:
options:
members: false
::: netbox.graphql.fields.ObjectListField
selection:
options:
members: false

View File

@@ -14,6 +14,7 @@ Plugins can do a lot, including:
* Provide their own "pages" (views) in the web user interface
* Inject template content and navigation links
* Extend NetBox's REST and GraphQL APIs
* Load additional Django apps
* Add custom request/response middleware
However, keep in mind that each piece of functionality is entirely optional. For example, if your plugin merely adds a piece of middleware or an API endpoint for existing data, there's no need to define any new models.
@@ -82,6 +83,7 @@ class FooBarConfig(PluginConfig):
default_settings = {
'baz': True
}
django_apps = ["foo", "bar", "baz"]
config = FooBarConfig
```
@@ -101,10 +103,12 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
| `base_url` | Base path to use for plugin URLs (optional). If not specified, the project's `name` will be used. |
| `required_settings` | A list of any configuration parameters that **must** be defined by the user |
| `default_settings` | A dictionary of configuration parameters and their default values |
| `django_apps` | A list of additional Django apps to load alongside the plugin |
| `min_version` | Minimum version of NetBox with which the plugin is compatible |
| `max_version` | Maximum version of NetBox with which the plugin is compatible |
| `middleware` | A list of middleware classes to append after NetBox's build-in middleware |
| `queues` | A list of custom background task queues to create |
| `search_extensions` | The dotted path to the list of search index classes (default: `search.indexes`) |
| `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) |
| `menu_items` | The dotted path to the list of menu items provided by the plugin (default: `navigation.menu_items`) |
| `graphql_schema` | The dotted path to the plugin's GraphQL schema class, if any (default: `graphql.schema`) |
@@ -112,6 +116,22 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
!!! tip "Accessing Config Parameters"
Plugin configuration parameters can be accessed using the `get_plugin_config()` function. For example:
```python
from extras.plugins import get_plugin_config
get_plugin_config('my_plugin', 'verbose_name')
```
#### Important Notes About `django_apps`
Loading additional apps may cause more harm than good and could make identifying problems within NetBox itself more difficult. The `django_apps` attribute is intended only for advanced use cases that require a deeper Django integration.
Apps from this list are inserted *before* the plugin's `PluginConfig` in the order defined. Adding the plugin's `PluginConfig` module to this list changes this behavior and allows for apps to be loaded *after* the plugin.
Any additional apps must be installed within the same Python environment as NetBox or `ImproperlyConfigured` exceptions will be raised when loading the plugin.
## Create setup.py
`setup.py` is the [setup script](https://docs.python.org/3.8/distutils/setupscript.html) used to package and install our plugin once it's finished. The primary function of this script is to call the setuptools library's `setup()` function to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. An example `setup.py` is below:

View File

@@ -49,23 +49,11 @@ class MyModel(NetBoxModel):
...
```
### The `clone()` Method
### NetBoxModel Properties
!!! info
This method was introduced in NetBox v3.3.
#### `docs_url`
The `NetBoxModel` class includes a `clone()` method to be used for gathering attributes which can be used to create a "cloned" instance. This is used primarily for form initialization, e.g. when using the "clone" button in the NetBox UI. By default, this method will replicate any fields listed in the model's `clone_fields` list, if defined.
Plugin models can leverage this method by defining `clone_fields` as a list of field names to be replicated, or override this method to replace or extend its content:
```python
class MyModel(NetBoxModel):
def clone(self):
attrs = super().clone()
attrs['extra-value'] = 123
return attrs
```
This attribute specifies the URL at which the documentation for this model can be reached. By default, it will return `/static/docs/models/<app_label>/<model_name>/`. Plugin models can override this to return a custom URL. For example, you might direct the user to your plugin's documentation hosted on [ReadTheDocs](https://readthedocs.org/).
### Enabling Features Individually
@@ -116,6 +104,8 @@ For more information about database migrations, see the [Django documentation](h
::: netbox.models.features.ChangeLoggingMixin
::: netbox.models.features.CloningMixin
::: netbox.models.features.CustomLinksMixin
::: netbox.models.features.CustomFieldsMixin

View File

@@ -1,25 +1,67 @@
# Navigation
## Menus
!!! note
This feature was introduced in NetBox v3.4.
A plugin can register its own submenu as part of NetBox's navigation menu. This is done by defining a variable named `menu` in `navigation.py`, pointing to an instance of the `PluginMenu` class. Each menu must define a label and grouped menu items (discussed below), and may optionally specify an icon. An example is shown below.
```python title="navigation.py"
from extras.plugins import PluginMenu
menu = PluginMenu(
label='My Plugin',
groups=(
('Foo', (item1, item2, item3)),
('Bar', (item4, item5)),
),
icon_class='mdi mdi-router'
)
```
Note that each group is a two-tuple containing a label and an iterable of menu items. The group's label serves as the section header within the submenu. A group label is required even if you have only one group of items.
!!! tip
The path to the menu class can be modified by setting `menu` in the PluginConfig instance.
A `PluginMenu` has the following attributes:
| Attribute | Required | Description |
|--------------|----------|---------------------------------------------------|
| `label` | Yes | The text displayed as the menu heading |
| `groups` | Yes | An iterable of named groups containing menu items |
| `icon_class` | - | The CSS name of the icon to use for the heading |
!!! tip
Supported icons can be found at [Material Design Icons](https://materialdesignicons.com/)
### The Default Menu
If your plugin has only a small number of menu items, it may be desirable to use NetBox's shared "Plugins" menu rather than creating your own. To do this, simply declare `menu_items` as a list of `PluginMenuItems` in `navigation.py`. The listed items will appear under a heading bearing the name of your plugin in the "Plugins" submenu.
```python title="navigation.py"
menu_items = (item1, item2, item3)
```
!!! tip
The path to the menu items list can be modified by setting `menu_items` in the PluginConfig instance.
## Menu Items
To make its views easily accessible to users, a plugin can inject items in NetBox's navigation menu under the "Plugins" header. Menu items are added by defining a list of PluginMenuItem instances. By default, this should be a variable named `menu_items` in the file `navigation.py`. An example is shown below.
Each menu item represents a link and (optionally) a set of buttons comprising one entry in NetBox's navigation menu. Menu items are defined as PluginMenuItem instances. An example is shown below.
!!! tip
The path to declared menu items can be modified by setting `menu_items` in the PluginConfig instance.
```python
```python filename="navigation.py"
from extras.plugins import PluginMenuButton, PluginMenuItem
from utilities.choices import ButtonColorChoices
menu_items = (
PluginMenuItem(
link='plugins:netbox_animal_sounds:random_animal',
link_text='Random sound',
buttons=(
PluginMenuButton('home', 'Button A', 'fa fa-info', ButtonColorChoices.BLUE),
PluginMenuButton('home', 'Button B', 'fa fa-warning', ButtonColorChoices.GREEN),
)
),
item1 = PluginMenuItem(
link='plugins:myplugin:myview',
link_text='Some text',
buttons=(
PluginMenuButton('home', 'Button A', 'fa fa-info', ButtonColorChoices.BLUE),
PluginMenuButton('home', 'Button B', 'fa fa-warning', ButtonColorChoices.GREEN),
)
)
```
@@ -34,17 +76,19 @@ A `PluginMenuItem` has the following attributes:
## Menu Buttons
Each menu item can include a set of buttons. These can be handy for providing shortcuts related to the menu item. For instance, most items in NetBox's navigation menu include buttons to create and import new objects.
A `PluginMenuButton` has the following attributes:
| Attribute | Required | Description |
|---------------|----------|--------------------------------------------------------------------|
| `link` | Yes | Name of the URL path to which this button links |
| `title` | Yes | The tooltip text (displayed when the mouse hovers over the button) |
| `icon_class` | Yes | Button icon CSS class* |
| `icon_class` | Yes | Button icon CSS class |
| `color` | - | One of the choices provided by `ButtonColorChoices` |
| `permissions` | - | A list of permissions required to display this button |
*NetBox supports [Material Design Icons](https://materialdesignicons.com/).
Any buttons associated within a menu item will be shown only if the user has permission to view the link, regardless of what permissions are set on the buttons.
!!! note
Any buttons associated within a menu item will be shown only if the user has permission to view the link, regardless of what permissions are set on the buttons.
!!! tip
Supported icons can be found at [Material Design Icons](https://materialdesignicons.com/)

View File

@@ -0,0 +1,31 @@
# Search
!!! note
This feature was introduced in NetBox v3.4.
Plugins can define and register their own models to extend NetBox's core search functionality. Typically, a plugin will include a file named `search.py`, which holds all search indexes for its models (see the example below).
```python
# search.py
from netbox.search import SearchIndex
from .models import MyModel
class MyModelIndex(SearchIndex):
model = MyModel
fields = (
('name', 100),
('description', 500),
('comments', 5000),
)
```
To register one or more indexes with NetBox, define a list named `indexes` at the end of this file:
```python
indexes = [MyModelIndex]
```
!!! tip
The path to the list of search indexes can be modified by setting `search_indexes` in the PluginConfig instance.
::: netbox.search.SearchIndex

View File

@@ -0,0 +1,42 @@
# Staged Changes
!!! danger "Experimental Feature"
This feature is still under active development and considered experimental in nature. Its use in production is strongly discouraged at this time.
!!! note
This feature was introduced in NetBox v3.4.
NetBox provides a programmatic API to stage the creation, modification, and deletion of objects without actually committing those changes to the active database. This can be useful for performing a "dry run" of bulk operations, or preparing a set of changes for administrative approval, for example.
To begin staging changes, first create a [branch](../../models/extras/branch.md):
```python
from extras.models import Branch
branch1 = Branch.objects.create(name='branch1')
```
Then, activate the branch using the `checkout()` context manager and begin making your changes. This initiates a new database transaction.
```python
from extras.models import Branch
from netbox.staging import checkout
branch1 = Branch.objects.get(name='branch1')
with checkout(branch1):
Site.objects.create(name='New Site', slug='new-site')
# ...
```
Upon exiting the context, the database transaction is automatically rolled back and your changes recorded as [staged changes](../../models/extras/stagedchange.md). Re-entering a branch will trigger a new database transaction and automatically apply any staged changes associated with the branch.
To apply the changes within a branch, call the branch's `commit()` method:
```python
from extras.models import Branch
branch1 = Branch.objects.get(name='branch1')
branch1.commit()
```
Committing a branch is an all-or-none operation: Any exceptions will revert the entire set of changes. After successfully committing a branch, all its associated StagedChange objects are automatically deleted (however the branch itself will remain and can be reused).

View File

@@ -52,38 +52,38 @@ This will automatically apply any user-specific preferences for the table. (If u
The table column classes listed below are supported for use in plugins. These classes can be imported from `netbox.tables.columns`.
::: netbox.tables.BooleanColumn
selection:
options:
members: false
::: netbox.tables.ChoiceFieldColumn
selection:
options:
members: false
::: netbox.tables.ColorColumn
selection:
options:
members: false
::: netbox.tables.ColoredLabelColumn
selection:
options:
members: false
::: netbox.tables.ContentTypeColumn
selection:
options:
members: false
::: netbox.tables.ContentTypesColumn
selection:
options:
members: false
::: netbox.tables.MarkdownColumn
selection:
options:
members: false
::: netbox.tables.TagColumn
selection:
options:
members: false
::: netbox.tables.TemplateColumn
selection:
options:
members:
- __init__

View File

@@ -82,26 +82,28 @@ class ThingEditView(ObjectEditView):
Below are the class definitions for NetBox's object views. These views handle CRUD actions for individual objects. The view, add/edit, and delete views each inherit from `BaseObjectView`, which is not intended to be used directly.
::: netbox.views.generic.base.BaseObjectView
options:
members:
- get_queryset
- get_object
- get_extra_context
::: netbox.views.generic.ObjectView
selection:
options:
members:
- get_object
- get_template_name
::: netbox.views.generic.ObjectEditView
selection:
options:
members:
- get_object
- alter_object
::: netbox.views.generic.ObjectDeleteView
selection:
members:
- get_object
options:
members: false
::: netbox.views.generic.ObjectChildrenView
selection:
options:
members:
- get_children
- prep_table_data
@@ -111,24 +113,29 @@ Below are the class definitions for NetBox's object views. These views handle CR
Below are the class definitions for NetBox's multi-object views. These views handle simultaneous actions for sets objects. The list, import, edit, and delete views each inherit from `BaseMultiObjectView`, which is not intended to be used directly.
::: netbox.views.generic.base.BaseMultiObjectView
options:
members:
- get_queryset
- get_extra_context
::: netbox.views.generic.ObjectListView
selection:
options:
members:
- get_table
- export_table
- export_template
::: netbox.views.generic.BulkImportView
selection:
members: false
options:
members:
- save_object
::: netbox.views.generic.BulkEditView
selection:
options:
members: false
::: netbox.views.generic.BulkDeleteView
selection:
options:
members:
- get_form
@@ -137,29 +144,62 @@ Below are the class definitions for NetBox's multi-object views. These views han
These views are provided to enable or enhance certain NetBox model features, such as change logging or journaling. These typically do not need to be subclassed: They can be used directly e.g. in a URL path.
::: netbox.views.generic.ObjectChangeLogView
selection:
options:
members:
- get_form
::: netbox.views.generic.ObjectJournalView
selection:
options:
members:
- get_form
## Extending Core Views
Plugins can inject custom content into certain areas of the detail views of applicable models. This is accomplished by subclassing `PluginTemplateExtension`, designating a particular NetBox model, and defining the desired methods to render custom content. Four methods are available:
### Additional Tabs
* `left_page()` - Inject content on the left side of the page
* `right_page()` - Inject content on the right side of the page
* `full_width_page()` - Inject content across the entire bottom of the page
* `buttons()` - Add buttons to the top of the page
!!! note
This feature was introduced in NetBox v3.4.
Plugins can "attach" a custom view to a core NetBox model by registering it with `register_model_view()`. To include a tab for this view within the NetBox UI, declare a TabView instance named `tab`:
```python
from dcim.models import Site
from myplugin.models import Stuff
from netbox.views import generic
from utilities.views import ViewTab, register_model_view
@register_model_view(Site, name='myview', path='some-other-stuff')
class MyView(generic.ObjectView):
...
tab = ViewTab(
label='Other Stuff',
badge=lambda obj: Stuff.objects.filter(site=obj).count(),
permission='myplugin.view_stuff'
)
```
::: utilities.views.register_model_view
::: utilities.views.ViewTab
### Extra Template Content
Plugins can inject custom content into certain areas of core NetBox views. This is accomplished by subclassing `PluginTemplateExtension`, designating a particular NetBox model, and defining the desired method(s) to render custom content. Five methods are available:
| Method | View | Description |
|---------------------|-------------|-----------------------------------------------------|
| `left_page()` | Object view | Inject content on the left side of the page |
| `right_page()` | Object view | Inject content on the right side of the page |
| `full_width_page()` | Object view | Inject content across the entire bottom of the page |
| `buttons()` | Object view | Add buttons to the top of the page |
| `list_buttons()` | List view | Add buttons to the top of the page |
Additionally, a `render()` method is available for convenience. This method accepts the name of a template to render, and any additional context data you want to pass. Its use is optional, however.
When a PluginTemplateExtension is instantiated, context data is assigned to `self.context`. Available data include:
* `object` - The object being viewed
* `object` - The object being viewed (object views only)
* `model` - The model of the list view (list views only)
* `request` - The current request
* `settings` - Global NetBox settings
* `config` - Plugin-specific configuration parameters

View File

@@ -168,7 +168,7 @@ Some text to show that the reference links can follow later.
## Images
```
Here's the Netbox logo (hover to see the title text):
Here's the NetBox logo (hover to see the title text):
Inline-style:
![alt text](/static/netbox_logo.png "Logo Title Text 1")
@@ -179,7 +179,7 @@ Reference-style:
[logo]: /static/netbox_logo.png "Logo Title Text 2"
```
Here's the Netbox logo (hover to see the title text):
Here's the NetBox logo (hover to see the title text):
Inline-style:
![alt text](/static/netbox_logo.png "Logo Title Text 1")

View File

@@ -10,6 +10,16 @@ Minor releases are published in April, August, and December of each calendar yea
This page contains a history of all major and minor releases since NetBox v2.0. For more detail on a specific patch release, please see the release notes page for that specific minor release.
#### [Version 3.4](./version-3.4.md) (December 2022)
* New Global Search ([#10560](https://github.com/netbox-community/netbox/issues/10560))
* Virtual Device Contexts ([#7854](https://github.com/netbox-community/netbox/issues/7854))
* Saved Filters ([#9623](https://github.com/netbox-community/netbox/issues/9623))
* JSON/YAML Bulk Imports ([#4347](https://github.com/netbox-community/netbox/issues/4347))
* Update Existing Objects via Bulk Import ([#7961](https://github.com/netbox-community/netbox/issues/7961))
* Scheduled Reports & Scripts ([#8366](https://github.com/netbox-community/netbox/issues/8366))
* API for Staged Changes ([#10851](https://github.com/netbox-community/netbox/issues/10851))
#### [Version 3.3](./version-3.3.md) (August 2022)
* Multi-object Cable Terminations ([#9102](https://github.com/netbox-community/netbox/issues/9102))

View File

@@ -1,5 +1,163 @@
# NetBox v3.3
## v3.3.10 (2022-12-13)
### Enhancements
* [#9361](https://github.com/netbox-community/netbox/issues/9361) - Add replication controls for module bulk import
* [#10255](https://github.com/netbox-community/netbox/issues/10255) - Introduce `LOGOUT_REDIRECT_URL` config parameter to control redirection of user after logout
* [#10447](https://github.com/netbox-community/netbox/issues/10447) - Enable reassigning an inventory item from one device to another
* [#10516](https://github.com/netbox-community/netbox/issues/10516) - Add vertical frame & cabinet rack types
* [#10748](https://github.com/netbox-community/netbox/issues/10748) - Add provider selection field for provider networks to circuit termination edit view
* [#11089](https://github.com/netbox-community/netbox/issues/11089) - Permit whitespace in MAC addresses
* [#11119](https://github.com/netbox-community/netbox/issues/11119) - Enable filtering L2VPNs by slug
### Bug Fixes
* [#11041](https://github.com/netbox-community/netbox/issues/11041) - Correct power utilization percentage precision
* [#11077](https://github.com/netbox-community/netbox/issues/11077) - Honor configured date format when displaying date custom field values in tables
* [#11087](https://github.com/netbox-community/netbox/issues/11087) - Fix background color of bottom banner content
* [#11101](https://github.com/netbox-community/netbox/issues/11101) - Correct circuits count under site view
* [#11109](https://github.com/netbox-community/netbox/issues/11109) - Fix nullification of custom object & multi-object fields via REST API
* [#11128](https://github.com/netbox-community/netbox/issues/11128) - Disable ordering changelog table by object to avoid exception
* [#11142](https://github.com/netbox-community/netbox/issues/11142) - Correct available choices for status under IP range filter form
* [#11168](https://github.com/netbox-community/netbox/issues/11168) - Honor `RQ_DEFAULT_TIMEOUT` config parameter when using Redis Sentinel
* [#11173](https://github.com/netbox-community/netbox/issues/11173) - Enable missing tags columns for contact, L2VPN lists
---
## v3.3.9 (2022-11-30)
### Enhancements
* [#10653](https://github.com/netbox-community/netbox/issues/10653) - Ensure logging of failed login attempts
### Bug Fixes
* [#6389](https://github.com/netbox-community/netbox/issues/6389) - Call `snapshot()` on object when processing deletions
* [#9223](https://github.com/netbox-community/netbox/issues/9223) - Fix serialization of array field values in change log
* [#9878](https://github.com/netbox-community/netbox/issues/9878) - Fix spurious error message when rendering REST API docs
* [#10236](https://github.com/netbox-community/netbox/issues/10236) - Fix TypeError exception when viewing PDU configured for three-phase power
* [#10241](https://github.com/netbox-community/netbox/issues/10241) - Support referencing custom field related objects by attribute in addition to PK
* [#10579](https://github.com/netbox-community/netbox/issues/10579) - Mark cable traces terminating to a provider network as complete
* [#10721](https://github.com/netbox-community/netbox/issues/10721) - Disable ordering by custom object field columns
* [#10929](https://github.com/netbox-community/netbox/issues/10929) - Raise validation error when attempting to create a duplicate cable termination
* [#10936](https://github.com/netbox-community/netbox/issues/10936) - Permit demotion of device/VM primary IP via IP address edit form
* [#10938](https://github.com/netbox-community/netbox/issues/10938) - `render_field` template tag should respect `label` kwarg
* [#10969](https://github.com/netbox-community/netbox/issues/10969) - Update cable paths ending at associated rear port when creating new front ports
* [#10996](https://github.com/netbox-community/netbox/issues/10996) - Hide checkboxes on child object lists when no bulk operations are available
* [#10997](https://github.com/netbox-community/netbox/issues/10997) - Fix exception when editing NAT IP for VM with no cluster
* [#11014](https://github.com/netbox-community/netbox/issues/11014) - Use natural ordering when sorting rack elevations by name
* [#11028](https://github.com/netbox-community/netbox/issues/11028) - Enable bulk clearing of color attribute of pass-through ports
* [#11047](https://github.com/netbox-community/netbox/issues/11047) - Cloning a rack reservation should replicate rack & user
---
## v3.3.8 (2022-11-16)
### Enhancements
* [#10356](https://github.com/netbox-community/netbox/issues/10356) - Add backplane Ethernet interface types
* [#10902](https://github.com/netbox-community/netbox/issues/10902) - Add location selector to power feed form
* [#10904](https://github.com/netbox-community/netbox/issues/10904) - Use front/rear port colors in cable trace SVG
* [#10914](https://github.com/netbox-community/netbox/issues/10914) - Include "add module type" button on manufacturer view
* [#10915](https://github.com/netbox-community/netbox/issues/10915) - Add count of L2VPNs to tenant view
* [#10919](https://github.com/netbox-community/netbox/issues/10919) - Include device location under cable view
* [#10920](https://github.com/netbox-community/netbox/issues/10920) - Include request cookies when queuing a custom script
### Bug Fixes
* [#9439](https://github.com/netbox-community/netbox/issues/9439) - Ensure thread safety of change logging functions
* [#10709](https://github.com/netbox-community/netbox/issues/10709) - Correct UI display for `azuread-v2-tenant-oauth2` SSO backend
* [#10829](https://github.com/netbox-community/netbox/issues/10829) - Fix bulk edit/delete buttons ad top of object lists
* [#10837](https://github.com/netbox-community/netbox/issues/10837) - Correct cookie paths when `BASE_PATH` is set
* [#10874](https://github.com/netbox-community/netbox/issues/10874) - Remove erroneous link for contact assignment count
* [#10881](https://github.com/netbox-community/netbox/issues/10881) - Fix dark mode coloring for data on device status page
* [#10891](https://github.com/netbox-community/netbox/issues/10891) - Populate tag selection list for service filter form
* [#10897](https://github.com/netbox-community/netbox/issues/10897) - Fix form widget styling on FHRP group form
* [#10910](https://github.com/netbox-community/netbox/issues/10910) - Fix cable creation links on power port view
---
## v3.3.7 (2022-11-01)
### Bug Fixes
* [#10282](https://github.com/netbox-community/netbox/issues/10282) - Enforce advisory locks when allocating available IP addresses to prevent race conditions
* [#10770](https://github.com/netbox-community/netbox/issues/10282) - Fix social authentication for new users
* [#10791](https://github.com/netbox-community/netbox/issues/10791) - Permit nullifying VLAN group `scope_type` via REST API
* [#10803](https://github.com/netbox-community/netbox/issues/10803) - Fix exception when ordering contacts by number of assignments
* [#10809](https://github.com/netbox-community/netbox/issues/10809) - Permit nullifying site `time_zone` via REST API
---
## v3.3.6 (2022-10-26)
### Enhancements
* [#9584](https://github.com/netbox-community/netbox/issues/9584) - Enable filtering devices by device type slug
* [#9722](https://github.com/netbox-community/netbox/issues/9722) - Add LDAP configuration parameters to specify certificates
* [#10580](https://github.com/netbox-community/netbox/issues/10580) - Link "assigned" checkbox in IP address table to assigned interface
* [#10639](https://github.com/netbox-community/netbox/issues/10639) - Set cookie paths according to configured `BASE_PATH`
* [#10685](https://github.com/netbox-community/netbox/issues/10685) - Position A/Z termination cards above the fold under circuit view
### Bug Fixes
* [#9669](https://github.com/netbox-community/netbox/issues/9669) - Strip colons from usernames when using remote authentication
* [#10575](https://github.com/netbox-community/netbox/issues/10575) - Include OIDC dependencies for python-social-auth
* [#10584](https://github.com/netbox-community/netbox/issues/10584) - Fix service clone link
* [#10610](https://github.com/netbox-community/netbox/issues/10610) - Allow assignment of VC member to LAG on non-master peer
* [#10643](https://github.com/netbox-community/netbox/issues/10643) - Ensure consistent display of custom fields for all model forms
* [#10646](https://github.com/netbox-community/netbox/issues/10646) - Fix filtering of power feed by power panel when connecting a cable
* [#10655](https://github.com/netbox-community/netbox/issues/10655) - Correct display of assigned contacts in object tables
* [#10666](https://github.com/netbox-community/netbox/issues/10666) - Re-evaluate disabled LDAP user when processing API requests
* [#10682](https://github.com/netbox-community/netbox/issues/10682) - Correct home view links to connection lists
* [#10712](https://github.com/netbox-community/netbox/issues/10712) - Fix ModuleNotFoundError exception when generating API schema under Python 3.9+
* [#10716](https://github.com/netbox-community/netbox/issues/10716) - Add left/right page plugin content embeds for tag view
* [#10719](https://github.com/netbox-community/netbox/issues/10719) - Prevent user without sufficient permission from creating an IP address via FHRP group creation
* [#10723](https://github.com/netbox-community/netbox/issues/10723) - Distinguish between inside/outside NAT assignments for device/VM primary IPs
* [#10745](https://github.com/netbox-community/netbox/issues/10745) - Correct display of status field in clusters list
* [#10746](https://github.com/netbox-community/netbox/issues/10746) - Add missing status attribute to cluster view
---
## v3.3.5 (2022-10-05)
### Enhancements
* [#8424](https://github.com/netbox-community/netbox/issues/8424) - Include rack elevation under device view
* [#10352](https://github.com/netbox-community/netbox/issues/10352) - Omit extraneous URL query attributes during search
* [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions
### Bug Fixes
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
* [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments
* [#10423](https://github.com/netbox-community/netbox/issues/10423) - Enforce object type validation when creating journal entries
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
* [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values
* [#10460](https://github.com/netbox-community/netbox/issues/10460) - Restore missing connection details for device components
* [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI
* [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms
* [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window
* [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion
* [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device
* [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine
* [#10559](https://github.com/netbox-community/netbox/issues/10559) - Permit the pinning of a VM to a particular device within a cluster which has no site assignment
* [#10562](https://github.com/netbox-community/netbox/issues/10562) - Correct URL for contacts table tags column
---
## v3.3.4 (2022-09-16)
### Bug Fixes
* [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI
* [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface
---
## v3.3.3 (2022-09-15)
### Enhancements
@@ -320,7 +478,7 @@ Custom field UI visibility has no impact on API operation.
* The `cluster` field is now optional. A virtual machine must have a site and/or cluster assigned.
* Added the optional `device` field
* Added the `l2vpn_termination` read-only field
wireless.WirelessLAN
* wireless.WirelessLAN
* Added `tenant` field
wireless.WirelessLink
* wireless.WirelessLink
* Added `tenant` field

View File

@@ -0,0 +1,303 @@
# NetBox v3.4
## v3.4.3 (2023-01-20)
### Enhancements
* [#9996](https://github.com/netbox-community/netbox/issues/9996) - Introduce `CA_CERT_PATH` parameter to define SSL CA path for Redis servers
* [#10486](https://github.com/netbox-community/netbox/issues/10486) - Add a cable edit button for connected components in component lists
* [#11118](https://github.com/netbox-community/netbox/issues/11118) - Add L2VPN filters for VLANs and interfaces
* [#11150](https://github.com/netbox-community/netbox/issues/11150) - Add primary IPv4/v6 address filters for devices
* [#11227](https://github.com/netbox-community/netbox/issues/11227) - Add 800GE interface types
* [#11228](https://github.com/netbox-community/netbox/issues/11228) - List both devices & VMs under device role view
* [#11245](https://github.com/netbox-community/netbox/issues/11245) - Enable export templates for journal entries
* [#11371](https://github.com/netbox-community/netbox/issues/11371) - Introduce additional 100M Ethernet interface types
### Bug Fixes
* [#10201](https://github.com/netbox-community/netbox/issues/10201) - Fix AssertionError exception when removing some terminations from an existing cable
* [#11210](https://github.com/netbox-community/netbox/issues/11210) - Fix ValueError exception when attempting to bulk import cables attached to occupied terminations
* [#11340](https://github.com/netbox-community/netbox/issues/11340) - Avoid flagging cable termination changes erroneously
* [#11379](https://github.com/netbox-community/netbox/issues/11379) - Fix TypeError exception when bulk editing custom date fields
* [#11384](https://github.com/netbox-community/netbox/issues/11384) - Correct current time display on script & report forms
* [#11402](https://github.com/netbox-community/netbox/issues/11402) - Avoid LookupError exception when running scripts with commit disabled
* [#11403](https://github.com/netbox-community/netbox/issues/11403) - Fix exception when scheduling a job in the past
* [#11416](https://github.com/netbox-community/netbox/issues/11416) - Avoid AttributeError exception when deleting a cabled circuit termination
* [#11433](https://github.com/netbox-community/netbox/issues/11433) - Avoid AttributeError exception when generating API schema for views with custom schema
* [#11438](https://github.com/netbox-community/netbox/issues/11438) - Fix deletion of scheduled job using non-default queues
* [#11444](https://github.com/netbox-community/netbox/issues/11444) - Adding/removing a device from a device bay should record a pre-change snapshot on the device bay
* [#11467](https://github.com/netbox-community/netbox/issues/11467) - Correct count on interfaces tab when viewing a VC master device
* [#11483](https://github.com/netbox-community/netbox/issues/11483) - Apply configured formatting to custom date fields
* [#11488](https://github.com/netbox-community/netbox/issues/11488) - Add missing `description` fields to several REST API serializers
* [#11497](https://github.com/netbox-community/netbox/issues/11497) - Enforce `run_script` permission when executing scripts via REST API
* [#11516](https://github.com/netbox-community/netbox/issues/11516) - Prevent text highlight utility from interpreting match as regex
* [#11522](https://github.com/netbox-community/netbox/issues/11522) - Correct tag links under contact & tenant list views
* [#11544](https://github.com/netbox-community/netbox/issues/11544) - Catch ValidationError exception when filtering by invalid MAC address
---
## v3.4.2 (2023-01-03)
### Enhancements
* [#9285](https://github.com/netbox-community/netbox/issues/9285) - Enable specifying assigned component during bulk import of inventory items
* [#10700](https://github.com/netbox-community/netbox/issues/10700) - Match device name when using modules quick search
* [#11121](https://github.com/netbox-community/netbox/issues/11121) - Add VM resource totals to cluster view
* [#11156](https://github.com/netbox-community/netbox/issues/11156) - Enable selecting assigned component when editing inventory item in UI
* [#11223](https://github.com/netbox-community/netbox/issues/11223) - `reindex` management command should accept app label without model name
* [#11244](https://github.com/netbox-community/netbox/issues/11244) - Add controls for saved filters to rack elevations list
* [#11248](https://github.com/netbox-community/netbox/issues/11248) - Fix database migration when plugin with search indexer is enabled
* [#11259](https://github.com/netbox-community/netbox/issues/11259) - Add support for Redis username configuration
### Bug Fixes
* [#11280](https://github.com/netbox-community/netbox/issues/11280) - Fix errant newlines when exporting interfaces with multiple IP addresses assigned
* [#11290](https://github.com/netbox-community/netbox/issues/11290) - Correct reporting of scheduled job duration
* [#11232](https://github.com/netbox-community/netbox/issues/11232) - Enable partial & regular expression matching for non-string types in global search
* [#11342](https://github.com/netbox-community/netbox/issues/11342) - Correct cable trace URL under "connection" tab for device components
* [#11345](https://github.com/netbox-community/netbox/issues/11345) - Fix form validation for bulk import of modules
---
## v3.4.1 (2022-12-16)
### Enhancements
* [#9971](https://github.com/netbox-community/netbox/issues/9971) - Enable ordering of nested group models by name
* [#11214](https://github.com/netbox-community/netbox/issues/11214) - Introduce the `DEFAULT_LANGUAGE` configuration parameter
### Bug Fixes
* [#11175](https://github.com/netbox-community/netbox/issues/11175) - Fix cloning of fields containing special characters
* [#11178](https://github.com/netbox-community/netbox/issues/11178) - Pressing enter in quick search box should not trigger bulk operations
* [#11184](https://github.com/netbox-community/netbox/issues/11184) - Correct visualization of cable path which splits across multiple circuit terminations
* [#11185](https://github.com/netbox-community/netbox/issues/11185) - Fix TemplateSyntaxError when viewing custom script results
* [#11189](https://github.com/netbox-community/netbox/issues/11189) - Fix localization of dates & numbers
* [#11205](https://github.com/netbox-community/netbox/issues/11205) - Correct cloning behavior for recursively-nested models
* [#11206](https://github.com/netbox-community/netbox/issues/11206) - Avoid clearing assigned groups if `REMOTE_AUTH_DEFAULT_GROUPS` is invalid
---
## v3.4.0 (2022-12-14)
!!! warning "PostgreSQL 11 Required"
NetBox v3.4 requires PostgreSQL 11 or later.
### Breaking Changes
* Device and virtual machine names are no longer case-sensitive. Attempting to create e.g. "device1" and "DEVICE1" within the same site will raise a validation error.
* The `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields have been removed from the provider model. Please replicate any data remaining in these fields to the ASN and contact models introduced in NetBox v3.1 prior to upgrading.
* The `content_type` fields on the CustomLink and ExportTemplate models have been renamed to `content_types` and now support the assignment of multiple content types per object.
* Within the Python API, the `cf` property on an object with custom fields now returns deserialized values. For example, a custom field referencing an object will return the object instance rather than its numeric ID. To access the raw serialized values, reference the object's `custom_field_data` attribute instead.
* The `NetBoxModelCSVForm` class has been renamed to `NetBoxModelImportForm`. Backward compatability with the previous name has been retained for this release, but will be dropped in NetBox v3.5.
### New Features
#### New Global Search ([#10560](https://github.com/netbox-community/netbox/issues/10560))
NetBox's global search functionality has been completely overhauled and replaced by a new cache-based lookup. This new implementation provides a much faster, more intelligent search capability. Results are returned in order of precedence regardless of object type, and matching field values are highlighted in the results. Additionally, custom field values are now included in global search results (where enabled). Plugins can also register their own models with the new global search engine.
#### Virtual Device Contexts ([#7854](https://github.com/netbox-community/netbox/issues/7854))
A new model representing virtual device contexts (VDCs) has been added. VDCs are logical partitions of resources within a device that can be managed independently. A VDC is created within a device and may have device interfaces assigned to it. An interface can be allocated to any number of VDCs on its device.
#### Saved Filters ([#9623](https://github.com/netbox-community/netbox/issues/9623))
Object lists can be filtered by a variety of different fields and characteristics. Applied filters can now be saved for reuse. For example, the query string
```
?status=active&region_id=12&tenant=acme
```
can be saved and applied to future queries as
```
?filter=my-custom-filter
```
Saved filters can be kept private, or shared among NetBox users. They can be applied to both UI and REST API searches.
#### JSON/YAML Bulk Imports ([#4347](https://github.com/netbox-community/netbox/issues/4347))
NetBox's bulk import feature, which was previously limited to CSV-formatted data for most types of objects, has been extended to accept data formatted in JSON or YAML as well. This enables users to directly import objects from a variety of sources without needing to first convert data to CSV. NetBox will attempt to automatically determine the format of import data if not specified by the user.
#### Update Existing Objects via Bulk Import ([#7961](https://github.com/netbox-community/netbox/issues/7961))
NetBox's CSV-based bulk import functionality has been extended to support also modifying existing objects. When an `id` column is present in the import form, it will be used to infer the object to be modified, rather than a new object being created. All fields (columns) are optional when modifying existing objects.
#### Scheduled Reports & Scripts ([#8366](https://github.com/netbox-community/netbox/issues/8366))
Reports and custom scripts can now be scheduled for execution at a desired future time. Background scheduling is handled entirely by the existing RQ workers; there is no need to configure additional tasks to support scheduled jobs. When creating a scheduled job, the user may optionally specify an interval at which the job will run repeatedly (e.g. every 24 hours).
#### API for Staged Changes ([#10851](https://github.com/netbox-community/netbox/issues/10851))
This release introduces a new programmatic API that enables plugins and custom scripts to prepare changes in NetBox without actually committing them to the active database. To stage changes, create and activate a branch using the `checkout()` context manager. Any changes made within this context will be captured, recorded, and rolled back for future use. Once ready, a branch can be applied to the active database by calling `merge()`.
!!! danger "Experimental Feature"
This feature is still under active development and considered experimental in nature. Its use in production is strongly discouraged at this time.
### Enhancements
* [#815](https://github.com/netbox-community/netbox/issues/815) - Enable specifying terminations when bulk importing circuits
* [#6003](https://github.com/netbox-community/netbox/issues/6003) - Enable the inclusion of custom field values in global search
* [#7376](https://github.com/netbox-community/netbox/issues/7376) - Enable the assignment of tags during CSV import
* [#8245](https://github.com/netbox-community/netbox/issues/8245) - Enable GraphQL filtering of related objects
* [#8274](https://github.com/netbox-community/netbox/issues/8274) - Enable associating a custom link with multiple object types
* [#8485](https://github.com/netbox-community/netbox/issues/8485) - Enable journaling for all organizational models
* [#8853](https://github.com/netbox-community/netbox/issues/8853) - Introduce the `ALLOW_TOKEN_RETRIEVAL` config parameter to restrict the display of API tokens
* [#9249](https://github.com/netbox-community/netbox/issues/9249) - Device and virtual machine names are no longer case-sensitive
* [#9478](https://github.com/netbox-community/netbox/issues/9478) - Add `link_peers` field to GraphQL types for cabled objects
* [#9654](https://github.com/netbox-community/netbox/issues/9654) - Add `weight` field to racks, device types, and module types
* [#9817](https://github.com/netbox-community/netbox/issues/9817) - Add `assigned_object` field to GraphQL type for IP addresses and L2VPN terminations
* [#9832](https://github.com/netbox-community/netbox/issues/9832) - Add `mounting_depth` field to rack model
* [#9892](https://github.com/netbox-community/netbox/issues/9892) - Add optional `name` field for FHRP groups
* [#10348](https://github.com/netbox-community/netbox/issues/10348) - Add decimal custom field type
* [#10371](https://github.com/netbox-community/netbox/issues/10371) - Add `status` field for modules
* [#10545](https://github.com/netbox-community/netbox/issues/10545) - Standardize the use of `description` and `comments` fields on all primary models
* [#10556](https://github.com/netbox-community/netbox/issues/10556) - Include a `display` field in all GraphQL object types
* [#10595](https://github.com/netbox-community/netbox/issues/10595) - Add GraphQL relationships for additional generic foreign key fields
* [#10675](https://github.com/netbox-community/netbox/issues/10675) - Add `max_weight` field to track maximum load capacity for racks
* [#10698](https://github.com/netbox-community/netbox/issues/10698) - Omit app label from content type in table columns
* [#10710](https://github.com/netbox-community/netbox/issues/10710) - Add `status` field to WirelessLAN
* [#10761](https://github.com/netbox-community/netbox/issues/10761) - Enable associating an export template with multiple object types
* [#10945](https://github.com/netbox-community/netbox/issues/10945) - Enable recurring execution of scheduled reports & scripts
* [#11022](https://github.com/netbox-community/netbox/issues/11022) - Introduce `QUEUE_MAPPINGS` configuration parameter to allow customization of background task prioritization
### Bug Fixes (from v3.4-beta1)
* [#10946](https://github.com/netbox-community/netbox/issues/10946) - Fix AttributeError exception when viewing a device with a primary IP and no platform assigned
* [#10948](https://github.com/netbox-community/netbox/issues/10948) - Linkify primary IPs for VDCs
* [#10950](https://github.com/netbox-community/netbox/issues/10950) - Fix validation of VDC primary IPs
* [#10957](https://github.com/netbox-community/netbox/issues/10957) - Add missing VDCs column to interface tables
* [#10973](https://github.com/netbox-community/netbox/issues/10973) - Fix device links in VDC table
* [#10980](https://github.com/netbox-community/netbox/issues/10980) - Fix view tabs for plugin objects
* [#10982](https://github.com/netbox-community/netbox/issues/10982) - Catch `NoReverseMatch` exception when rendering tabs with no registered URL
* [#10984](https://github.com/netbox-community/netbox/issues/10984) - Fix navigation menu expansion for plugin menus comprising multiple words
* [#11000](https://github.com/netbox-community/netbox/issues/11000) - Improve validation of YAML-formatted import data
* [#11046](https://github.com/netbox-community/netbox/issues/11046) - Fix exception when caching very large field values for search
* [#11154](https://github.com/netbox-community/netbox/issues/11154) - Index VM interface MAC address and MTU for global search
* [#11171](https://github.com/netbox-community/netbox/issues/11171) - Fix querying of related objects under GraphQL API
### Plugins API
* [#4751](https://github.com/netbox-community/netbox/issues/4751) - Enable embedding custom content on core list views via `list_buttons()` method
* [#8927](https://github.com/netbox-community/netbox/issues/8927) - Enable inclusion of plugin models in global search via `SearchIndex`
* [#9071](https://github.com/netbox-community/netbox/issues/9071) - Enable plugins to register top-level navigation menus using PluginMenu
* [#9072](https://github.com/netbox-community/netbox/issues/9072) - Enable registration of tabbed plugin views for core NetBox models
* [#9880](https://github.com/netbox-community/netbox/issues/9880) - Enable plugins to install and register other Django apps via `django_apps` attribute
* [#9887](https://github.com/netbox-community/netbox/issues/9887) - Inspect `docs_url` property to determine link to model documentation
* [#10314](https://github.com/netbox-community/netbox/issues/10314) - Move `clone()` method from NetBoxModel to CloningMixin
* [#10543](https://github.com/netbox-community/netbox/issues/10543) - Introduce `get_plugin_config()` utility function
* [#10739](https://github.com/netbox-community/netbox/issues/10739) - Introduce `get_queryset()` method on generic views
### Other Changes
* [#9045](https://github.com/netbox-community/netbox/issues/9045) - Remove legacy ASN field from provider model
* [#9046](https://github.com/netbox-community/netbox/issues/9046) - Remove legacy contact fields from provider model
* [#10052](https://github.com/netbox-community/netbox/issues/10052) - The `cf` attribute on objects now returns deserialized custom field data
* [#10358](https://github.com/netbox-community/netbox/issues/10358) - Raise minimum required PostgreSQL version from 10 to 11
* [#10694](https://github.com/netbox-community/netbox/issues/10694) - Emit the `post_save` signal when creating device components in bulk
* [#10697](https://github.com/netbox-community/netbox/issues/10697) - Move application registry into core app
* [#10699](https://github.com/netbox-community/netbox/issues/10699) - Remove unused custom `import_object()` function
* [#10781](https://github.com/netbox-community/netbox/issues/10781) - Add support for Python v3.11
* [#10816](https://github.com/netbox-community/netbox/issues/10816) - Pass the current request as context when instantiating a FilterSet within UI views
* [#10820](https://github.com/netbox-community/netbox/issues/10820) - Switch timezone library from pytz to zoneinfo
* [#10821](https://github.com/netbox-community/netbox/issues/10821) - Enable data localization
### REST API Changes
* Added the `/api/dcim/virtual-device-contexts/` endpoint
* circuits.provider
* Removed the `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields
* Added a `description` field
* dcim.Cable
* Added `description` and `comments` fields
* dcim.Device
* Added a `description` field
* dcim.DeviceType
* Added `description`, `weight`, and `weight_unit` fields
* dcim.Module
* Added a `description` field
* dcim.Interface
* Added the `vdcs` field
* dcim.Module
* Added a required `status` field
* dcim.ModuleType
* Added `description`, `weight`, and `weight_unit` fields
* dcim.PowerFeed
* Added a `description` field
* dcim.PowerPanel
* Added `description` and `comments` fields
* dcim.Rack
* Added `description`, `mounting_depth`, `weight`, `max_weight`, and `weight_unit` fields
* dcim.RackReservation
* Added a `comments` field
* dcim.VirtualChassis
* Added `description` and `comments` fields
* extras.CustomField
* Added a `search_weight` field
* extras.CustomLink
* Renamed `content_type` field to `content_types`
* extras.ExportTemplate
* Renamed `content_type` field to `content_types`
* extras.JobResult
* Added `interval`, `scheduled`, and `started` fields
* ipam.Aggregate
* Added a `comments` field
* ipam.ASN
* Added a `comments` field
* ipam.FHRPGroup
* Added `name` and `comments` fields
* ipam.IPAddress
* Added a `comments` field
* ipam.IPRange
* Added a `comments` field
* ipam.L2VPN
* Added a `comments` field
* ipam.Prefix
* Added a `comments` field
* ipam.RouteTarget
* Added a `comments` field
* ipam.Service
* Added a `comments` field
* ipam.ServiceTemplate
* Added a `comments` field
* ipam.VLAN
* Added a `comments` field
* ipam.VRF
* Added a `comments` field
* tenancy.Contact
* Added a `description` field
* virtualization.Cluster
* Added a `description` field
* virtualization.VirtualMachine
* Added a `description` field
* wireless.WirelessLAN
* Added a required `status` choice field
* Added a `comments` field
* wireless.WirelessLink
* Added a `comments` field
### GraphQL API Changes
* All object types now include a `display` field
* All cabled object types now include a `link_peers` field
* Add a `contacts` relationship for all relevant models
* dcim.Cable
* Add A/B terminations fields
* dcim.CableTermination
* Add `termination` field
* dcim.InventoryItem
* Add `component` field
* dcim.InventoryItemTemplate
* Add `component` field
* dcim.Rack
* Add `mounting_depth` field
* ipam.FHRPGroupAssignment
* Add `interface` field
* ipam.IPAddress
* Add `assigned_object` field
* ipam.L2VPNTermination
* Add `assigned_object` field
* ipam.VLANGroupType
* Add `scope` field

View File

@@ -30,7 +30,7 @@ plugins:
- os.chdir('netbox/')
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings")
- django.setup()
rendering:
options:
heading_level: 3
members_order: source
show_root_heading: true
@@ -38,7 +38,6 @@ plugins:
show_root_toc_entry: false
show_source: false
extra:
readthedocs: !ENV READTHEDOCS
social:
- icon: fontawesome/brands/github
link: https://github.com/netbox-community/netbox
@@ -73,6 +72,7 @@ nav:
- Virtualization: 'features/virtualization.md'
- Tenancy: 'features/tenancy.md'
- Contacts: 'features/contacts.md'
- Search: 'features/search.md'
- Context Data: 'features/context-data.md'
- Change Logging: 'features/change-logging.md'
- Journaling: 'features/journaling.md'
@@ -129,9 +129,11 @@ nav:
- Tables: 'plugins/development/tables.md'
- Forms: 'plugins/development/forms.md'
- Filters & Filter Sets: 'plugins/development/filtersets.md'
- Search: 'plugins/development/search.md'
- REST API: 'plugins/development/rest-api.md'
- GraphQL API: 'plugins/development/graphql-api.md'
- Background Tasks: 'plugins/development/background-tasks.md'
- Staged Changes: 'plugins/development/staged-changes.md'
- Exceptions: 'plugins/development/exceptions.md'
- Administration:
- Authentication:
@@ -190,13 +192,17 @@ nav:
- Site: 'models/dcim/site.md'
- SiteGroup: 'models/dcim/sitegroup.md'
- VirtualChassis: 'models/dcim/virtualchassis.md'
- VirtualDeviceContext: 'models/dcim/virtualdevicecontext.md'
- Extras:
- Branch: 'models/extras/branch.md'
- ConfigContext: 'models/extras/configcontext.md'
- CustomField: 'models/extras/customfield.md'
- CustomLink: 'models/extras/customlink.md'
- ExportTemplate: 'models/extras/exporttemplate.md'
- ImageAttachment: 'models/extras/imageattachment.md'
- JournalEntry: 'models/extras/journalentry.md'
- SavedFilter: 'models/extras/savedfilter.md'
- StagedChange: 'models/extras/stagedchange.md'
- Tag: 'models/extras/tag.md'
- Webhook: 'models/extras/webhook.md'
- IPAM:
@@ -245,6 +251,7 @@ nav:
- Adding Models: 'development/adding-models.md'
- Extending Models: 'development/extending-models.md'
- Signals: 'development/signals.md'
- Search: 'development/search.md'
- Application Registry: 'development/application-registry.md'
- User Preferences: 'development/user-preferences.md'
- Web UI: 'development/web-ui.md'
@@ -252,6 +259,7 @@ nav:
- git Cheat Sheet: 'development/git-cheat-sheet.md'
- Release Notes:
- Summary: 'release-notes/index.md'
- Version 3.4: 'release-notes/version-3.4.md'
- Version 3.3: 'release-notes/version-3.3.md'
- Version 3.2: 'release-notes/version-3.2.md'
- Version 3.1: 'release-notes/version-3.1.md'

View File

@@ -31,8 +31,8 @@ class ProviderSerializer(NetBoxModelSerializer):
class Meta:
model = Provider
fields = [
'id', 'url', 'display', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact',
'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count',
'id', 'url', 'display', 'name', 'slug', 'account', 'description', 'comments', 'asns', 'tags',
'custom_fields', 'created', 'last_updated', 'circuit_count',
]
@@ -77,6 +77,7 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
model = CircuitTermination
fields = [
'id', 'url', 'display', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id',
'description',
]

View File

@@ -6,4 +6,4 @@ class CircuitsConfig(AppConfig):
verbose_name = "Circuits"
def ready(self):
import circuits.signals
from . import signals, search

View File

@@ -1,5 +1,6 @@
import django_filters
from django.db.models import Q
from django.utils.translation import gettext as _
from dcim.filtersets import CabledObjectFilterSet
from dcim.models import Region, Site, SiteGroup
@@ -24,48 +25,48 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
queryset=Region.objects.all(),
field_name='circuits__terminations__site__region',
lookup_expr='in',
label='Region (ID)',
label=_('Region (ID)'),
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='circuits__terminations__site__region',
lookup_expr='in',
to_field_name='slug',
label='Region (slug)',
label=_('Region (slug)'),
)
site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='circuits__terminations__site__group',
lookup_expr='in',
label='Site group (ID)',
label=_('Site group (ID)'),
)
site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='circuits__terminations__site__group',
lookup_expr='in',
to_field_name='slug',
label='Site group (slug)',
label=_('Site group (slug)'),
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='circuits__terminations__site',
queryset=Site.objects.all(),
label='Site',
label=_('Site'),
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='circuits__terminations__site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
label=_('Site (slug)'),
)
asn_id = django_filters.ModelMultipleChoiceFilter(
field_name='asns',
queryset=ASN.objects.all(),
label='ASN (ID)',
label=_('ASN (ID)'),
)
class Meta:
model = Provider
fields = ['id', 'name', 'slug', 'asn', 'account']
fields = ['id', 'name', 'slug', 'account']
def search(self, queryset, name, value):
if not value.strip():
@@ -73,8 +74,6 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
return queryset.filter(
Q(name__icontains=value) |
Q(account__icontains=value) |
Q(noc_contact__icontains=value) |
Q(admin_contact__icontains=value) |
Q(comments__icontains=value)
)
@@ -82,13 +81,13 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
class ProviderNetworkFilterSet(NetBoxModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(),
label='Provider (ID)',
label=_('Provider (ID)'),
)
provider = django_filters.ModelMultipleChoiceFilter(
field_name='provider__slug',
queryset=Provider.objects.all(),
to_field_name='slug',
label='Provider (slug)',
label=_('Provider (slug)'),
)
class Meta:
@@ -116,28 +115,28 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(),
label='Provider (ID)',
label=_('Provider (ID)'),
)
provider = django_filters.ModelMultipleChoiceFilter(
field_name='provider__slug',
queryset=Provider.objects.all(),
to_field_name='slug',
label='Provider (slug)',
label=_('Provider (slug)'),
)
provider_network_id = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__provider_network',
queryset=ProviderNetwork.objects.all(),
label='ProviderNetwork (ID)',
label=_('ProviderNetwork (ID)'),
)
type_id = django_filters.ModelMultipleChoiceFilter(
queryset=CircuitType.objects.all(),
label='Circuit type (ID)',
label=_('Circuit type (ID)'),
)
type = django_filters.ModelMultipleChoiceFilter(
field_name='type__slug',
queryset=CircuitType.objects.all(),
to_field_name='slug',
label='Circuit type (slug)',
label=_('Circuit type (slug)'),
)
status = django_filters.MultipleChoiceFilter(
choices=CircuitStatusChoices,
@@ -147,38 +146,38 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
queryset=Region.objects.all(),
field_name='terminations__site__region',
lookup_expr='in',
label='Region (ID)',
label=_('Region (ID)'),
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='terminations__site__region',
lookup_expr='in',
to_field_name='slug',
label='Region (slug)',
label=_('Region (slug)'),
)
site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='terminations__site__group',
lookup_expr='in',
label='Site group (ID)',
label=_('Site group (ID)'),
)
site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='terminations__site__group',
lookup_expr='in',
to_field_name='slug',
label='Site group (slug)',
label=_('Site group (slug)'),
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__site',
queryset=Site.objects.all(),
label='Site (ID)',
label=_('Site (ID)'),
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
label=_('Site (slug)'),
)
class Meta:
@@ -201,25 +200,25 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
label=_('Search'),
)
circuit_id = django_filters.ModelMultipleChoiceFilter(
queryset=Circuit.objects.all(),
label='Circuit',
label=_('Circuit'),
)
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label='Site (ID)',
label=_('Site (ID)'),
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
label=_('Site (slug)'),
)
provider_network_id = django_filters.ModelMultipleChoiceFilter(
queryset=ProviderNetwork.objects.all(),
label='ProviderNetwork (ID)',
label=_('ProviderNetwork (ID)'),
)
class Meta:

View File

@@ -1,4 +1,4 @@
from .bulk_edit import *
from .bulk_import import *
from .filtersets import *
from .models import *
from .model_forms import *

View File

@@ -20,10 +20,6 @@ __all__ = (
class ProviderBulkEditForm(NetBoxModelBulkEditForm):
asn = forms.IntegerField(
required=False,
label='ASN (legacy)'
)
asns = DynamicModelMultipleChoiceField(
queryset=ASN.objects.all(),
label=_('ASNs'),
@@ -32,33 +28,23 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
account = forms.CharField(
max_length=30,
required=False,
label='Account number'
label=_('Account number')
)
portal_url = forms.URLField(
required=False,
label='Portal'
)
noc_contact = forms.CharField(
required=False,
widget=SmallTextarea,
label='NOC contact'
)
admin_contact = forms.CharField(
required=False,
widget=SmallTextarea,
label='Admin contact'
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
label=_('Comments')
)
model = Provider
fieldsets = (
(None, ('asn', 'asns', 'account', 'portal_url', 'noc_contact', 'admin_contact')),
(None, ('asns', 'account', )),
)
nullable_fields = (
'asn', 'asns', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
'asns', 'account', 'description', 'comments',
)
@@ -70,7 +56,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
service_id = forms.CharField(
max_length=100,
required=False,
label='Service ID'
label=_('Service ID')
)
description = forms.CharField(
max_length=200,
@@ -78,7 +64,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
label=_('Comments')
)
model = ProviderNetwork
@@ -132,7 +118,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
)
commit_rate = forms.IntegerField(
required=False,
label='Commit rate (Kbps)'
label=_('Commit rate (Kbps)')
)
description = forms.CharField(
max_length=100,
@@ -140,7 +126,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
label=_('Comments')
)
model = Circuit

View File

@@ -1,77 +1,102 @@
from django import forms
from circuits.choices import CircuitStatusChoices
from circuits.models import *
from netbox.forms import NetBoxModelCSVForm
from dcim.models import Site
from django.utils.translation import gettext as _
from netbox.forms import NetBoxModelImportForm
from tenancy.models import Tenant
from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
from utilities.forms import BootstrapMixin, CSVChoiceField, CSVModelChoiceField, SlugField
__all__ = (
'CircuitCSVForm',
'CircuitTypeCSVForm',
'ProviderCSVForm',
'ProviderNetworkCSVForm',
'CircuitImportForm',
'CircuitTerminationImportForm',
'CircuitTypeImportForm',
'ProviderImportForm',
'ProviderNetworkImportForm',
)
class ProviderCSVForm(NetBoxModelCSVForm):
class ProviderImportForm(NetBoxModelImportForm):
slug = SlugField()
class Meta:
model = Provider
fields = (
'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
'name', 'slug', 'account', 'description', 'comments', 'tags',
)
class ProviderNetworkCSVForm(NetBoxModelCSVForm):
class ProviderNetworkImportForm(NetBoxModelImportForm):
provider = CSVModelChoiceField(
queryset=Provider.objects.all(),
to_field_name='name',
help_text='Assigned provider'
help_text=_('Assigned provider')
)
class Meta:
model = ProviderNetwork
fields = [
'provider', 'name', 'service_id', 'description', 'comments',
'provider', 'name', 'service_id', 'description', 'comments', 'tags'
]
class CircuitTypeCSVForm(NetBoxModelCSVForm):
class CircuitTypeImportForm(NetBoxModelImportForm):
slug = SlugField()
class Meta:
model = CircuitType
fields = ('name', 'slug', 'description')
fields = ('name', 'slug', 'description', 'tags')
help_texts = {
'name': 'Name of circuit type',
'name': _('Name of circuit type'),
}
class CircuitCSVForm(NetBoxModelCSVForm):
class CircuitImportForm(NetBoxModelImportForm):
provider = CSVModelChoiceField(
queryset=Provider.objects.all(),
to_field_name='name',
help_text='Assigned provider'
help_text=_('Assigned provider')
)
type = CSVModelChoiceField(
queryset=CircuitType.objects.all(),
to_field_name='name',
help_text='Type of circuit'
help_text=_('Type of circuit')
)
status = CSVChoiceField(
choices=CircuitStatusChoices,
help_text='Operational status'
help_text=_('Operational status')
)
tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(),
required=False,
to_field_name='name',
help_text='Assigned tenant'
help_text=_('Assigned tenant')
)
class Meta:
model = Circuit
fields = [
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate',
'description', 'comments',
'description', 'comments', 'tags'
]
class CircuitTerminationImportForm(BootstrapMixin, forms.ModelForm):
site = CSVModelChoiceField(
queryset=Site.objects.all(),
to_field_name='name',
required=False
)
provider_network = CSVModelChoiceField(
queryset=ProviderNetwork.objects.all(),
to_field_name='name',
required=False
)
class Meta:
model = CircuitTermination
fields = [
'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id',
'pp_info', 'description',
]

View File

@@ -20,7 +20,7 @@ __all__ = (
class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
model = Provider
fieldsets = (
(None, ('q', 'tag')),
(None, ('q', 'filter_id', 'tag')),
('Location', ('region_id', 'site_group_id', 'site_id')),
('ASN', ('asn',)),
('Contacts', ('contact', 'contact_role', 'contact_group')),
@@ -59,7 +59,7 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
model = ProviderNetwork
fieldsets = (
(None, ('q', 'tag')),
(None, ('q', 'filter_id', 'tag')),
('Attributes', ('provider_id', 'service_id')),
)
provider_id = DynamicModelMultipleChoiceField(
@@ -82,7 +82,7 @@ class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
model = Circuit
fieldsets = (
(None, ('q', 'tag')),
(None, ('q', 'filter_id', 'tag')),
('Provider', ('provider_id', 'provider_network_id')),
('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
('Location', ('region_id', 'site_group_id', 'site_id')),

View File

@@ -1,4 +1,3 @@
from django import forms
from django.utils.translation import gettext as _
from circuits.models import *
@@ -7,8 +6,8 @@ from ipam.models import ASN
from netbox.forms import NetBoxModelForm
from tenancy.forms import TenancyForm
from utilities.forms import (
BootstrapMixin, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
SelectSpeedWidget, SmallTextarea, SlugField, StaticSelect,
CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SlugField,
StaticSelect,
)
__all__ = (
@@ -30,29 +29,17 @@ class ProviderForm(NetBoxModelForm):
comments = CommentField()
fieldsets = (
('Provider', ('name', 'slug', 'asn', 'asns', 'tags')),
('Support Info', ('account', 'portal_url', 'noc_contact', 'admin_contact')),
('Provider', ('name', 'slug', 'asns', 'description', 'tags')),
('Support Info', ('account',)),
)
class Meta:
model = Provider
fields = [
'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'asns', 'comments', 'tags',
'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags',
]
widgets = {
'noc_contact': SmallTextarea(
attrs={'rows': 5}
),
'admin_contact': SmallTextarea(
attrs={'rows': 5}
),
}
help_texts = {
'name': "Full name of the provider",
'asn': "BGP autonomous system number (if applicable)",
'portal_url': "URL of the provider's customer support portal",
'noc_contact': "NOC email address and phone number",
'admin_contact': "Administrative contact email address and phone number",
'name': _("Full name of the provider"),
}
@@ -76,6 +63,12 @@ class ProviderNetworkForm(NetBoxModelForm):
class CircuitTypeForm(NetBoxModelForm):
slug = SlugField()
fieldsets = (
('Circuit Type', (
'name', 'slug', 'description', 'tags',
)),
)
class Meta:
model = CircuitType
fields = [
@@ -105,8 +98,8 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
'tenant_group', 'tenant', 'comments', 'tags',
]
help_texts = {
'cid': "Unique circuit ID",
'commit_rate': "Committed rate",
'cid': _("Unique circuit ID"),
'commit_rate': _("Committed rate"),
}
widgets = {
'status': StaticSelect(),
@@ -152,21 +145,33 @@ class CircuitTerminationForm(NetBoxModelForm):
},
required=False
)
provider_network_provider = DynamicModelChoiceField(
queryset=Provider.objects.all(),
required=False,
label='Provider',
initial_params={
'networks': 'provider_network'
}
)
provider_network = DynamicModelChoiceField(
queryset=ProviderNetwork.objects.all(),
query_params={
'provider_id': '$provider_network_provider',
},
required=False
)
class Meta:
model = CircuitTermination
fields = [
'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected',
'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags',
'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network_provider',
'provider_network', 'mark_connected', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
'description', 'tags',
]
help_texts = {
'port_speed': "Physical circuit speed",
'xconnect_id': "ID of the local cross-connect",
'pp_info': "Patch panel ID and port number(s)"
'port_speed': _("Physical circuit speed"),
'xconnect_id': _("ID of the local cross-connect"),
'pp_info': _("Patch panel ID and port number(s)")
}
widgets = {
'term_side': StaticSelect(),

View File

@@ -1,6 +1,8 @@
import graphene
from circuits import filtersets, models
from dcim.graphql.mixins import CabledObjectMixin
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin, ContactsMixin
from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObjectType
__all__ = (
@@ -20,8 +22,7 @@ class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, Ob
filterset_class = filtersets.CircuitTerminationFilterSet
class CircuitType(NetBoxObjectType):
class CircuitType(NetBoxObjectType, ContactsMixin):
class Meta:
model = models.Circuit
fields = '__all__'
@@ -36,7 +37,7 @@ class CircuitTypeType(OrganizationalObjectType):
filterset_class = filtersets.CircuitTypeFilterSet
class ProviderType(NetBoxObjectType):
class ProviderType(NetBoxObjectType, ContactsMixin):
class Meta:
model = models.Provider

View File

@@ -1,5 +1,5 @@
import dcim.fields
import django.core.serializers.json
from utilities.json import CustomFieldJSONEncoder
from django.db import migrations, models
import django.db.models.deletion
@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
fields=[
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('cid', models.CharField(max_length=100)),
('status', models.CharField(default='active', max_length=50)),
@@ -58,14 +58,14 @@ class Migration(migrations.Migration):
fields=[
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, unique=True)),
('slug', models.SlugField(max_length=100, unique=True)),
('description', models.CharField(blank=True, max_length=200)),
],
options={
'ordering': ['name'],
'ordering': ('name',),
},
),
migrations.CreateModel(
@@ -73,7 +73,7 @@ class Migration(migrations.Migration):
fields=[
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, unique=True)),
('slug', models.SlugField(max_length=100, unique=True)),
@@ -93,7 +93,7 @@ class Migration(migrations.Migration):
fields=[
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100)),
('description', models.CharField(blank=True, max_length=200)),

View File

@@ -1,4 +1,4 @@
import django.core.serializers.json
from utilities.json import CustomFieldJSONEncoder
from django.db import migrations, models
import taggit.managers
@@ -18,7 +18,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='circuittermination',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
field=models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder),
),
migrations.AddField(
model_name='circuittermination',

View File

@@ -0,0 +1,39 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('circuits', '0038_cabling_cleanup'),
]
operations = [
migrations.RemoveConstraint(
model_name='providernetwork',
name='circuits_providernetwork_provider_name',
),
migrations.AlterUniqueTogether(
name='circuit',
unique_together=set(),
),
migrations.AlterUniqueTogether(
name='circuittermination',
unique_together=set(),
),
migrations.AlterUniqueTogether(
name='providernetwork',
unique_together=set(),
),
migrations.AddConstraint(
model_name='circuit',
constraint=models.UniqueConstraint(fields=('provider', 'cid'), name='circuits_circuit_unique_provider_cid'),
),
migrations.AddConstraint(
model_name='circuittermination',
constraint=models.UniqueConstraint(fields=('circuit', 'term_side'), name='circuits_circuittermination_unique_circuit_term_side'),
),
migrations.AddConstraint(
model_name='providernetwork',
constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_unique_provider_name'),
),
]

View File

@@ -0,0 +1,59 @@
import os
from django.db import migrations
from django.db.utils import DataError
def check_legacy_data(apps, schema_editor):
"""
Abort the migration if any legacy provider fields still contain data.
"""
Provider = apps.get_model('circuits', 'Provider')
provider_count = Provider.objects.exclude(asn__isnull=True).count()
if provider_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
raise DataError(
f"Unable to proceed with deleting asn field from Provider model: Found {provider_count} "
f"providers with legacy ASN data. Please ensure all legacy provider ASN data has been "
f"migrated to ASN objects before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA "
f"environment variable to bypass this safeguard and delete all legacy provider ASN data."
)
provider_count = Provider.objects.exclude(admin_contact='', noc_contact='', portal_url='').count()
if provider_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
raise DataError(
f"Unable to proceed with deleting contact fields from Provider model: Found {provider_count} "
f"providers with legacy contact data. Please ensure all legacy provider contact data has been "
f"migrated to contact objects before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA "
f"environment variable to bypass this safeguard and delete all legacy provider contact data."
)
class Migration(migrations.Migration):
dependencies = [
('circuits', '0039_unique_constraints'),
]
operations = [
migrations.RunPython(
code=check_legacy_data,
reverse_code=migrations.RunPython.noop
),
migrations.RemoveField(
model_name='provider',
name='admin_contact',
),
migrations.RemoveField(
model_name='provider',
name='asn',
),
migrations.RemoveField(
model_name='provider',
name='noc_contact',
),
migrations.RemoveField(
model_name='provider',
name='portal_url',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.1.2 on 2022-11-03 18:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('circuits', '0040_provider_remove_deprecated_fields'),
]
operations = [
migrations.AddField(
model_name='provider',
name='description',
field=models.CharField(blank=True, max_length=200),
),
]

View File

@@ -3,11 +3,12 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext as _
from circuits.choices import *
from dcim.models import CabledObjectModel
from netbox.models import (
ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin,
ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, PrimaryModel, TagsMixin,
)
from netbox.models.features import WebhooksMixin
@@ -23,30 +24,11 @@ class CircuitType(OrganizationalModel):
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
"Long Haul," "Metro," or "Out-of-Band".
"""
name = models.CharField(
max_length=100,
unique=True
)
slug = models.SlugField(
max_length=100,
unique=True
)
description = models.CharField(
max_length=200,
blank=True,
)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('circuits:circuittype', args=[self.pk])
class Circuit(NetBoxModel):
class Circuit(PrimaryModel):
"""
A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple
circuits. Each circuit is also assigned a CircuitType and a Site. Circuit port speed and commit rate are measured
@@ -92,13 +74,6 @@ class Circuit(NetBoxModel):
blank=True,
null=True,
verbose_name='Commit rate (Kbps)')
description = models.CharField(
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
)
# Generic relations
contacts = GenericRelation(
@@ -129,18 +104,23 @@ class Circuit(NetBoxModel):
clone_fields = (
'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate', 'description',
)
prerequisite_models = (
'circuits.CircuitType',
'circuits.Provider',
)
class Meta:
ordering = ['provider', 'cid']
unique_together = ['provider', 'cid']
constraints = (
models.UniqueConstraint(
fields=('provider', 'cid'),
name='%(app_label)s_%(class)s_unique_provider_cid'
),
)
def __str__(self):
return self.cid
@classmethod
def get_prerequisite_models(cls):
return [apps.get_model('circuits.Provider'), CircuitType]
def get_absolute_url(self):
return reverse('circuits:circuit', args=[self.pk])
@@ -189,7 +169,7 @@ class CircuitTermination(
blank=True,
null=True,
verbose_name='Upstream speed (Kbps)',
help_text='Upstream speed, if different from port speed'
help_text=_('Upstream speed, if different from port speed')
)
xconnect_id = models.CharField(
max_length=50,
@@ -208,7 +188,12 @@ class CircuitTermination(
class Meta:
ordering = ['circuit', 'term_side']
unique_together = ['circuit', 'term_side']
constraints = (
models.UniqueConstraint(
fields=('circuit', 'term_side'),
name='%(app_label)s_%(class)s_unique_circuit_term_side'
),
)
def __str__(self):
return f'Termination {self.term_side}: {self.site or self.provider_network}'

View File

@@ -2,8 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from django.urls import reverse
from dcim.fields import ASNField
from netbox.models import NetBoxModel
from netbox.models import PrimaryModel
__all__ = (
'ProviderNetwork',
@@ -11,7 +10,7 @@ __all__ = (
)
class Provider(NetBoxModel):
class Provider(PrimaryModel):
"""
Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
stores information pertinent to the user's relationship with the Provider.
@@ -24,12 +23,6 @@ class Provider(NetBoxModel):
max_length=100,
unique=True
)
asn = ASNField(
blank=True,
null=True,
verbose_name='ASN',
help_text='32-bit autonomous system number'
)
asns = models.ManyToManyField(
to='ipam.ASN',
related_name='providers',
@@ -40,21 +33,6 @@ class Provider(NetBoxModel):
blank=True,
verbose_name='Account number'
)
portal_url = models.URLField(
blank=True,
verbose_name='Portal URL'
)
noc_contact = models.TextField(
blank=True,
verbose_name='NOC contact'
)
admin_contact = models.TextField(
blank=True,
verbose_name='Admin contact'
)
comments = models.TextField(
blank=True
)
# Generic relations
contacts = GenericRelation(
@@ -62,7 +40,7 @@ class Provider(NetBoxModel):
)
clone_fields = (
'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact',
'account',
)
class Meta:
@@ -75,7 +53,7 @@ class Provider(NetBoxModel):
return reverse('circuits:provider', args=[self.pk])
class ProviderNetwork(NetBoxModel):
class ProviderNetwork(PrimaryModel):
"""
This represents a provider network which exists outside of NetBox, the details of which are unknown or
unimportant to the user.
@@ -93,23 +71,15 @@ class ProviderNetwork(NetBoxModel):
blank=True,
verbose_name='Service ID'
)
description = models.CharField(
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
)
class Meta:
ordering = ('provider', 'name')
constraints = (
models.UniqueConstraint(
fields=('provider', 'name'),
name='circuits_providernetwork_provider_name'
name='%(app_label)s_%(class)s_unique_provider_name'
),
)
unique_together = ('provider', 'name')
def __str__(self):
return self.name

56
netbox/circuits/search.py Normal file
View File

@@ -0,0 +1,56 @@
from netbox.search import SearchIndex, register_search
from . import models
@register_search
class CircuitIndex(SearchIndex):
model = models.Circuit
fields = (
('cid', 100),
('description', 500),
('comments', 5000),
)
@register_search
class CircuitTerminationIndex(SearchIndex):
model = models.CircuitTermination
fields = (
('xconnect_id', 300),
('pp_info', 300),
('description', 500),
('port_speed', 2000),
('upstream_speed', 2000),
)
@register_search
class CircuitTypeIndex(SearchIndex):
model = models.CircuitType
fields = (
('name', 100),
('slug', 110),
('description', 500),
)
@register_search
class ProviderIndex(SearchIndex):
model = models.Provider
fields = (
('name', 100),
('account', 200),
('description', 500),
('comments', 5000),
)
@register_search
class ProviderNetworkIndex(SearchIndex):
model = models.ProviderNetwork
fields = (
('name', 100),
('service_id', 200),
('description', 500),
('comments', 5000),
)

View File

@@ -1,8 +1,9 @@
import django_tables2 as tables
from circuits.models import *
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin
from .columns import CommitRateColumn
__all__ = (
@@ -39,7 +40,7 @@ class CircuitTypeTable(NetBoxTable):
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
class CircuitTable(TenancyColumnsMixin, NetBoxTable):
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
cid = tables.Column(
linkify=True,
verbose_name='Circuit ID'
@@ -58,9 +59,6 @@ class CircuitTable(TenancyColumnsMixin, NetBoxTable):
)
commit_rate = CommitRateColumn()
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='circuits:circuit_list'
)

View File

@@ -1,7 +1,8 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from circuits.models import *
from django_tables2.utils import Accessor
from tenancy.tables import ContactsColumnMixin
from netbox.tables import NetBoxTable, columns
__all__ = (
@@ -10,7 +11,7 @@ __all__ = (
)
class ProviderTable(NetBoxTable):
class ProviderTable(ContactsColumnMixin, NetBoxTable):
name = tables.Column(
linkify=True
)
@@ -31,9 +32,6 @@ class ProviderTable(NetBoxTable):
verbose_name='Circuits'
)
comments = columns.MarkdownColumn()
contacts = columns.ManyToManyColumn(
linkify_item=True
)
tags = columns.TagColumn(
url_name='circuits:provider_list'
)
@@ -41,10 +39,10 @@ class ProviderTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = Provider
fields = (
'pk', 'id', 'name', 'asn', 'asns', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'asn_count',
'circuit_count', 'comments', 'contacts', 'tags', 'created', 'last_updated',
'pk', 'id', 'name', 'asns', 'account', 'asn_count', 'circuit_count', 'description', 'comments', 'contacts',
'tags', 'created', 'last_updated',
)
default_columns = ('pk', 'name', 'asn', 'account', 'circuit_count')
default_columns = ('pk', 'name', 'account', 'circuit_count')
class ProviderNetworkTable(NetBoxTable):

View File

@@ -20,7 +20,7 @@ class ProviderTest(APIViewTestCases.APIViewTestCase):
model = Provider
brief_fields = ['circuit_count', 'display', 'id', 'name', 'slug', 'url']
bulk_update_data = {
'asn': 1234,
'account': '1234',
}
@classmethod

View File

@@ -25,11 +25,11 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
ASN.objects.bulk_create(asns)
providers = (
Provider(name='Provider 1', slug='provider-1', asn=65001, account='1234'),
Provider(name='Provider 2', slug='provider-2', asn=65002, account='2345'),
Provider(name='Provider 3', slug='provider-3', asn=65003, account='3456'),
Provider(name='Provider 4', slug='provider-4', asn=65004, account='4567'),
Provider(name='Provider 5', slug='provider-5', asn=65005, account='5678'),
Provider(name='Provider 1', slug='provider-1', account='1234'),
Provider(name='Provider 2', slug='provider-2', account='2345'),
Provider(name='Provider 3', slug='provider-3', account='3456'),
Provider(name='Provider 4', slug='provider-4', account='4567'),
Provider(name='Provider 5', slug='provider-5', account='5678'),
)
Provider.objects.bulk_create(providers)
providers[0].asns.set([asns[0]])
@@ -82,10 +82,6 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'slug': ['provider-1', 'provider-2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_asn(self): # Legacy field
params = {'asn': ['65001', '65002']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_asn_id(self): # ASN object assignment
asns = ASN.objects.all()[:2]
params = {'asn_id': [asns[0].pk, asns[1].pk]}

View File

@@ -23,9 +23,9 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
ASN.objects.bulk_create(asns)
providers = (
Provider(name='Provider 1', slug='provider-1', asn=65001),
Provider(name='Provider 2', slug='provider-2', asn=65002),
Provider(name='Provider 3', slug='provider-3', asn=65003),
Provider(name='Provider 1', slug='provider-1'),
Provider(name='Provider 2', slug='provider-2'),
Provider(name='Provider 3', slug='provider-3'),
)
Provider.objects.bulk_create(providers)
providers[0].asns.set([asns[0], asns[1]])
@@ -37,12 +37,8 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
cls.form_data = {
'name': 'Provider X',
'slug': 'provider-x',
'asn': 65123,
'asns': [asns[6].pk, asns[7].pk],
'account': '1234',
'portal_url': 'http://example.com/portal',
'noc_contact': 'noc@example.com',
'admin_contact': 'admin@example.com',
'comments': 'Another provider',
'tags': [t.pk for t in tags],
}
@@ -54,12 +50,15 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
"Provider 6,provider-6",
)
cls.csv_update_data = (
"id,name,comments",
f"{providers[0].pk},Provider 7,New comment7",
f"{providers[1].pk},Provider 8,New comment8",
f"{providers[2].pk},Provider 9,New comment9",
)
cls.bulk_edit_data = {
'asn': 65009,
'account': '5678',
'portal_url': 'http://example.com/portal2',
'noc_contact': 'noc2@example.com',
'admin_contact': 'admin2@example.com',
'comments': 'New comments',
}
@@ -70,11 +69,13 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
@classmethod
def setUpTestData(cls):
CircuitType.objects.bulk_create([
circuit_types = (
CircuitType(name='Circuit Type 1', slug='circuit-type-1'),
CircuitType(name='Circuit Type 2', slug='circuit-type-2'),
CircuitType(name='Circuit Type 3', slug='circuit-type-3'),
])
)
CircuitType.objects.bulk_create(circuit_types)
tags = create_tags('Alpha', 'Bravo', 'Charlie')
@@ -92,6 +93,13 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
"Circuit Type 6,circuit-type-6",
)
cls.csv_update_data = (
"id,name,description",
f"{circuit_types[0].pk},Circuit Type 7,New description7",
f"{circuit_types[1].pk},Circuit Type 8,New description8",
f"{circuit_types[2].pk},Circuit Type 9,New description9",
)
cls.bulk_edit_data = {
'description': 'Foo',
}
@@ -100,12 +108,19 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Circuit
def setUp(self):
super().setUp()
self.add_permissions(
'circuits.add_circuittermination',
)
@classmethod
def setUpTestData(cls):
providers = (
Provider(name='Provider 1', slug='provider-1', asn=65001),
Provider(name='Provider 2', slug='provider-2', asn=65002),
Provider(name='Provider 1', slug='provider-1'),
Provider(name='Provider 2', slug='provider-2'),
)
Provider.objects.bulk_create(providers)
@@ -115,11 +130,13 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
)
CircuitType.objects.bulk_create(circuittypes)
Circuit.objects.bulk_create([
circuits = (
Circuit(cid='Circuit 1', provider=providers[0], type=circuittypes[0]),
Circuit(cid='Circuit 2', provider=providers[0], type=circuittypes[0]),
Circuit(cid='Circuit 3', provider=providers[0], type=circuittypes[0]),
])
)
Circuit.objects.bulk_create(circuits)
tags = create_tags('Alpha', 'Bravo', 'Charlie')
@@ -144,6 +161,13 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
"Circuit 6,Provider 1,Circuit Type 1,active",
)
cls.csv_update_data = (
f"id,cid,description,status",
f"{circuits[0].pk},Circuit 7,New description7,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
f"{circuits[1].pk},Circuit 8,New description8,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
f"{circuits[2].pk},Circuit 9,New description9,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
)
cls.bulk_edit_data = {
'provider': providers[1].pk,
'type': circuittypes[1].pk,
@@ -167,11 +191,13 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
)
Provider.objects.bulk_create(providers)
ProviderNetwork.objects.bulk_create([
provider_networks = (
ProviderNetwork(name='Provider Network 1', provider=providers[0]),
ProviderNetwork(name='Provider Network 2', provider=providers[0]),
ProviderNetwork(name='Provider Network 3', provider=providers[0]),
])
)
ProviderNetwork.objects.bulk_create(provider_networks)
tags = create_tags('Alpha', 'Bravo', 'Charlie')
@@ -190,6 +216,13 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
"Provider Network 6,Provider 1,Baz",
)
cls.csv_update_data = (
"id,name,description",
f"{provider_networks[0].pk},Provider Network 7,New description7",
f"{provider_networks[1].pk},Provider Network 8,New description8",
f"{provider_networks[2].pk},Provider Network 9,New description9",
)
cls.bulk_edit_data = {
'provider': providers[1].pk,
'description': 'New description',

View File

@@ -1,9 +1,7 @@
from django.urls import path
from django.urls import include, path
from dcim.views import PathTraceView
from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
from utilities.urls import get_model_urls
from . import views
from .models import *
app_name = 'circuits'
urlpatterns = [
@@ -14,11 +12,7 @@ urlpatterns = [
path('providers/import/', views.ProviderBulkImportView.as_view(), name='provider_import'),
path('providers/edit/', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
path('providers/<int:pk>/', views.ProviderView.as_view(), name='provider'),
path('providers/<int:pk>/edit/', views.ProviderEditView.as_view(), name='provider_edit'),
path('providers/<int:pk>/delete/', views.ProviderDeleteView.as_view(), name='provider_delete'),
path('providers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
path('providers/<int:pk>/journal/', ObjectJournalView.as_view(), name='provider_journal', kwargs={'model': Provider}),
path('providers/<int:pk>/', include(get_model_urls('circuits', 'provider'))),
# Provider networks
path('provider-networks/', views.ProviderNetworkListView.as_view(), name='providernetwork_list'),
@@ -26,11 +20,7 @@ urlpatterns = [
path('provider-networks/import/', views.ProviderNetworkBulkImportView.as_view(), name='providernetwork_import'),
path('provider-networks/edit/', views.ProviderNetworkBulkEditView.as_view(), name='providernetwork_bulk_edit'),
path('provider-networks/delete/', views.ProviderNetworkBulkDeleteView.as_view(), name='providernetwork_bulk_delete'),
path('provider-networks/<int:pk>/', views.ProviderNetworkView.as_view(), name='providernetwork'),
path('provider-networks/<int:pk>/edit/', views.ProviderNetworkEditView.as_view(), name='providernetwork_edit'),
path('provider-networks/<int:pk>/delete/', views.ProviderNetworkDeleteView.as_view(), name='providernetwork_delete'),
path('provider-networks/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providernetwork_changelog', kwargs={'model': ProviderNetwork}),
path('provider-networks/<int:pk>/journal/', ObjectJournalView.as_view(), name='providernetwork_journal', kwargs={'model': ProviderNetwork}),
path('provider-networks/<int:pk>/', include(get_model_urls('circuits', 'providernetwork'))),
# Circuit types
path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'),
@@ -38,10 +28,7 @@ urlpatterns = [
path('circuit-types/import/', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
path('circuit-types/edit/', views.CircuitTypeBulkEditView.as_view(), name='circuittype_bulk_edit'),
path('circuit-types/delete/', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
path('circuit-types/<int:pk>/', views.CircuitTypeView.as_view(), name='circuittype'),
path('circuit-types/<int:pk>/edit/', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
path('circuit-types/<int:pk>/delete/', views.CircuitTypeDeleteView.as_view(), name='circuittype_delete'),
path('circuit-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
path('circuit-types/<int:pk>/', include(get_model_urls('circuits', 'circuittype'))),
# Circuits
path('circuits/', views.CircuitListView.as_view(), name='circuit_list'),
@@ -49,17 +36,11 @@ urlpatterns = [
path('circuits/import/', views.CircuitBulkImportView.as_view(), name='circuit_import'),
path('circuits/edit/', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
path('circuits/delete/', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
path('circuits/<int:pk>/', views.CircuitView.as_view(), name='circuit'),
path('circuits/<int:pk>/edit/', views.CircuitEditView.as_view(), name='circuit_edit'),
path('circuits/<int:pk>/delete/', views.CircuitDeleteView.as_view(), name='circuit_delete'),
path('circuits/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}),
path('circuits/<int:pk>/journal/', ObjectJournalView.as_view(), name='circuit_journal', kwargs={'model': Circuit}),
path('circuits/<int:pk>/terminations/swap/', views.CircuitSwapTerminations.as_view(), name='circuit_terminations_swap'),
path('circuits/<int:pk>/', include(get_model_urls('circuits', 'circuit'))),
# Circuit terminations
path('circuit-terminations/add/', views.CircuitTerminationEditView.as_view(), name='circuittermination_add'),
path('circuit-terminations/<int:pk>/edit/', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
path('circuit-terminations/<int:pk>/delete/', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
path('circuit-terminations/<int:pk>/trace/', PathTraceView.as_view(), name='circuittermination_trace', kwargs={'model': CircuitTermination}),
path('circuit-terminations/<int:pk>/', include(get_model_urls('circuits', 'circuittermination'))),
]

View File

@@ -3,9 +3,11 @@ from django.db import transaction
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
from dcim.views import PathTraceView
from netbox.views import generic
from utilities.forms import ConfirmationForm
from utilities.utils import count_related
from utilities.views import register_model_view
from . import filtersets, forms, tables
from .models import *
@@ -23,6 +25,7 @@ class ProviderListView(generic.ObjectListView):
table = tables.ProviderTable
@register_model_view(Provider)
class ProviderView(generic.ObjectView):
queryset = Provider.objects.all()
@@ -41,18 +44,20 @@ class ProviderView(generic.ObjectView):
}
@register_model_view(Provider, 'edit')
class ProviderEditView(generic.ObjectEditView):
queryset = Provider.objects.all()
form = forms.ProviderForm
@register_model_view(Provider, 'delete')
class ProviderDeleteView(generic.ObjectDeleteView):
queryset = Provider.objects.all()
class ProviderBulkImportView(generic.BulkImportView):
queryset = Provider.objects.all()
model_form = forms.ProviderCSVForm
model_form = forms.ProviderImportForm
table = tables.ProviderTable
@@ -84,6 +89,7 @@ class ProviderNetworkListView(generic.ObjectListView):
table = tables.ProviderNetworkTable
@register_model_view(ProviderNetwork)
class ProviderNetworkView(generic.ObjectView):
queryset = ProviderNetwork.objects.all()
@@ -103,18 +109,20 @@ class ProviderNetworkView(generic.ObjectView):
}
@register_model_view(ProviderNetwork, 'edit')
class ProviderNetworkEditView(generic.ObjectEditView):
queryset = ProviderNetwork.objects.all()
form = forms.ProviderNetworkForm
@register_model_view(ProviderNetwork, 'delete')
class ProviderNetworkDeleteView(generic.ObjectDeleteView):
queryset = ProviderNetwork.objects.all()
class ProviderNetworkBulkImportView(generic.BulkImportView):
queryset = ProviderNetwork.objects.all()
model_form = forms.ProviderNetworkCSVForm
model_form = forms.ProviderNetworkImportForm
table = tables.ProviderNetworkTable
@@ -144,6 +152,7 @@ class CircuitTypeListView(generic.ObjectListView):
table = tables.CircuitTypeTable
@register_model_view(CircuitType)
class CircuitTypeView(generic.ObjectView):
queryset = CircuitType.objects.all()
@@ -157,18 +166,20 @@ class CircuitTypeView(generic.ObjectView):
}
@register_model_view(CircuitType, 'edit')
class CircuitTypeEditView(generic.ObjectEditView):
queryset = CircuitType.objects.all()
form = forms.CircuitTypeForm
@register_model_view(CircuitType, 'delete')
class CircuitTypeDeleteView(generic.ObjectDeleteView):
queryset = CircuitType.objects.all()
class CircuitTypeBulkImportView(generic.BulkImportView):
queryset = CircuitType.objects.all()
model_form = forms.CircuitTypeCSVForm
model_form = forms.CircuitTypeImportForm
table = tables.CircuitTypeTable
@@ -202,23 +213,36 @@ class CircuitListView(generic.ObjectListView):
table = tables.CircuitTable
@register_model_view(Circuit)
class CircuitView(generic.ObjectView):
queryset = Circuit.objects.all()
@register_model_view(Circuit, 'edit')
class CircuitEditView(generic.ObjectEditView):
queryset = Circuit.objects.all()
form = forms.CircuitForm
@register_model_view(Circuit, 'delete')
class CircuitDeleteView(generic.ObjectDeleteView):
queryset = Circuit.objects.all()
class CircuitBulkImportView(generic.BulkImportView):
queryset = Circuit.objects.all()
model_form = forms.CircuitCSVForm
model_form = forms.CircuitImportForm
table = tables.CircuitTable
additional_permissions = [
'circuits.add_circuittermination',
]
related_object_forms = {
'terminations': forms.CircuitTerminationImportForm,
}
def prep_related_object_data(self, parent, data):
data.update({'circuit': parent})
return data
class CircuitBulkEditView(generic.BulkEditView):
@@ -318,11 +342,17 @@ class CircuitSwapTerminations(generic.ObjectEditView):
# Circuit terminations
#
@register_model_view(CircuitTermination, 'edit')
class CircuitTerminationEditView(generic.ObjectEditView):
queryset = CircuitTermination.objects.all()
form = forms.CircuitTerminationForm
template_name = 'circuits/circuittermination_edit.html'
@register_model_view(CircuitTermination, 'delete')
class CircuitTerminationDeleteView(generic.ObjectDeleteView):
queryset = CircuitTermination.objects.all()
# Trace view
register_model_view(CircuitTermination, 'trace', kwargs={'model': CircuitTermination})(PathTraceView)

View File

@@ -45,6 +45,7 @@ __all__ = [
'NestedSiteSerializer',
'NestedSiteGroupSerializer',
'NestedVirtualChassisSerializer',
'NestedVirtualDeviceContextSerializer',
]
@@ -466,3 +467,12 @@ class NestedPowerFeedSerializer(WritableNestedSerializer):
class Meta:
model = models.PowerFeed
fields = ['id', 'url', 'display', 'name', 'cable', '_occupied']
class NestedVirtualDeviceContextSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
device = NestedDeviceSerializer()
class Meta:
model = models.VirtualDeviceContext
fields = ['id', 'url', 'display', 'name', 'identifier', 'device']

View File

@@ -1,6 +1,7 @@
import decimal
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _
from drf_yasg.utils import swagger_serializer_method
from rest_framework import serializers
from timezone_field.rest_framework import TimeZoneSerializerField
@@ -130,7 +131,7 @@ class SiteSerializer(NetBoxModelSerializer):
region = NestedRegionSerializer(required=False, allow_null=True)
group = NestedSiteGroupSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
time_zone = TimeZoneSerializerField(required=False)
time_zone = TimeZoneSerializerField(required=False, allow_null=True)
asns = SerializedPKRelatedField(
queryset=ASN.objects.all(),
serializer=NestedASNSerializer,
@@ -197,10 +198,11 @@ class RackSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=RackStatusChoices, required=False)
role = NestedRackRoleSerializer(required=False, allow_null=True)
type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False)
facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label='Facility ID',
facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label=_('Facility ID'),
default=None)
width = ChoiceField(choices=RackWidthChoices, required=False)
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
device_count = serializers.IntegerField(read_only=True)
powerfeed_count = serializers.IntegerField(read_only=True)
@@ -208,8 +210,9 @@ class RackSerializer(NetBoxModelSerializer):
model = Rack
fields = [
'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
'asset_tag', 'type', 'width', 'u_height', 'weight', 'max_weight', 'weight_unit', 'desc_units',
'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'description', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
]
@@ -241,8 +244,8 @@ class RackReservationSerializer(NetBoxModelSerializer):
class Meta:
model = RackReservation
fields = [
'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description', 'tags',
'custom_fields',
'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description',
'comments', 'tags', 'custom_fields',
]
@@ -309,33 +312,34 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
u_height = serializers.DecimalField(
max_digits=4,
decimal_places=1,
label='Position (U)',
label=_('Position (U)'),
min_value=0,
default=1.0
)
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
device_count = serializers.IntegerField(read_only=True)
class Meta:
model = DeviceType
fields = [
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'subdevice_role', 'airflow', 'front_image', 'rear_image', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'device_count',
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
]
class ModuleTypeSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
manufacturer = NestedManufacturerSerializer()
# module_count = serializers.IntegerField(read_only=True)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
class Meta:
model = ModuleType
fields = [
'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'comments', 'tags', 'custom_fields',
'created', 'last_updated',
'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
]
@@ -633,7 +637,7 @@ class DeviceSerializer(NetBoxModelSerializer):
max_digits=4,
decimal_places=1,
allow_null=True,
label='Position (U)',
label=_('Position (U)'),
min_value=decimal.Decimal(0.5),
default=None
)
@@ -652,8 +656,8 @@ class DeviceSerializer(NetBoxModelSerializer):
fields = [
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
'comments', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
]
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
@@ -668,20 +672,6 @@ class DeviceSerializer(NetBoxModelSerializer):
return data
class ModuleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
device = NestedDeviceSerializer()
module_bay = NestedModuleBaySerializer()
module_type = NestedModuleTypeSerializer()
class Meta:
model = Module
fields = [
'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'comments', 'tags',
'custom_fields', 'created', 'last_updated',
]
class DeviceWithConfigContextSerializer(DeviceSerializer):
config_context = serializers.SerializerMethodField()
@@ -689,8 +679,8 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
fields = [
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated',
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
'comments', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated',
]
@swagger_serializer_method(serializer_or_field=serializers.JSONField)
@@ -698,6 +688,41 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
return obj.get_config_context()
class VirtualDeviceContextSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
device = NestedDeviceSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True, default=None)
primary_ip = NestedIPAddressSerializer(read_only=True)
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
# Related object counts
interface_count = serializers.IntegerField(read_only=True)
class Meta:
model = VirtualDeviceContext
fields = [
'id', 'url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip', 'primary_ip4',
'primary_ip6', 'status', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'interface_count',
]
class ModuleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
device = NestedDeviceSerializer()
module_bay = NestedModuleBaySerializer()
module_type = NestedModuleTypeSerializer()
status = ChoiceField(choices=ModuleStatusChoices, required=False)
class Meta:
model = Module
fields = [
'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag',
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
]
class DeviceNAPALMSerializer(serializers.Serializer):
method = serializers.JSONField()
@@ -820,6 +845,12 @@ class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
device = NestedDeviceSerializer()
vdcs = SerializedPKRelatedField(
queryset=VirtualDeviceContext.objects.all(),
serializer=NestedVirtualDeviceContextSerializer,
required=False,
many=True
)
module = ComponentNestedModuleSerializer(
required=False,
allow_null=True
@@ -856,13 +887,13 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
class Meta:
model = Interface
fields = [
'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag',
'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel',
'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan',
'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers', 'link_peers_type',
'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints', 'connected_endpoints_type',
'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', 'last_updated', 'count_ipaddresses',
'count_fhrp_groups', '_occupied',
'id', 'url', 'display', 'device', 'vdcs', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge',
'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role',
'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers',
'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints',
'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
]
def validate(self, data):
@@ -905,7 +936,7 @@ class FrontPortRearPortSerializer(WritableNestedSerializer):
class Meta:
model = RearPort
fields = ['id', 'url', 'display', 'name', 'label']
fields = ['id', 'url', 'display', 'name', 'label', 'description']
class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
@@ -1016,7 +1047,7 @@ class CableSerializer(NetBoxModelSerializer):
model = Cable
fields = [
'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color',
'length', 'length_unit', 'tags', 'custom_fields', 'created', 'last_updated',
'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
]
@@ -1029,7 +1060,7 @@ class TracedCableSerializer(serializers.ModelSerializer):
class Meta:
model = Cable
fields = [
'id', 'url', 'type', 'status', 'label', 'color', 'length', 'length_unit',
'id', 'url', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'description',
]
@@ -1082,8 +1113,8 @@ class VirtualChassisSerializer(NetBoxModelSerializer):
class Meta:
model = VirtualChassis
fields = [
'id', 'url', 'display', 'name', 'domain', 'master', 'tags', 'custom_fields', 'member_count',
'created', 'last_updated',
'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
'member_count', 'created', 'last_updated',
]
@@ -1104,8 +1135,8 @@ class PowerPanelSerializer(NetBoxModelSerializer):
class Meta:
model = PowerPanel
fields = [
'id', 'url', 'display', 'site', 'location', 'name', 'tags', 'custom_fields', 'powerfeed_count',
'created', 'last_updated',
'id', 'url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'custom_fields',
'powerfeed_count', 'created', 'last_updated',
]
@@ -1138,7 +1169,7 @@ class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
model = PowerFeed
fields = [
'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
'amperage', 'max_utilization', 'comments', 'mark_connected', 'cable', 'cable_end', 'link_peers',
'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable',
'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
]

View File

@@ -37,6 +37,7 @@ router.register('inventory-item-templates', views.InventoryItemTemplateViewSet)
router.register('device-roles', views.DeviceRoleViewSet)
router.register('platforms', views.PlatformViewSet)
router.register('devices', views.DeviceViewSet)
router.register('virtual-device-contexts', views.VirtualDeviceContextViewSet)
router.register('modules', views.ModuleViewSet)
# Device components

View File

@@ -538,6 +538,16 @@ class DeviceViewSet(ConfigContextQuerySetMixin, NetBoxModelViewSet):
return Response(response)
class VirtualDeviceContextViewSet(NetBoxModelViewSet):
queryset = VirtualDeviceContext.objects.prefetch_related(
'device__device_type', 'device', 'tenant', 'tags',
).annotate(
interface_count=count_related(Interface, 'vdcs'),
)
serializer_class = serializers.VirtualDeviceContextSerializer
filterset_class = filtersets.VirtualDeviceContextFilterSet
class ModuleViewSet(NetBoxModelViewSet):
queryset = Module.objects.prefetch_related(
'device', 'module_bay', 'module_type__manufacturer', 'tags',

View File

@@ -8,7 +8,7 @@ class DCIMConfig(AppConfig):
verbose_name = "DCIM"
def ready(self):
import dcim.signals
from . import signals, search
from .models import CableTermination
# Register denormalized fields

View File

@@ -55,14 +55,18 @@ class RackTypeChoices(ChoiceSet):
TYPE_4POST = '4-post-frame'
TYPE_CABINET = '4-post-cabinet'
TYPE_WALLFRAME = 'wall-frame'
TYPE_WALLFRAME_VERTICAL = 'wall-frame-vertical'
TYPE_WALLCABINET = 'wall-cabinet'
TYPE_WALLCABINET_VERTICAL = 'wall-cabinet-vertical'
CHOICES = (
(TYPE_2POST, '2-post frame'),
(TYPE_4POST, '4-post frame'),
(TYPE_CABINET, '4-post cabinet'),
(TYPE_WALLFRAME, 'Wall-mounted frame'),
(TYPE_WALLFRAME_VERTICAL, 'Wall-mounted frame (vertical)'),
(TYPE_WALLCABINET, 'Wall-mounted cabinet'),
(TYPE_WALLCABINET_VERTICAL, 'Wall-mounted cabinet (vertical)'),
)
@@ -194,6 +198,30 @@ class DeviceAirflowChoices(ChoiceSet):
)
#
# Modules
#
class ModuleStatusChoices(ChoiceSet):
key = 'Module.status'
STATUS_OFFLINE = 'offline'
STATUS_ACTIVE = 'active'
STATUS_PLANNED = 'planned'
STATUS_STAGED = 'staged'
STATUS_FAILED = 'failed'
STATUS_DECOMMISSIONING = 'decommissioning'
CHOICES = [
(STATUS_OFFLINE, 'Offline', 'gray'),
(STATUS_ACTIVE, 'Active', 'green'),
(STATUS_PLANNED, 'Planned', 'cyan'),
(STATUS_STAGED, 'Staged', 'blue'),
(STATUS_FAILED, 'Failed', 'red'),
(STATUS_DECOMMISSIONING, 'Decommissioning', 'yellow'),
]
#
# ConsolePorts
#
@@ -757,7 +785,10 @@ class InterfaceTypeChoices(ChoiceSet):
TYPE_LAG = 'lag'
# Ethernet
TYPE_100ME_FX = '100base-fx'
TYPE_100ME_LFX = '100base-lfx'
TYPE_100ME_FIXED = '100base-tx'
TYPE_100ME_T1 = '100base-t1'
TYPE_1GE_FIXED = '1000base-t'
TYPE_1GE_GBIC = '1000base-x-gbic'
TYPE_1GE_SFP = '1000base-x-sfp'
@@ -782,6 +813,19 @@ class InterfaceTypeChoices(ChoiceSet):
TYPE_200GE_QSFP56 = '200gbase-x-qsfp56'
TYPE_400GE_QSFP_DD = '400gbase-x-qsfpdd'
TYPE_400GE_OSFP = '400gbase-x-osfp'
TYPE_800GE_QSFP_DD = '800gbase-x-qsfpdd'
TYPE_800GE_OSFP = '800gbase-x-osfp'
# Ethernet Backplane
TYPE_1GE_KX = '1000base-kx'
TYPE_10GE_KR = '10gbase-kr'
TYPE_10GE_KX4 = '10gbase-kx4'
TYPE_25GE_KR = '25gbase-kr'
TYPE_40GE_KR4 = '40gbase-kr4'
TYPE_50GE_KR = '50gbase-kr'
TYPE_100GE_KP4 = '100gbase-kp4'
TYPE_100GE_KR2 = '100gbase-kr2'
TYPE_100GE_KR4 = '100gbase-kr4'
# Wireless
TYPE_80211A = 'ieee802.11a'
@@ -879,7 +923,10 @@ class InterfaceTypeChoices(ChoiceSet):
(
'Ethernet (fixed)',
(
(TYPE_100ME_FX, '100BASE-FX (10/100ME FIBER)'),
(TYPE_100ME_LFX, '100BASE-LFX (10/100ME FIBER)'),
(TYPE_100ME_FIXED, '100BASE-TX (10/100ME)'),
(TYPE_100ME_T1, '100BASE-T1 (10/100ME Single Pair)'),
(TYPE_1GE_FIXED, '1000BASE-T (1GE)'),
(TYPE_2GE_FIXED, '2.5GBASE-T (2.5GE)'),
(TYPE_5GE_FIXED, '5GBASE-T (5GE)'),
@@ -909,6 +956,22 @@ class InterfaceTypeChoices(ChoiceSet):
(TYPE_200GE_QSFP56, 'QSFP56 (200GE)'),
(TYPE_400GE_QSFP_DD, 'QSFP-DD (400GE)'),
(TYPE_400GE_OSFP, 'OSFP (400GE)'),
(TYPE_800GE_QSFP_DD, 'QSFP-DD (800GE)'),
(TYPE_800GE_OSFP, 'OSFP (800GE)'),
)
),
(
'Ethernet (backplane)',
(
(TYPE_1GE_KX, '1000BASE-KX (1GE)'),
(TYPE_10GE_KR, '10GBASE-KR (10GE)'),
(TYPE_10GE_KX4, '10GBASE-KX4 (10GE)'),
(TYPE_25GE_KR, '25GBASE-KR (25GE)'),
(TYPE_40GE_KR4, '40GBASE-KR4 (40GE)'),
(TYPE_50GE_KR, '50GBASE-KR (50GE)'),
(TYPE_100GE_KP4, '100GBASE-KP4 (100GE)'),
(TYPE_100GE_KR2, '100GBASE-KR2 (100GE)'),
(TYPE_100GE_KR4, '100GBASE-KR4 (100GE)'),
)
),
(
@@ -1314,6 +1377,24 @@ class CableLengthUnitChoices(ChoiceSet):
)
class WeightUnitChoices(ChoiceSet):
# Metric
UNIT_KILOGRAM = 'kg'
UNIT_GRAM = 'g'
# Imperial
UNIT_POUND = 'lb'
UNIT_OUNCE = 'oz'
CHOICES = (
(UNIT_KILOGRAM, 'Kilograms'),
(UNIT_GRAM, 'Grams'),
(UNIT_POUND, 'Pounds'),
(UNIT_OUNCE, 'Ounces'),
)
#
# CableTerminations
#
@@ -1381,3 +1462,20 @@ class PowerFeedPhaseChoices(ChoiceSet):
(PHASE_SINGLE, 'Single phase'),
(PHASE_3PHASE, 'Three-phase'),
)
#
# VDC
#
class VirtualDeviceContextStatusChoices(ChoiceSet):
key = 'VirtualDeviceContext.status'
STATUS_ACTIVE = 'active'
STATUS_PLANNED = 'planned'
STATUS_OFFLINE = 'offline'
CHOICES = [
(STATUS_ACTIVE, 'Active', 'green'),
(STATUS_PLANNED, 'Planned', 'cyan'),
(STATUS_OFFLINE, 'Offline', 'red'),
]

View File

@@ -55,6 +55,8 @@ class MACAddressField(models.Field):
def to_python(self, value):
if value is None:
return value
if type(value) is str:
value = value.replace(' ', '')
try:
return EUI(value, version=48, dialect=mac_unix_expanded_uppercase)
except AddrFormatError:

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
from .models import *
from .model_forms import *
from .filtersets import *
from .object_create import *
from .object_import import *

View File

@@ -1,6 +1,7 @@
from django import forms
from dcim.models import *
from django.utils.translation import gettext as _
from extras.forms import CustomFieldsMixin
from extras.models import Tag
from utilities.forms import BootstrapMixin, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model
@@ -105,9 +106,9 @@ class ModuleBayBulkCreateForm(DeviceBulkAddComponentForm):
field_order = ('name', 'label', 'position_pattern', 'description', 'tags')
replication_fields = ('name', 'label', 'position')
position_pattern = ExpandableNameField(
label='Position',
label=_('Position'),
required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
help_text=_('Alphanumeric ranges are supported. (Must match the number of names being created.)')
)

View File

@@ -1,6 +1,6 @@
from django import forms
from django.utils.translation import gettext as _
from django.contrib.auth.models import User
from django.utils.translation import gettext as _
from timezone_field import TimeZoneFormField
from dcim.choices import *
@@ -54,6 +54,7 @@ __all__ = (
'SiteBulkEditForm',
'SiteGroupBulkEditForm',
'VirtualChassisBulkEditForm',
'VirtualDeviceContextBulkEditForm'
)
@@ -125,24 +126,28 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm):
)
contact_email = forms.EmailField(
required=False,
label='Contact E-mail'
)
description = forms.CharField(
max_length=100,
required=False
label=_('Contact E-mail')
)
time_zone = TimeZoneFormField(
choices=add_blank_choice(TimeZoneFormField().choices),
required=False,
widget=StaticSelect()
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = Site
fieldsets = (
(None, ('status', 'region', 'group', 'tenant', 'asns', 'time_zone', 'description')),
)
nullable_fields = (
'region', 'group', 'tenant', 'asns', 'description', 'time_zone',
'region', 'group', 'tenant', 'asns', 'time_zone', 'description', 'comments',
)
@@ -243,7 +248,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
serial = forms.CharField(
max_length=50,
required=False,
label='Serial Number'
label=_('Serial Number')
)
asset_tag = forms.CharField(
max_length=50,
@@ -261,12 +266,12 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
)
u_height = forms.IntegerField(
required=False,
label='Height (U)'
label=_('Height (U)')
)
desc_units = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label='Descending units'
label=_('Descending units')
)
outer_width = forms.IntegerField(
required=False,
@@ -281,6 +286,28 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
required=False,
widget=StaticSelect()
)
mounting_depth = forms.IntegerField(
required=False,
min_value=1
)
weight = forms.DecimalField(
min_value=0,
required=False
)
max_weight = forms.IntegerField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
@@ -288,12 +315,16 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
model = Rack
fieldsets = (
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag')),
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')),
('Location', ('region', 'site_group', 'site', 'location')),
('Hardware', ('type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit')),
('Hardware', (
'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth',
)),
('Weight', ('weight', 'max_weight', 'weight_unit')),
)
nullable_fields = (
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight',
'max_weight', 'weight_unit', 'description', 'comments',
)
@@ -310,14 +341,19 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
required=False
)
description = forms.CharField(
max_length=100,
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = RackReservation
fieldsets = (
(None, ('user', 'tenant', 'description')),
)
nullable_fields = ('comments',)
class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
@@ -348,19 +384,38 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
is_full_depth = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect(),
label='Is full depth'
label=_('Is full depth')
)
airflow = forms.ChoiceField(
choices=add_blank_choice(DeviceAirflowChoices),
required=False,
widget=StaticSelect()
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = DeviceType
fieldsets = (
(None, ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow')),
('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number', 'airflow')
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments')
class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
@@ -371,12 +426,31 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
part_number = forms.CharField(
required=False
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = ModuleType
fieldsets = (
(None, ('manufacturer', 'part_number')),
('Module Type', ('manufacturer', 'part_number', 'description')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number',)
nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments')
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
@@ -386,7 +460,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
vm_role = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label='VM role'
label=_('VM role')
)
description = forms.CharField(
max_length=200,
@@ -470,17 +544,25 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
serial = forms.CharField(
max_length=50,
required=False,
label='Serial Number'
label=_('Serial Number')
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = Device
fieldsets = (
('Device', ('device_role', 'status', 'tenant', 'platform')),
('Device', ('device_role', 'status', 'tenant', 'platform', 'description')),
('Location', ('site', 'location')),
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
)
nullable_fields = (
'location', 'tenant', 'platform', 'serial', 'airflow',
'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments',
)
@@ -496,17 +578,31 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm):
'manufacturer_id': '$manufacturer'
}
)
status = forms.ChoiceField(
choices=add_blank_choice(ModuleStatusChoices),
required=False,
initial='',
widget=StaticSelect()
)
serial = forms.CharField(
max_length=50,
required=False,
label='Serial Number'
label=_('Serial Number')
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = Module
fieldsets = (
(None, ('manufacturer', 'module_type', 'serial')),
(None, ('manufacturer', 'module_type', 'status', 'serial', 'description')),
)
nullable_fields = ('serial',)
nullable_fields = ('serial', 'description', 'comments')
class CableBulkEditForm(NetBoxModelBulkEditForm):
@@ -543,39 +639,44 @@ class CableBulkEditForm(NetBoxModelBulkEditForm):
initial='',
widget=StaticSelect()
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = Cable
fieldsets = (
(None, ('type', 'status', 'tenant', 'label')),
(None, ('type', 'status', 'tenant', 'label', 'description')),
('Attributes', ('color', 'length', 'length_unit')),
)
nullable_fields = (
'type', 'status', 'tenant', 'label', 'color', 'length',
'type', 'status', 'tenant', 'label', 'color', 'length', 'description', 'comments',
)
def clean(self):
super().clean()
# Validate length/unit
length = self.cleaned_data.get('length')
length_unit = self.cleaned_data.get('length_unit')
if length and not length_unit:
raise forms.ValidationError({
'length_unit': "Must specify a unit when setting length"
})
class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
domain = forms.CharField(
max_length=30,
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = VirtualChassis
fieldsets = (
(None, ('domain',)),
(None, ('domain', 'description')),
)
nullable_fields = ('domain',)
nullable_fields = ('domain', 'description', 'comments')
class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
@@ -608,12 +709,20 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
'site_id': '$site'
}
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
)
model = PowerPanel
fieldsets = (
(None, ('region', 'site_group', 'site', 'location')),
(None, ('region', 'site_group', 'site', 'location', 'description')),
)
nullable_fields = ('location',)
nullable_fields = ('location', 'description', 'comments')
class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
@@ -662,17 +771,21 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
required=False,
widget=BulkEditNullBooleanSelect
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
widget=SmallTextarea,
label='Comments'
label=_('Comments')
)
model = PowerFeed
fieldsets = (
(None, ('power_panel', 'rack', 'status', 'type', 'mark_connected')),
(None, ('power_panel', 'rack', 'status', 'type', 'mark_connected', 'description')),
('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization'))
)
nullable_fields = ('location', 'comments')
nullable_fields = ('location', 'description', 'comments')
#
@@ -735,12 +848,12 @@ class PowerPortTemplateBulkEditForm(BulkEditForm):
maximum_draw = forms.IntegerField(
min_value=1,
required=False,
help_text="Maximum power draw (watts)"
help_text=_("Maximum power draw (watts)")
)
allocated_draw = forms.IntegerField(
min_value=1,
required=False,
help_text="Allocated power draw (watts)"
help_text=_("Allocated power draw (watts)")
)
description = forms.CharField(
required=False
@@ -813,7 +926,7 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
mgmt_only = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label='Management only'
label=_('Management only')
)
description = forms.CharField(
required=False
@@ -823,14 +936,14 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
required=False,
initial='',
widget=StaticSelect(),
label='PoE mode'
label=_('PoE mode')
)
poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices),
required=False,
initial='',
widget=StaticSelect(),
label='PoE type'
label=_('PoE type')
)
nullable_fields = ('label', 'description', 'poe_mode', 'poe_type')
@@ -1071,31 +1184,31 @@ class InterfaceBulkEditForm(
query_params={
'type': 'lag',
},
label='LAG'
label=_('LAG')
)
speed = forms.IntegerField(
required=False,
widget=SelectSpeedWidget(),
label='Speed'
label=_('Speed')
)
mgmt_only = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label='Management only'
label=_('Management only')
)
poe_mode = forms.ChoiceField(
choices=add_blank_choice(InterfacePoEModeChoices),
required=False,
initial='',
widget=StaticSelect(),
label='PoE mode'
label=_('PoE mode')
)
poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices),
required=False,
initial='',
widget=StaticSelect(),
label='PoE type'
label=_('PoE type')
)
mark_connected = forms.NullBooleanField(
required=False,
@@ -1110,7 +1223,7 @@ class InterfaceBulkEditForm(
vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(),
required=False,
label='VLAN group'
label=_('VLAN group')
)
untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(),
@@ -1118,7 +1231,7 @@ class InterfaceBulkEditForm(
query_params={
'group_id': '$vlan_group',
},
label='Untagged VLAN'
label=_('Untagged VLAN')
)
tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(),
@@ -1126,12 +1239,12 @@ class InterfaceBulkEditForm(
query_params={
'group_id': '$vlan_group',
},
label='Tagged VLANs'
label=_('Tagged VLANs')
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
label='VRF'
label=_('VRF')
)
model = Interface
@@ -1218,7 +1331,7 @@ class FrontPortBulkEditForm(
fieldsets = (
(None, ('module', 'type', 'label', 'color', 'description', 'mark_connected')),
)
nullable_fields = ('module', 'label', 'description')
nullable_fields = ('module', 'label', 'description', 'color')
class RearPortBulkEditForm(
@@ -1229,7 +1342,7 @@ class RearPortBulkEditForm(
fieldsets = (
(None, ('module', 'type', 'label', 'color', 'description', 'mark_connected')),
)
nullable_fields = ('module', 'label', 'description')
nullable_fields = ('module', 'label', 'description', 'color')
class ModuleBayBulkEditForm(
@@ -1296,3 +1409,24 @@ class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm):
(None, ('color', 'description')),
)
nullable_fields = ('color', 'description')
class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm):
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
required=False
)
status = forms.ChoiceField(
required=False,
choices=add_blank_choice(VirtualDeviceContextStatusChoices),
widget=StaticSelect()
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
model = VirtualDeviceContext
fieldsets = (
(None, ('device', 'status', 'tenant')),
)
nullable_fields = ('device', 'tenant', )

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,12 @@
from django import forms
from django.utils.translation import gettext as _
from dcim.choices import *
from dcim.constants import *
__all__ = (
'InterfaceCommonForm',
'ModuleCommonForm'
)
@@ -12,13 +14,13 @@ class InterfaceCommonForm(forms.Form):
mac_address = forms.CharField(
empty_value=None,
required=False,
label='MAC address'
label=_('MAC address')
)
mtu = forms.IntegerField(
required=False,
min_value=INTERFACE_MTU_MIN,
max_value=INTERFACE_MTU_MAX,
label='MTU'
label=_('MTU')
)
def clean(self):
@@ -47,3 +49,62 @@ class InterfaceCommonForm(forms.Form):
'tagged_vlans': f"The tagged VLANs ({', '.join(invalid_vlans)}) must belong to the same site as "
f"the interface's parent device/VM, or they must be global"
})
class ModuleCommonForm(forms.Form):
def clean(self):
super().clean()
replicate_components = self.cleaned_data.get('replicate_components')
adopt_components = self.cleaned_data.get('adopt_components')
device = self.cleaned_data.get('device')
module_type = self.cleaned_data.get('module_type')
module_bay = self.cleaned_data.get('module_bay')
if adopt_components:
self.instance._adopt_components = True
# Bail out if we are not installing a new module or if we are not replicating components (or if
# validation has already failed)
if self.errors or self.instance.pk or not replicate_components:
self.instance._disable_replication = True
return
for templates, component_attribute in [
("consoleporttemplates", "consoleports"),
("consoleserverporttemplates", "consoleserverports"),
("interfacetemplates", "interfaces"),
("powerporttemplates", "powerports"),
("poweroutlettemplates", "poweroutlets"),
("rearporttemplates", "rearports"),
("frontporttemplates", "frontports")
]:
# Prefetch installed components
installed_components = {
component.name: component for component in getattr(device, component_attribute).all()
}
# Get the templates for the module type.
for template in getattr(module_type, templates).all():
# Installing modules with placeholders require that the bay has a position value
if MODULE_TOKEN in template.name and not module_bay.position:
raise forms.ValidationError(
"Cannot install module with placeholder values in a module bay with no position defined"
)
resolved_name = template.name.replace(MODULE_TOKEN, module_bay.position)
existing_item = installed_components.get(resolved_name)
# It is not possible to adopt components already belonging to a module
if adopt_components and existing_item and existing_item.module:
raise forms.ValidationError(
f"Cannot adopt {template.component_model.__name__} '{resolved_name}' as it already belongs "
f"to a module"
)
# If we are not adopting components we error if the component exists
if not adopt_components and resolved_name in installed_components:
raise forms.ValidationError(
f"{template.component_model.__name__} - {resolved_name} already exists"
)

Some files were not shown because too many files have changed in this diff Show More