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

Crash when moving rack to a new site with identical device sharing a common tenant #3524

Closed
matt852 opened this issue Mar 31, 2023 · 4 comments · Fixed by #4025
Closed

Crash when moving rack to a new site with identical device sharing a common tenant #3524

matt852 opened this issue Mar 31, 2023 · 4 comments · Fixed by #4025
Assignees
Labels
type: bug Something isn't working as expected

Comments

@matt852
Copy link
Contributor

matt852 commented Mar 31, 2023

Environment

  • Nautobot version (Docker tag too if applicable): 1.5.15b1
  • Python version: 3.8
  • Database platform, version: PostGreSQL
  • Middleware(s): Docker

Steps to Reproduce

  1. Create 2 sites: site1 and site2
  2. Create 2 racks: rack 1 in site1, and rack 2 in site2
  3. Create 1 tenant: tenant1
  4. Create 1 device with the following parameters (all others are irrelevant):
    1. Site: - site1
    2. Name - example
    3. Rack - 1
    4. Tenant - tenant1
  5. Create 1 device with the following parameters (name and tenant are identical):
    1. Site: - site2
    2. Name - example
    3. Rack - 2
    4. Tenant - tenant1
  6. Attempt to move rack 2 from site2 to site1 by editing it and changing the Site variable

Expected Behavior

Rack 2 to move to site1 and automatically assign any devices in it to site1 as well, like it normally does.

Observed Behavior

Nautobot crashed with an IntegrityError. I believe this is because Nautobot does not allow a Device to have the same name and the same Tenant in the same Site.

I would like to see either:

  1. Preferably have the Edit action fail with a prompt to the user stating the reason, or
  2. Have the error handled a little more gracefully with better error reporting to the end user

Should handle the RackGroup edit as well, which will recurse through the Rack

Traceback

Screenshot 2023-03-31 at 3 57 27 PM

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8080/dcim/racks/a54b87c8-5c82-4489-b1ed-3fd826343eb0/edit/

Django Version: 3.2.18
Python Version: 3.8.16
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'cacheops',
 'corsheaders',
 'django_filters',
 'django_jinja',
 'django_tables2',
 'django_prometheus',
 'mptt',
 'social_django',
 'taggit',
 'timezone_field',
 'nautobot.core.apps.NautobotConstanceConfig',
 'nautobot.core',
 'django.contrib.admin',
 'django_celery_beat',
 'rest_framework',
 'db_file_storage',
 'nautobot.circuits',
 'nautobot.dcim',
 'nautobot.ipam',
 'nautobot.extras',
 'nautobot.tenancy',
 'nautobot.users',
 'nautobot.utilities',
 'nautobot.virtualization',
 'django_rq',
 'drf_spectacular',
 'drf_spectacular_sidecar',
 'graphene_django',
 'health_check',
 'health_check.storage',
 'django_extensions',
 'constance.backends.database',
 'django_ajax_tables',
 'debug_toolbar',
 'acme.AcmeConfig']
Installed Middleware:
['debug_toolbar.middleware.DebugToolbarMiddleware',
 'django_prometheus.middleware.PrometheusBeforeMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'nautobot.core.middleware.ExceptionHandlingMiddleware',
 'nautobot.core.middleware.RemoteUserMiddleware',
 'nautobot.core.middleware.ExternalAuthMiddleware',
 'nautobot.core.middleware.ObjectChangeMiddleware',
 'django_prometheus.middleware.PrometheusAfterMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.8/site-packages/django_prometheus/db/common.py", line 71, in execute
    return super().execute(*args, **kwargs)

The above exception (duplicate key value violates unique constraint "dcim_device_site_id_tenant_id_name_93f4f962_uniq"
DETAIL:  Key (site_id, tenant_id, name)=(67d80af5-2811-4732-97fa-e0e42d331b66, 355ed849-1c84-4dcc-8f8f-9811ed686f69, example) already exists.
) was the direct cause of the following exception:
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/views/generic.py", line 412, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/utilities/views.py", line 116, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/views/generic.py", line 446, in post
    obj = form.save()
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/forms/mixins.py", line 642, in save
    obj = super().save(commit)
  File "/usr/local/lib/python3.8/site-packages/django/forms/models.py", line 468, in save
    self.instance.save()
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 739, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 787, in save_base
    post_save.send(
  File "/usr/local/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 180, in send
    return [
  File "/usr/local/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/usr/local/lib/python3.8/site-packages/nautobot/dcim/signals.py", line 170, in handle_rack_site_location_change
    device.save()
  File "/usr/local/lib/python3.8/site-packages/nautobot/dcim/models/devices.py", line 818, in save
    super().save(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 739, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 776, in save_base
    updated = self._save_table(
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 858, in _save_table
    updated = self._do_update(base_qs, using, pk_val, values, update_fields,
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 912, in _do_update
    return filtered._update(values) > 0
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 802, in _update
    return query.get_compiler(self.db).execute_sql(CURSOR)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1559, in execute_sql
    cursor = super().execute_sql(result_type)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1175, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.8/site-packages/debug_toolbar/panels/sql/tracking.py", line 230, in execute
    return self._record(self.cursor.execute, sql, params)
  File "/usr/local/lib/python3.8/site-packages/debug_toolbar/panels/sql/tracking.py", line 154, in _record
    return method(sql, params)
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 98, in execute
    return super().execute(sql, params)
  File "/usr/local/lib/python3.8/site-packages/cacheops/transaction.py", line 97, in execute
    result = self._no_monkey.execute(self, sql, params)
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.8/site-packages/django_prometheus/db/common.py", line 71, in execute
    return super().execute(*args, **kwargs)

Exception Type: IntegrityError at /dcim/racks/a54b87c8-5c82-4489-b1ed-3fd826343eb0/edit/
Exception Value: duplicate key value violates unique constraint "dcim_device_site_id_tenant_id_name_93f4f962_uniq"
DETAIL:  Key (site_id, tenant_id, name)=(67d80af5-2811-4732-97fa-e0e42d331b66, 355ed849-1c84-4dcc-8f8f-9811ed686f69, example) already exists.
@bryanculver bryanculver added the type: bug Something isn't working as expected label Apr 3, 2023
@bryanculver
Copy link
Member

Thanks for the report @matt852!

Does it leave the data in a partially corrupted state? I feel like better error handling here would be sufficient but we're looking at improving uniqueness in v2.0 for a potentially more ideal fix.

@bryanculver bryanculver added the question Further information is requested label Apr 3, 2023
@matt852
Copy link
Contributor Author

matt852 commented Apr 3, 2023

No I don't believe any data is corrupted. It just fails to migrate the rack, and the rack and device stay with their existing site assignment.

@bryanculver bryanculver removed the question Further information is requested label Apr 4, 2023
@bryanculver
Copy link
Member

Accepted expected behavior is to catch and throw a user-friendly error message for this.

@gsnider2195
Copy link
Contributor

Probably needs form validation on RackGroup and Rack

@timizuoebideri1 timizuoebideri1 self-assigned this Jun 28, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: bug Something isn't working as expected
Projects
No open projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants