Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cable with multiple connections can't cross module front/rear ports. #11079

Closed
ThomasADavis opened this issue Dec 1, 2022 · 8 comments · Fixed by #13337
Closed

cable with multiple connections can't cross module front/rear ports. #11079

ThomasADavis opened this issue Dec 1, 2022 · 8 comments · Fixed by #13337
Assignees
Labels
severity: medium Results in substantial degraded or broken functionality for specfic workflows status: accepted This issue has been accepted for implementation topic: cabling type: bug A confirmed report of unexpected behavior in the application

Comments

@ThomasADavis
Copy link

ThomasADavis commented Dec 1, 2022

NetBox version

v3.3.9

Python version

3.9

Steps to Reproduce

We use a module fiber cassette system - these are cassettes you plug into 1u rack mount.

Trying to plug a MPO to LC breakout cable can cross these modules - the rear ports a single MPO and the front ports are 6 pairs of LC connectors. So the break out cable we use is a 1 MPO (ie, 100G qsfp) to 4 pair of LC's. This can cross between two modules.

  1. create a device. aka 'sw-test'

  2. add to this device a network interface. any type will do, except lag or virtual.

  3. create a module_type, with no components add.

  4. create a device to use as a patch panel.

  5. in that patch panel, create two module bays, 'C1' and 'C2'.

  6. populate the module bay with the above module type.

  7. for module C1 add rear port of 'MPO-1', positions of 6

  8. for module C2 add rear port of 'MPO-2', positions of 6

  9. for module C1, add front ports of 'LC-[1-6]', type 'LC', attached to rear-port MPO-1:[1-6]

  10. for module C2, add front ports of 'LC-[7-12]', type 'LC', attached to rear-port MPO-2:[1-6]

See attached screen shot for module/cassette/front/rear setup.
Screenshot_2022-12-01_15-02-22

  1. go to the test device you created.

  2. for the on the network interface, tell it you want to make a connection. Choose front port.

for the termination_b, choose LC-6 (associated with MPO-1) and LC-7 (associated with MPO-2)

Screenshot_2022-12-01_15-08-24

Get error message in browser.

Screenshot_2022-12-01_15-08-46

Stack dump from our test netbox instance, doing the same thing:

Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/api/viewsets/__init__.py", line 118, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/mixins.py", line 19, in create
    self.perform_create(serializer)
  File "/opt/netbox/netbox/netbox/api/viewsets/__init__.py", line 157, in perform_create
    instance = serializer.save()
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 212, in save
    self.instance = self.create(validated_data)
  File "/opt/netbox/netbox/netbox/api/serializers/features.py", line 56, in create
    instance = super().create(validated_data)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 962, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/models/query.py", line 514, in create
    obj.save(force_insert=True, using=self.db)
  File "/opt/netbox/netbox/dcim/models/cables.py", line 207, in save
    trace_paths.send(Cable, instance=self, created=_created)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 176, in send
    return [
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/opt/netbox/netbox/dcim/signals.py", line 97, in update_connected_endpoints
    create_cablepath(nodes)
  File "/opt/netbox/netbox/dcim/utils.py", line 43, in create_cablepath
    cp = CablePath.from_origin(terminations)
  File "/opt/netbox/netbox/dcim/models/cables.py", line 543, in from_origin
    assert all(rp.positions == 1 for rp in rear_ports)
AssertionError

Expected Behavior

Can attach a breakout cable across modules/frontports

Observed Behavior

Internal Server Error: /api/dcim/cables/
Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/api/viewsets/__init__.py", line 118, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/mixins.py", line 19, in create
    self.perform_create(serializer)
  File "/opt/netbox/netbox/netbox/api/viewsets/__init__.py", line 157, in perform_create
    instance = serializer.save()
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 212, in save
    self.instance = self.create(validated_data)
  File "/opt/netbox/netbox/netbox/api/serializers/features.py", line 56, in create
    instance = super().create(validated_data)
  File "/opt/netbox/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 962, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/models/query.py", line 514, in create
    obj.save(force_insert=True, using=self.db)
  File "/opt/netbox/netbox/dcim/models/cables.py", line 207, in save
    trace_paths.send(Cable, instance=self, created=_created)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 176, in send
    return [
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/opt/netbox/netbox/dcim/signals.py", line 97, in update_connected_endpoints
    create_cablepath(nodes)
  File "/opt/netbox/netbox/dcim/utils.py", line 43, in create_cablepath
    cp = CablePath.from_origin(terminations)
  File "/opt/netbox/netbox/dcim/models/cables.py", line 543, in from_origin
    assert all(rp.positions == 1 for rp in rear_ports)
AssertionError
@ThomasADavis ThomasADavis added the type: bug A confirmed report of unexpected behavior in the application label Dec 1, 2022
@jeremystretch
Copy link
Member

in demo.netbox.dev, do

Per the bug report template:

Additionally, do not rely on the demo instance for reproducing suspected bugs, as its data is prone to modification or deletion at any time.

Please review your post above to ensure that the reproduction steps are not dependent on any data in the demo instance.

@jeremystretch jeremystretch added the status: revisions needed This issue requires additional information to be actionable label Dec 2, 2022
@armanngu
Copy link

armanngu commented Dec 5, 2022

I think I have the same or a similar bug.

Steps to Reproduce

a) create a device with interfaces
b) create a patch panel with front and back ports connected (1-1,2-2,etc)
c) connect interface to two front ports.
connect-to-front-port

Observed Behavior

Traceback (most recent call last):
File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/opt/netbox/venv/lib/python3.10/site-packages/django/views/generic/base.py", line 84, in view
return self.dispatch(request, *args, **kwargs)
File "/opt/netbox/netbox/dcim/views.py", line 2786, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 303, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/opt/netbox/netbox/utilities/views.py", line 90, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/opt/netbox/venv/lib/python3.10/site-packages/django/views/generic/base.py", line 119, in dispatch
return handler(request, *args, **kwargs)
File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 391, in post
obj = form.save()
File "/opt/netbox/venv/lib/python3.10/site-packages/django/forms/models.py", line 548, in save
self.instance.save()
File "/opt/netbox/netbox/dcim/models/cables.py", line 207, in save
trace_paths.send(Cable, instance=self, created=_created)
File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 176, in send
return [
File "/opt/netbox/venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py", line 177, in
(receiver, receiver(signal=self, sender=sender, **named))
File "/opt/netbox/netbox/dcim/signals.py", line 97, in update_connected_endpoints
create_cablepath(nodes)
File "/opt/netbox/netbox/dcim/utils.py", line 43, in create_cablepath
cp = CablePath.from_origin(terminations)
File "/opt/netbox/netbox/dcim/models/cables.py", line 543, in from_origin
assert all(rp.positions == 1 for rp in rear_ports)

Exception Type: AssertionError at /dcim/cables/add/
Exception Value:

@ThomasADavis
Copy link
Author

I've removed all references to any devices/device_type/module types/modules in demo.netbox.dev.

@jeremystretch jeremystretch added topic: cabling status: accepted This issue has been accepted for implementation and removed status: revisions needed This issue requires additional information to be actionable labels Jan 6, 2023
@jeremystretch jeremystretch self-assigned this Jan 11, 2023
@jeremystretch
Copy link
Member

There are two issues here:

  1. The unhandled exception
  2. Lack of support for the condition that assert statement is checking for

IIRC, this specific condition was not possible to reach prior to the introduction of multi-termination cabling in v3.3, hence the lack of elegant validation, however it obviously did not get updated.

I presume we can resolve the exception itself fairly easily, however supporting traces that split across multiple multi-position rear ports may be difficult. There's also probably some overlap here with #10602; we should consider these in tandem.

@craized
Copy link

craized commented Feb 4, 2023

+1 for supporting this. My use case is different, but I am running into the same AssertError.
Situation is:
Connect a single interface to a MUX with separate TX/RX rear ports.
Breaking cable traces would be sad, but for me allowing the proper modeling of both directions of a span is first priority.

@CADbloke
Copy link

Related discussion: #11158 in summary, modeling Lanes of QSFP-type connections across breakouts and keeping track of the individual data channels.

@mblue-fasttrack
Copy link

Issue only occurs when the cable is attached to an interface. Attaching a cable from front or rear ports to other multiple front ports linked to different, multi-position rear ports does not raise an exception.

@jsenecal jsenecal self-assigned this May 4, 2023
@jeremystretch jeremystretch added the severity: medium Results in substantial degraded or broken functionality for specfic workflows label Jun 23, 2023
@DanSheps
Copy link
Member

DanSheps commented Aug 1, 2023

I am going to try and take this up by simply catching the exception. We can then discuss supported and unsupported topologies in a separate FR.

@DanSheps DanSheps assigned DanSheps and unassigned jsenecal and jeremystretch Aug 1, 2023
jeremystretch added a commit that referenced this issue Sep 26, 2023
…3337)

* Catch AssertionError's in signals.  Handle accordingly

* Alter cable logic to handle certain additional path types.

* Fix failures and add test

* More tests

* Remove not needed tests, add additional tests

* Finish tests, correct some behaviour

* Add check for mid-span device not allowed condition

* Remove excess import

* Remove logging import

* Remove logging import

* Minor tweaks based on Arthur's feedback

* Update netbox/dcim/tests/test_cablepaths.py

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

* Update netbox/dcim/models/cables.py

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

* Changes to account for required SVG rendering changes and based on feedback

* More tweaks for cable path checking

* Improve handling of links with multi-terminations

* Improved SVG rendering of multiple rear ports (with positions) per path trace.  Include asymmetric path detection

* Include missing assert to ensure links are same type.

* Clean up tests

* Remove unused objects from tests

* Changes requested to tests and update comments/doctstrings

* Fix parent reference

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
severity: medium Results in substantial degraded or broken functionality for specfic workflows status: accepted This issue has been accepted for implementation topic: cabling type: bug A confirmed report of unexpected behavior in the application
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants