Skip to content

Fixes: #15016 - Catch AssertionError from cable trace and throw ValidationError #16384

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

Merged
merged 13 commits into from
Mar 4, 2025

Conversation

DanSheps
Copy link
Member

@DanSheps DanSheps commented Jun 3, 2024

Fixes: #15016 - Catch AssertionError from cable trace and throw ValidationError

  • Catch any assertion errors thrown by the Cable save signal and raise a validation error
  • Catch validation error in ObjectEditView and report error in UI while re-rendering form

@DanSheps DanSheps requested a review from jeremystretch June 3, 2024 03:09
@DanSheps DanSheps self-assigned this Jun 3, 2024
Copy link
Member

@jeremystretch jeremystretch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of assert statements in this logic was primarily for sanity-checking during initial development; they shouldn't be relied upon as true validation checks. (They aren't even run when __debug__ is False.)

If the use case in #15016 is not supported, we need to add specific validation logic to check for and report on it.

@arthanson arthanson requested a review from jeremystretch June 10, 2024 15:42
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Jun 26, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 2, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 17, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 22, 2024
Copy link
Contributor

github-actions bot commented Aug 7, 2024

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Aug 7, 2024
Copy link
Member

@jeremystretch jeremystretch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid this still doesn't address my primary concern: Validation of cable state needs to be performed prior to the point where we're generating cable paths. (Again, the original assertions were just sanity checks.) This should ideally be performed on each model under clean().

Additionally, as a rule generic views should not check for and handle any model-specific exceptions.

@jeremystretch jeremystretch removed the pending closure Requires immediate attention to avoid being closed for inactivity label Aug 16, 2024
@DanSheps
Copy link
Member Author

DanSheps commented Aug 16, 2024

I'm afraid this still doesn't address my primary concern: Validation of cable state needs to be performed prior to the point where we're generating cable paths. (Again, the original assertions were just sanity checks.) This should ideally be performed on each model under clean().

The issue is there isn't really a way to validate the cable state prior to the cable being saved, without effectively duplicating all the work done in the cable path generation.

The main reason for this is because a lot of these assertion checks are dependant on sibling cable state further down the path, not just part of the existing cable save, which isn't known until you generate the full path.

We would effectively be running the from_origin twice in this instance, once to validate the cable state and once to save it.

Take for example this path, where Switch 1, interface1 is what you are connecting (the rest is fully formed):

                     /----[FP1-1]                       [FP2-1]----[FP3-1]                      [FP4-1]---- 
[Switch1][Interface1]             [PP1][RP]----[RP][PP2]                   [PP3][RP]----[RP][PP4]                 
                     \----[FP1-2]                       [FP2-2]----[FP3-2]                      [FP4-2]----

You can validate FP1-1 and FP1-2 because they are connected.

But you can't run any of the peer validations on FP2-1 and FP2-2 because FP2-1 doesn't know that FP2-2 will be part of that same path until Interface1 is connect and that path is fully formed.

I can take another pass at it, and see if I can have it run this in clean() first, but most of the parts of this rely on objects existing in the database already as well, so this would likely need a complete re-write, which I was trying to avoid doing.

Copy link
Contributor

github-actions bot commented Sep 1, 2024

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Sep 1, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Sep 12, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Oct 12, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Oct 15, 2024
@DanSheps
Copy link
Member Author

This is now ready. I stupidly missed an UnsupportedCablePath in the test instead of AbortRequest

Copy link
Contributor

github-actions bot commented Feb 2, 2025

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Feb 2, 2025
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Feb 6, 2025
Copy link
Collaborator

@arthanson arthanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dan, can you please rebase to main

@DanSheps DanSheps changed the base branch from develop to main February 18, 2025 20:36
@DanSheps DanSheps requested review from a team, jnovinger and arthanson and removed request for jeremystretch, a team and jnovinger February 24, 2025 19:40
@arthanson
Copy link
Collaborator

One more @DanSheps when I switch to this branch NetBox won't start with the following error - can you please sync and try:

  File "/Users/ahanson/dev/work/netbox/netbox/netbox/urls.py", line 7, in <module>
    from account.views import LoginView, LogoutView
  File "/Users/ahanson/dev/work/netbox/netbox/account/views.py", line 28, in <module>
    from netbox.views import generic
  File "/Users/ahanson/dev/work/netbox/netbox/netbox/views/generic/__init__.py", line 2, in <module>
    from .feature_views import *
  File "/Users/ahanson/dev/work/netbox/netbox/netbox/views/generic/feature_views.py", line 12, in <module>
    from extras.forms import JournalEntryForm
  File "/Users/ahanson/dev/work/netbox/netbox/extras/forms/__init__.py", line 4, in <module>
    from .bulk_import import *
  File "/Users/ahanson/dev/work/netbox/netbox/extras/forms/bulk_import.py", line 184, in <module>
    class EventRuleImportForm(NetBoxModelImportForm):
  File "/Users/ahanson/dev/work/netbox/venv/lib/python3.12/site-packages/django/forms/models.py", line 312, in __new__
    fields = fields_for_model(
             ^^^^^^^^^^^^^^^^^
  File "/Users/ahanson/dev/work/netbox/venv/lib/python3.12/site-packages/django/forms/models.py", line 207, in fields_for_model
    raise FieldError(
django.core.exceptions.FieldError: 'action_object' cannot be specified for EventRule model form as it is a non-editable field

…o 15016-fix-assertionerror-when-saving-cable
@DanSheps
Copy link
Member Author

Merged in main. Started clean for me either way but hopefully this corrects whatever you are hitting.

Copy link
Collaborator

@arthanson arthanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dcim.model.cables.CablePath.from_origin() is called from dcim.utils.create_cablepath which is called from wireless.signals.update_connected_interfaces in a post_save handler. This would be an issue as it could raise an error post_save so it would already be saved in this incorrect state.

I agree with Jeremy's prior comment that I think we need to validate it before save. Seems like we would want to create the connection graph in memory and then validate that... which sounds like a big pain.

@DanSheps
Copy link
Member Author

I agree with Jeremy's prior comment that I think we need to validate it before save. Seems like we would want to create the connection graph in memory and then validate that... which sounds like a big pain.

Short of re-writing the whole thing, I don't know if we can write it in-memory as-is due to some of the queries that are run against it.

The signals will all fire inside of a transaction which should be rolled back automatically if there is an error. I don't think there is a data consistency concern here, it would be treated the same as if the exception is raise directly in save (the transaction would roll back and you would be presented with the form again).

@arthanson
Copy link
Collaborator

arthanson commented Feb 25, 2025

You are right on the transaction prevent save, but the raised error won't be caught in this case - to make it easy to test I just put into wireless.signals to force the raise:

@receiver(post_save, sender=WirelessLink)
def update_connected_interfaces(instance, created, raw=False, **kwargs):
    """
    When a WirelessLink is saved, save a reference to it on each connected interface.
    """
    from dcim.exceptions import UnsupportedCablePath
    raise UnsupportedCablePath("All mid-span terminations must have the same parent object")

Then created a wireless link, resulting in
image

So it's about the same as the assert in this specific case (i.e. no nice validation message popup). Not sure if that is a separate issue.

@DanSheps
Copy link
Member Author

I think catching that is a separate issue and I think we can wrap that in this PR as it is similar.

Let me go add that and see if I can adjust to catch that as well.

@arthanson
Copy link
Collaborator

also, do you have an easier repro scenario for the original cable error?

@DanSheps
Copy link
Member Author

also, do you have an easier repro scenario for the original cable error?

Unfortunately no

@DanSheps DanSheps requested a review from arthanson February 27, 2025 16:03
@arthanson arthanson dismissed jeremystretch’s stale review March 4, 2025 18:57

From message " it's been too long since I looked at it. If you're comfortable dismissing the old review, it's fine with me"

@arthanson arthanson merged commit 4ab58f2 into main Mar 4, 2025
6 checks passed
bctiemann pushed a commit that referenced this pull request Mar 6, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error when adding new connection to front port.
4 participants