netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/free-netbox-cloud/
http://netboxlabs.com/oss/netbox/
Apache License 2.0
16.27k stars 2.59k forks source link

Partial MAC search leads to exception #4092

Closed xtprox closed 4 years ago

xtprox commented 4 years ago

Environment

Seems that search using MAC address field in Devices section expects full MAC address to be entered, otherwise search leads to exception.

Steps to Reproduce

  1. Create device
  2. Create interface and specify MAC address for it (for example 00:27:E3:3D:CE:B0)
  3. Open Devices section and enter into MAC address search field 00:27:E3:3D:CE
  4. Press Apply

Expected Behavio

All devices that have interfaces that partially/fully matching entered string.

Observed Behavior

Exception raised.

image

Internal Server Error: /dcim/devices/

ValidationError at /dcim/devices/
['Invalid MAC address format: 00:27:E3:3D:CE:']

Request Method: GET
Request URL: https://s-dc1-log01.dtekgroup.tek.loc/dcim/devices/?q=&mac_address=00%3A27%3AE3%3A3D%3ACE%3A&has_primary_ip=&local_context_data=&virtual_chassis_member=&console_ports=&console_server_ports=&power_ports=&power_outlets=&interfaces=&pass_through_ports=&Active+Support=&Software+version=
Django Version: 2.2.10
Python Executable: /usr/bin/python3
Python Version: 3.6.9
Python Path: ['/opt/netbox/netbox', '/opt/netbox-2.7.4', '/usr/local/bin', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages'] Server time: Wed, 5 Feb 2020 15:57:32 +0200 Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'cacheops',
 'corsheaders',
 'debug_toolbar',
 'django_filters',
 'django_rq',
 'django_tables2',
 'django_prometheus',
 'mptt',
 'rest_framework',
 'taggit',
 'taggit_serializer',
 'timezone_field',
 'circuits',
 'dcim',
 'ipam',
 'extras',
 'secrets',
 'tenancy',
 'users',
 'utilities',
 'virtualization',
 'drf_yasg']
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',
 'utilities.middleware.ExceptionHandlingMiddleware',
 'utilities.middleware.LoginRequiredMiddleware',
 'utilities.middleware.APIVersionMiddleware',
 'extras.middleware.ObjectChangeMiddleware',
 'django_prometheus.middleware.PrometheusAfterMiddleware')

Traceback:

File "/usr/local/lib/python3.6/dist-packages/netaddr/eui/__init__.py" in _set_value
  442.                     self._value = self._module.str_to_int(value)

File "/usr/local/lib/python3.6/dist-packages/netaddr/strategy/eui48.py" in str_to_int
  176.             raise AddrFormatError('%r is not a supported MAC format!' % addr)

During handling of the above exception ('00:27:E3:3D:CE:' is not a supported MAC format!), another exception occurred:

File "/opt/netbox/netbox/dcim/fields.py" in to_python
  42.             return EUI(value, version=48, dialect=mac_unix_expanded_uppercase)

File "/usr/local/lib/python3.6/dist-packages/netaddr/eui/__init__.py" in __init__
  387.         self.value = addr

File "/usr/local/lib/python3.6/dist-packages/netaddr/eui/__init__.py" in _set_value
  445.                         % (value, self._module.version))

During handling of the above exception (address '00:27:E3:3D:CE:' is not an EUIv48), another exception occurred:

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/views/generic/base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/contrib/auth/mixins.py" in dispatch
  85.         return super().dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/views/generic/base.py" in dispatch
  97.         return handler(request, *args, **kwargs)

File "/opt/netbox/netbox/utilities/views.py" in get
  119.             self.queryset = self.filterset(request.GET, self.queryset).qs

File "/usr/local/lib/python3.6/dist-packages/django_filters/filterset.py" in qs
  237.                 qs = self.filter_queryset(qs)

File "/usr/local/lib/python3.6/dist-packages/django_filters/filterset.py" in filter_queryset
  224.             queryset = self.filters[name].filter(queryset, value)

File "/usr/local/lib/python3.6/dist-packages/django_filters/filters.py" in filter
  251.             qs = self.get_method(qs)(q)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/query.py" in filter
  892.         return self._filter_or_exclude(False, *args, **kwargs)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/query.py" in _filter_or_exclude
  910.             clone.query.add_q(Q(*args, **kwargs))

File "/usr/local/lib/python3.6/dist-packages/django/db/models/sql/query.py" in add_q
  1290.         clause, _ = self._add_q(q_object, self.used_aliases)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/sql/query.py" in _add_q
  1312.                     current_negated, allow_joins, split_subq, simple_col)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/sql/query.py" in _add_q
  1318.                     split_subq=split_subq, simple_col=simple_col,

File "/usr/local/lib/python3.6/dist-packages/django/db/models/sql/query.py" in build_filter
  1251.         condition = self.build_lookup(lookups, col, value)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/sql/query.py" in build_lookup
  1116.         lookup = lookup_class(lhs, rhs)

File "/usr/local/lib/python3.6/dist-packages/django/db/models/lookups.py" in __init__
  20.         self.rhs = self.get_prep_lookup()

File "/usr/local/lib/python3.6/dist-packages/django/db/models/lookups.py" in get_prep_lookup
  70.             return self.lhs.output_field.get_prep_value(self.rhs)

File "/opt/netbox/netbox/dcim/fields.py" in get_prep_value
  52.         return str(self.to_python(value))

File "/opt/netbox/netbox/dcim/fields.py" in to_python
  44.             raise ValidationError("Invalid MAC address format: {}".format(value))

Exception Type: ValidationError at /dcim/devices/ Exception Value: ['Invalid MAC address format: 00:27:E3:3D:CE:'] Request information:
USER: #####

GET:
q = ''
mac_address = '00:27:E3:3D:CE:'
has_primary_ip = ''
local_context_data = ''
virtual_chassis_member = ''
console_ports = ''
console_server_ports = ''
power_ports = ''
power_outlets = ''
interfaces = ''
pass_through_ports = ''
Active Support = ''
Software version = ''

POST: No POST data

FILES: No FILES data
DanSheps commented 4 years ago

This is not a bug, those fields, with the exception of the search field, only take exact matches.

If you would like a partial match, perhaps raid a feature request regarding that (it would most likely be implemented through the search field, and not a direct mapped field)