Race condition caused by PR #7803 when clearing modules from the sys.modules cache #6256

Closed
opened 2025-12-29 19:38:35 +01:00 by adam · 1 comment
Owner

Originally created by @kkthxbye-code on GitHub (Mar 24, 2022).

Originally assigned to: @kkthxbye-code on GitHub.

NetBox version

v3.1.9

Python version

3.9

Steps to Reproduce

As race conditions a finicky in nature, I can't really guarantee the reproduction steps.

  1. Create any script and put in the scripts folder.
  2. Create a user
  3. Create an API token for the user
  4. Run the following bash script:
for y in `seq 1 4` ; \
    do (for x in `seq 1 4` ; \
        do curl -H "Authorization: Token YOUR_TOKEN" -H "Accept: application/json" http://127.0.0.1:8000/api/extras/scripts/ -I ; \
    done)& ; \
done

Expected Behavior

No exceptions

Observed Behavior

Internal Server Error: /api/extras/scripts/
Traceback (most recent call last):
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/user/devel/netbox-source/netbox/extras/api/views.py", line 295, in list
    for script_list in get_scripts().values():
  File "/home/user/devel/netbox-source/netbox/extras/scripts.py", line 495, in get_scripts
    module = importer.find_module(module_name).load_module(module_name)
  File "<frozen importlib._bootstrap_external>", line 548, in _check_name_wrapper
  File "<frozen importlib._bootstrap_external>", line 1063, in load_module
  File "<frozen importlib._bootstrap_external>", line 888, in load_module
  File "<frozen importlib._bootstrap>", line 290, in _load_module_shim
  File "<frozen importlib._bootstrap>", line 719, in _load
  File "<frozen importlib._bootstrap>", line 699, in _load_unlocked
KeyError: 'ScriptName'

The reason is that get_scripts first clears the cache and then loads the module:

e09ab79a1a/netbox/extras/scripts.py (L501-L504)

If another thread is in the process of loading the modules while another thread is clearing the cache importlib will fail. (I assume this is the issue).

Not sure how to fix it, other than putting a lock around the cache clearing and loading of the module.

Originally created by @kkthxbye-code on GitHub (Mar 24, 2022). Originally assigned to: @kkthxbye-code on GitHub. ### NetBox version v3.1.9 ### Python version 3.9 ### Steps to Reproduce As race conditions a finicky in nature, I can't really guarantee the reproduction steps. 1. Create any script and put in the scripts folder. 2. Create a user 3. Create an API token for the user 4. Run the following bash script: ``` for y in `seq 1 4` ; \ do (for x in `seq 1 4` ; \ do curl -H "Authorization: Token YOUR_TOKEN" -H "Accept: application/json" http://127.0.0.1:8000/api/extras/scripts/ -I ; \ done)& ; \ done ``` ### Expected Behavior No exceptions ### Observed Behavior ``` Internal Server Error: /api/extras/scripts/ Traceback (most recent call last): File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner response = get_response(request) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 181, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view return self.dispatch(request, *args, **kwargs) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch response = self.handle_exception(exc) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception raise exc File "/home/user/devel/netbox-source/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch response = handler(request, *args, **kwargs) File "/home/user/devel/netbox-source/netbox/extras/api/views.py", line 295, in list for script_list in get_scripts().values(): File "/home/user/devel/netbox-source/netbox/extras/scripts.py", line 495, in get_scripts module = importer.find_module(module_name).load_module(module_name) File "<frozen importlib._bootstrap_external>", line 548, in _check_name_wrapper File "<frozen importlib._bootstrap_external>", line 1063, in load_module File "<frozen importlib._bootstrap_external>", line 888, in load_module File "<frozen importlib._bootstrap>", line 290, in _load_module_shim File "<frozen importlib._bootstrap>", line 719, in _load File "<frozen importlib._bootstrap>", line 699, in _load_unlocked KeyError: 'ScriptName' ``` The reason is that get_scripts first clears the cache and then loads the module: https://github.com/netbox-community/netbox/blob/e09ab79a1ac508779b715f5c7fb00412d1b57308/netbox/extras/scripts.py#L501-L504 If another thread is in the process of loading the modules while another thread is clearing the cache importlib will fail. (I assume this is the issue). Not sure how to fix it, other than putting a lock around the cache clearing and loading of the module.
adam added the type: bugstatus: accepted labels 2025-12-29 19:38:35 +01:00
adam closed this issue 2025-12-29 19:38:36 +01:00
Author
Owner

@kkthxbye-code commented on GitHub (Mar 25, 2022):

The issue is obviously only hit when running a threaded application server. In normal use the issue is very rarely hit and when it is, it mostly just results in a 500 returned for the periodic check for script completion. No error is shown to the user and the script succeeds like normal.

Should be fixed regardless. I hope we can find a solution that allows the functionality to remain, as it was quite annoying to have to restart netbox if you renamed a script class.

@kkthxbye-code commented on GitHub (Mar 25, 2022): The issue is obviously only hit when running a threaded application server. In normal use the issue is very rarely hit and when it is, it mostly just results in a 500 returned for the periodic check for script completion. No error is shown to the user and the script succeeds like normal. Should be fixed regardless. I hope we can find a solution that allows the functionality to remain, as it was quite annoying to have to restart netbox if you renamed a script class.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#6256