Browse Source

lazy-load loadfire and ldap lib for faster startup time

Nick Sweeting 1 year ago
parent
commit
1492c02bfa

+ 7 - 7
archivebox/config/legacy.py

@@ -823,15 +823,15 @@ def setup_django(out_dir: Path | None=None, check_db=False, config: benedict=CON
                 bump_startup_progress_bar()
                 bump_startup_progress_bar()
 
 
                 # https://docs.pydantic.dev/logfire/integrations/django/ Logfire Debugging
                 # https://docs.pydantic.dev/logfire/integrations/django/ Logfire Debugging
-                if settings.DEBUG_LOGFIRE:
-                    from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor
-                    SQLite3Instrumentor().instrument()
+                # if settings.DEBUG_LOGFIRE:
+                #     from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor
+                #     SQLite3Instrumentor().instrument()
 
 
-                    import logfire
+                #     import logfire
 
 
-                    logfire.configure()
-                    logfire.instrument_django(is_sql_commentor_enabled=True)
-                    logfire.info(f'Started ArchiveBox v{CONSTANTS.VERSION}', argv=sys.argv)
+                #     logfire.configure()
+                #     logfire.instrument_django(is_sql_commentor_enabled=True)
+                #     logfire.info(f'Started ArchiveBox v{CONSTANTS.VERSION}', argv=sys.argv)
 
 
         except KeyboardInterrupt:
         except KeyboardInterrupt:
             raise SystemExit(2)
             raise SystemExit(2)

+ 3 - 3
archivebox/core/settings.py

@@ -600,9 +600,9 @@ if DEBUG_REQUESTS_TRACKER:
         ),
         ),
     }
     }
 
 
-# https://docs.pydantic.dev/logfire/integrations/django/ (similar to DataDog / NewRelic / etc.)
-DEBUG_LOGFIRE = False
-DEBUG_LOGFIRE = DEBUG_LOGFIRE and (DATA_DIR / '.logfire').is_dir()
+# # https://docs.pydantic.dev/logfire/integrations/django/ (similar to DataDog / NewRelic / etc.)
+# DEBUG_LOGFIRE = False
+# DEBUG_LOGFIRE = DEBUG_LOGFIRE and (DATA_DIR / '.logfire').is_dir()
 
 
 
 
 # For usage with https://www.jetadmin.io/integrations/django
 # For usage with https://www.jetadmin.io/integrations/django

+ 7 - 5
archivebox/plugins_auth/ldap/apps.py

@@ -13,11 +13,13 @@ from abx.archivebox.base_hook import BaseHook
 from abx.archivebox.base_binary import BaseBinary, BaseBinProvider
 from abx.archivebox.base_binary import BaseBinary, BaseBinProvider
 
 
 from plugins_pkg.pip.apps import SYS_PIP_BINPROVIDER, VENV_PIP_BINPROVIDER
 from plugins_pkg.pip.apps import SYS_PIP_BINPROVIDER, VENV_PIP_BINPROVIDER
-from .settings import LDAP_CONFIG, LDAP_LIB
+from .settings import LDAP_CONFIG, get_ldap_lib
 
 
 
 
 ###################### Config ##########################
 ###################### Config ##########################
 
 
+LDAP_LIB = lambda: get_ldap_lib()[0]
+
 
 
 class LdapBinary(BaseBinary):
 class LdapBinary(BaseBinary):
     name: str = 'ldap'
     name: str = 'ldap'
@@ -26,12 +28,12 @@ class LdapBinary(BaseBinary):
 
 
     provider_overrides: Dict[BinProviderName, ProviderLookupDict] = {
     provider_overrides: Dict[BinProviderName, ProviderLookupDict] = {
         VENV_PIP_BINPROVIDER.name: {
         VENV_PIP_BINPROVIDER.name: {
-            "abspath": lambda: LDAP_LIB and Path(inspect.getfile(LDAP_LIB)),
-            "version": lambda: LDAP_LIB and SemVer(LDAP_LIB.__version__),
+            "abspath": lambda: LDAP_LIB() and Path(inspect.getfile(LDAP_LIB())),
+            "version": lambda: LDAP_LIB() and SemVer(LDAP_LIB().__version__),
         },
         },
         SYS_PIP_BINPROVIDER.name: {
         SYS_PIP_BINPROVIDER.name: {
-            "abspath": lambda: LDAP_LIB and Path(inspect.getfile(LDAP_LIB)),
-            "version": lambda: LDAP_LIB and SemVer(LDAP_LIB.__version__),
+            "abspath": lambda: LDAP_LIB() and Path(inspect.getfile(LDAP_LIB())),
+            "version": lambda: LDAP_LIB() and SemVer(LDAP_LIB().__version__),
         },
         },
     }
     }
 
 

+ 55 - 38
archivebox/plugins_auth/ldap/settings.py

@@ -8,12 +8,19 @@ from pydantic import Field, model_validator, computed_field
 from abx.archivebox.base_configset import BaseConfigSet
 from abx.archivebox.base_configset import BaseConfigSet
 
 
 LDAP_LIB = None
 LDAP_LIB = None
-try:
-    import ldap
-    from django_auth_ldap.config import LDAPSearch
-    LDAP_LIB = ldap
-except ImportError:
-    pass
+LDAP_SEARCH = None
+
+def get_ldap_lib():
+    global LDAP_LIB, LDAP_SEARCH
+    if LDAP_LIB and LDAP_SEARCH:
+        return LDAP_LIB, LDAP_SEARCH
+    try:
+        import ldap
+        from django_auth_ldap.config import LDAPSearch
+        LDAP_LIB, LDAP_SEARCH = ldap, LDAPSearch
+    except ImportError:
+        pass
+    return LDAP_LIB, LDAP_SEARCH
 
 
 ###################### Config ##########################
 ###################### Config ##########################
 
 
@@ -41,35 +48,40 @@ class LdapConfig(BaseConfigSet):
     
     
     @model_validator(mode='after')
     @model_validator(mode='after')
     def validate_ldap_config(self):
     def validate_ldap_config(self):
-        # Check that LDAP libraries are installed
-        if self.LDAP_ENABLED and LDAP_LIB is None:
-            sys.stderr.write('[X] Error: LDAP Authentication is enabled but LDAP libraries are not installed. You may need to run: pip install archivebox[ldap]\n')
-            # dont hard exit here. in case the user is just running "archivebox version" or "archivebox help", we still want those to work despite broken ldap
-            # sys.exit(1)
-            self.update(LDAP_ENABLED=False)
-
-        # Check that all required LDAP config options are set
-        if self.LDAP_ENABLED and not self.LDAP_CONFIG_IS_SET:
-            missing_config_options = [
-                key for key, value in self.model_dump().items()
-                if value is None and key != 'LDAP_ENABLED'
-            ]
-            sys.stderr.write('[X] Error: LDAP_* config options must all be set if LDAP_ENABLED=True\n')
-            sys.stderr.write(f'    Missing: {", ".join(missing_config_options)}\n')
-            self.update(LDAP_ENABLED=False)
+        if self.LDAP_ENABLED:
+            LDAP_LIB, _LDAPSearch = get_ldap_lib()
+            # Check that LDAP libraries are installed
+            if LDAP_LIB is None:
+                sys.stderr.write('[X] Error: LDAP Authentication is enabled but LDAP libraries are not installed. You may need to run: pip install archivebox[ldap]\n')
+                # dont hard exit here. in case the user is just running "archivebox version" or "archivebox help", we still want those to work despite broken ldap
+                # sys.exit(1)
+                self.update_in_place(LDAP_ENABLED=False)
+
+            # Check that all required LDAP config options are set
+            if self.self.LDAP_CONFIG_IS_SET:
+                missing_config_options = [
+                    key for key, value in self.model_dump().items()
+                    if value is None and key != 'LDAP_ENABLED'
+                ]
+                sys.stderr.write('[X] Error: LDAP_* config options must all be set if LDAP_ENABLED=True\n')
+                sys.stderr.write(f'    Missing: {", ".join(missing_config_options)}\n')
+                self.update_in_place(LDAP_ENABLED=False)
         return self
         return self
     
     
     @computed_field
     @computed_field
     @property
     @property
     def LDAP_CONFIG_IS_SET(self) -> bool:
     def LDAP_CONFIG_IS_SET(self) -> bool:
         """Check that all required LDAP config options are set"""
         """Check that all required LDAP config options are set"""
-        return bool(LDAP_LIB) and self.LDAP_ENABLED and bool(
-            self.LDAP_SERVER_URI
-            and self.LDAP_BIND_DN
-            and self.LDAP_BIND_PASSWORD
-            and self.LDAP_USER_BASE
-            and self.LDAP_USER_FILTER
-        )
+        if self.LDAP_ENABLED:
+            LDAP_LIB, _LDAPSearch = get_ldap_lib()
+            return bool(LDAP_LIB) and self.LDAP_ENABLED and bool(
+                self.LDAP_SERVER_URI
+                and self.LDAP_BIND_DN
+                and self.LDAP_BIND_PASSWORD
+                and self.LDAP_USER_BASE
+                and self.LDAP_USER_FILTER
+            )
+        return False
 
 
     @computed_field
     @computed_field
     @property
     @property
@@ -84,19 +96,24 @@ class LdapConfig(BaseConfigSet):
     @computed_field
     @computed_field
     @property
     @property
     def AUTHENTICATION_BACKENDS(self) -> List[str]:
     def AUTHENTICATION_BACKENDS(self) -> List[str]:
-        return [
-            'django.contrib.auth.backends.ModelBackend',
-            'django_auth_ldap.backend.LDAPBackend',
-        ]
+        if self.LDAP_ENABLED:
+            return [
+                'django.contrib.auth.backends.ModelBackend',
+                'django_auth_ldap.backend.LDAPBackend',
+            ]
+        return []
 
 
     @computed_field
     @computed_field
     @property
     @property
     def AUTH_LDAP_USER_SEARCH(self) -> Optional[object]:
     def AUTH_LDAP_USER_SEARCH(self) -> Optional[object]:
-        return self.LDAP_USER_FILTER and LDAPSearch(
-            self.LDAP_USER_BASE,
-            LDAP_LIB.SCOPE_SUBTREE,                                                                         # type: ignore
-            '(&(' + self.LDAP_USERNAME_ATTR + '=%(user)s)' + self.LDAP_USER_FILTER + ')',
-        )
+        if self.LDAP_ENABLED:
+            LDAP_LIB, LDAPSearch = get_ldap_lib()
+            return self.LDAP_USER_FILTER and LDAPSearch(
+                self.LDAP_USER_BASE,
+                LDAP_LIB.SCOPE_SUBTREE,                                                                         # type: ignore
+                '(&(' + self.LDAP_USERNAME_ATTR + '=%(user)s)' + self.LDAP_USER_FILTER + ')',
+            )
+        return None
 
 
 
 
 LDAP_CONFIG = LdapConfig()
 LDAP_CONFIG = LdapConfig()