From 04c0caa77f2c9a3587444e174b20538efefac0be Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 12:12:02 -0600 Subject: [PATCH] Show toolbar for docker's internal IP address Fixes #1854 --- debug_toolbar/middleware.py | 21 ++++++++++++++++++++- docs/changes.rst | 3 +++ docs/installation.rst | 10 ++++------ tests/test_integration.py | 9 +++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py index b5e5d0827..544d3df53 100644 --- a/debug_toolbar/middleware.py +++ b/debug_toolbar/middleware.py @@ -3,6 +3,7 @@ """ import re +import socket from functools import lru_cache from django.conf import settings @@ -12,6 +13,8 @@ from debug_toolbar.toolbar import DebugToolbar from debug_toolbar.utils import clear_stack_trace_caches +# See https://docs.python.org/3/library/socket.html#socket.gaierror +SOCKET_SERV_NAME_NOT_KNOWN = 8 _HTML_TYPES = ("text/html", "application/xhtml+xml") @@ -19,7 +22,23 @@ def show_toolbar(request): """ Default function to determine whether to show the toolbar on a given page. """ - return settings.DEBUG and request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS + internal_ips = settings.INTERNAL_IPS.copy() + + try: + # This is a hack for docker installations. It attempts to look + # up the IP address of the docker host. + # This is not guaranteed to work. + docker_ip = ( + # Convert the last segment of the IP address to be .1 + ".".join(socket.gethostbyname("host.docker.internal").rsplit(".")[:-1]) + + ".1" + ) + internal_ips.append(docker_ip) + except socket.gaierror as err: + # It's fine if the lookup errored since they may not be using docker + if err.errno != SOCKET_SERV_NAME_NOT_KNOWN: + raise + return settings.DEBUG and request.META.get("REMOTE_ADDR") in internal_ips @lru_cache(maxsize=None) diff --git a/docs/changes.rst b/docs/changes.rst index e2a610991..3caa35419 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -4,6 +4,9 @@ Change log Pending ------- +* Automatically support Docker rather than having the developer write a + workaround for ``INTERNAL_IPS``. + 4.3.0 (2024-02-01) ------------------ diff --git a/docs/installation.rst b/docs/installation.rst index a350d9c3a..1f2e1f119 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -145,12 +145,10 @@ option. .. warning:: - If using Docker the following will set your ``INTERNAL_IPS`` correctly in Debug mode:: - - if DEBUG: - import socket # only if you haven't already imported this - hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) - INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + ["127.0.0.1", "10.0.2.2"] + If using Docker, the toolbar will attempt to look up your host name + automatically and treat it as an allowable internal IP. If you're not + able to get the toolbar to work with your docker installation, review + the code in ``debug_toolbar.middleware.show_toolbar``. Troubleshooting --------------- diff --git a/tests/test_integration.py b/tests/test_integration.py index 379fafaf4..4cfc84a78 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -2,6 +2,7 @@ import re import time import unittest +from unittest.mock import patch import html5lib from django.contrib.staticfiles.testing import StaticLiveServerTestCase @@ -66,6 +67,14 @@ def test_show_toolbar_INTERNAL_IPS(self): with self.settings(INTERNAL_IPS=[]): self.assertFalse(show_toolbar(self.request)) + @patch("socket.gethostbyname", return_value="127.0.0.255") + def test_show_toolbar_docker(self, mocked_gethostbyname): + with self.settings(INTERNAL_IPS=[]): + # Is true because REMOTE_ADDR is 127.0.0.1 and the 255 + # is shifted to be 1. + self.assertTrue(show_toolbar(self.request)) + mocked_gethostbyname.assert_called_once_with("host.docker.internal") + def test_should_render_panels_RENDER_PANELS(self): """ The toolbar should force rendering panels on each request