mirror of
https://github.com/inventree/InvenTree.git
synced 2026-04-25 12:33:33 +00:00
Ensure configuration settings are documented (#11674)
* Export configuration keys to JSON * Support rendering of config options in docs * Check for missing config settings * Simplify macro * Initial tests * Fix collisions * Updates * Ensure values are stringified * Ensure null values are exported correctly * Refactor database config - Observability on the config settings * More docs updates * Updates * Add observability of cache settings * More updates * Observability * Set env config for RTD * Revert RTD config file - Handled by ENV VAR on RTD account * Visibility on background worker settings * Tweaks * Tweaks * Split tracing settings out into separate file - Improved discovery - declutter settings.py * Cleanup LDAP settings * Social providers docs * More updates * Refactor ldap setup into own module * Tweaks * Formatting tweaks * Tweak logic * Fix INVENTREE_SESSION_COOKIE_SECURE setting * Fix wrapping * Add custom default
This commit is contained in:
+19
-1
@@ -280,9 +280,27 @@ def on_post_build(*args, **kwargs):
|
|||||||
ignored_settings = {
|
ignored_settings = {
|
||||||
'global': ['SERVER_RESTART_REQUIRED'],
|
'global': ['SERVER_RESTART_REQUIRED'],
|
||||||
'user': ['LAST_USED_PRINTING_MACHINES'],
|
'user': ['LAST_USED_PRINTING_MACHINES'],
|
||||||
|
'config': [
|
||||||
|
'INVENTREE_DB_TCP_KEEPALIVES',
|
||||||
|
'INVENTREE_DB_TCP_KEEPALIVES_IDLE',
|
||||||
|
'INVENTREE_DB_TCP_KEEPALIVES_INTERVAL',
|
||||||
|
'INVENTREE_DB_TCP_KEEPALIVES_COUNT',
|
||||||
|
'INVENTREE_DB_ISOLATION_SERIALIZABLE',
|
||||||
|
'INVENTREE_DB_WAL_MODE',
|
||||||
|
'INVENTREE_PLUGIN_DIR',
|
||||||
|
'INVENTREE_DOCKER',
|
||||||
|
'INVENTREE_FLAGS',
|
||||||
|
'INVENTREE_REMOTE_LOGIN',
|
||||||
|
'INVENTREE_REMOTE_LOGIN_HEADER',
|
||||||
|
'TEST_TRANSLATIONS',
|
||||||
|
'INVENTREE_FRONTEND_URL_BASE',
|
||||||
|
'INVENTREE_FRONTEND_API_HOST',
|
||||||
|
'INVENTREE_FRONTEND_SETTINGS',
|
||||||
|
'INVENTREE_LOGOUT_REDIRECT_URL',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
for group in ['global', 'user']:
|
for group in ['global', 'user', 'config']:
|
||||||
expected = expected_settings.get(group, {})
|
expected = expected_settings.get(group, {})
|
||||||
observed = observed_settings.get(group, {})
|
observed = observed_settings.get(group, {})
|
||||||
ignored = ignored_settings.get(group, [])
|
ignored = ignored_settings.get(group, [])
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ For complicated plugins it makes sense to add unit tests the code to ensure that
|
|||||||
|
|
||||||
For plugin testing the following environment variables must be set to True:
|
For plugin testing the following environment variables must be set to True:
|
||||||
|
|
||||||
| Name | Function | Value |
|
{{ configtable() }}
|
||||||
| ---- | -------- | ----- |
|
{{ configsetting("INVENTREE_PLUGINS_ENABLED") }} Enables the use of 3rd party plugins |
|
||||||
| INVENTREE_PLUGINS_ENABLED | Enables the use of 3rd party plugins | True |
|
{{ configsetting("INVENTREE_PLUGIN_TESTING") }} Enables enables all plugins no matter of their active state in the db or built-in flag |
|
||||||
| INVENTREE_PLUGIN_TESTING | Enables enables all plugins no matter of their active state in the db or built-in flag | True |
|
{{ configsetting("INVENTREE_PLUGIN_TESTING_SETUP") }} Enables the url mixin |
|
||||||
| INVENTREE_PLUGIN_TESTING_SETUP | Enables the url mixin | True |
|
|
||||||
|
|
||||||
### Test Program
|
### Test Program
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ The first step is to ensure that the required provider modules are installed, vi
|
|||||||
|
|
||||||
There are two variables in the configuration file which define the operation of SSO:
|
There are two variables in the configuration file which define the operation of SSO:
|
||||||
|
|
||||||
| Environment Variable |Configuration File | Description | More Info |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_SOCIAL_BACKENDS") }} A *list* of [social provider backends](https://docs.allauth.org/en/latest/installation/quickstart.html) enabled for the InvenTree instance |
|
||||||
| INVENTREE_SOCIAL_BACKENDS | `social_backends` | A *list* of provider backends enabled for the InvenTree instance | [django-allauth docs](https://docs.allauth.org/en/latest/installation/quickstart.html) |
|
{{ configsetting("INVENTREE_SOCIAL_PROVIDERS") }} A *dict* of settings specific to the [installed providers](https://docs.allauth.org/en/latest/socialaccount/providers/index.html) |
|
||||||
| INVENTREE_SOCIAL_PROVIDERS | `social_providers` | A *dict* of settings specific to the installed providers | [provider documentation](https://docs.allauth.org/en/latest/socialaccount/providers/index.html) |
|
|
||||||
|
|
||||||
In the example below, SSO provider modules are activated for *google*, *github* and *microsoft*. Specific configuration options are specified for the *microsoft* provider module:
|
In the example below, SSO provider modules are activated for *google*, *github* and *microsoft*. Specific configuration options are specified for the *microsoft* provider module:
|
||||||
|
|
||||||
|
|||||||
+35
-38
@@ -51,46 +51,44 @@ You can link your InvenTree server to an LDAP server.
|
|||||||
|
|
||||||
Next you can start configuring the connection. Either use the config file or set the environment variables.
|
Next you can start configuring the connection. Either use the config file or set the environment variables.
|
||||||
|
|
||||||
| config key | ENV Variable | Description |
|
{{ configtable() }}
|
||||||
| --- | --- | --- |
|
{{ configsetting("INVENTREE_LDAP_ENABLED") }} Enable LDAP support |
|
||||||
| `ldap.enabled` | `INVENTREE_LDAP_ENABLED` | Set this to `True` to enable LDAP. |
|
{{ configsetting("INVENTREE_LDAP_DEBUG") }} Set this to `True` to activate debug mode, useful for troubleshooting ldap configurations. |
|
||||||
| `ldap.debug` | `INVENTREE_LDAP_DEBUG` | Set this to `True` to activate debug mode, useful for troubleshooting ldap configurations. |
|
| `INVENTREE_LDAP_SERVER_URI` | `ldap.server_uri` | LDAP Server URI, e.g. `ldaps://example.org` |
|
||||||
| `ldap.server_uri` | `INVENTREE_LDAP_SERVER_URI` | LDAP Server URI, e.g. `ldaps://example.org` |
|
| `INVENTREE_LDAP_START_TLS` | `ldap.start_tls` | Enable TLS encryption over the standard LDAP port, [see](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-start-tls). (You can set TLS options via `ldap.global_options`) |
|
||||||
| `ldap.start_tls` | `INVENTREE_LDAP_START_TLS` | Enable TLS encryption over the standard LDAP port, [see](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-start-tls). (You can set TLS options via `ldap.global_options`) |
|
| `INVENTREE_LDAP_BIND_DN` | `ldap.bind_dn` | LDAP bind dn, e.g. `cn=admin,dc=example,dc=org` |
|
||||||
| `ldap.bind_dn` | `INVENTREE_LDAP_BIND_DN` | LDAP bind dn, e.g. `cn=admin,dc=example,dc=org` |
|
| `INVENTREE_LDAP_BIND_PASSWORD` | `ldap.bind_password` | LDAP bind password |
|
||||||
| `ldap.bind_password` | `INVENTREE_LDAP_BIND_PASSWORD` | LDAP bind password |
|
| `INVENTREE_LDAP_SEARCH_BASE_DN` | `ldap.search_base_dn` | LDAP search base dn, e.g. `cn=Users,dc=example,dc=org` |
|
||||||
| `ldap.search_base_dn` | `INVENTREE_LDAP_SEARCH_BASE_DN` | LDAP search base dn, e.g. `cn=Users,dc=example,dc=org` |
|
| `INVENTREE_LDAP_USER_DN_TEMPLATE` | `ldap.user_dn_template` | use direct bind as auth user, `ldap.bind_dn` and `ldap.bin_password` is not necessary then, e.g. `uid=%(user)s,dc=example,dc=org` |
|
||||||
| `ldap.user_dn_template` | `INVENTREE_LDAP_USER_DN_TEMPLATE` | use direct bind as auth user, `ldap.bind_dn` and `ldap.bin_password` is not necessary then, e.g. `uid=%(user)s,dc=example,dc=org` |
|
| `INVENTREE_LDAP_GLOBAL_OPTIONS` | `ldap.global_options` | set advanced options as dict, e.g. TLS settings. For a list of all available options, see [python-ldap docs](https://www.python-ldap.org/en/latest/reference/ldap.html#ldap-options). (keys and values starting with OPT_ get automatically converted to `python-ldap` keys) |
|
||||||
| `ldap.global_options` | `INVENTREE_LDAP_GLOBAL_OPTIONS` | set advanced options as dict, e.g. TLS settings. For a list of all available options, see [python-ldap docs](https://www.python-ldap.org/en/latest/reference/ldap.html#ldap-options). (keys and values starting with OPT_ get automatically converted to `python-ldap` keys) |
|
| `INVENTREE_LDAP_SEARCH_FILTER_STR`| `ldap.search_filter_str` | LDAP search filter str, default: `uid=%(user)s` |
|
||||||
| `ldap.search_filter_str`| `INVENTREE_LDAP_SEARCH_FILTER_STR` | LDAP search filter str, default: `uid=%(user)s` |
|
| `INVENTREE_LDAP_USER_ATTR_MAP` | `ldap.user_attr_map` | LDAP <-> InvenTree user attribute map, can be json if used as env, in yml directly specify the object. default: `{"first_name": "givenName", "last_name": "sn", "email": "mail"}` |
|
||||||
| `ldap.user_attr_map` | `INVENTREE_LDAP_USER_ATTR_MAP` | LDAP <-> InvenTree user attribute map, can be json if used as env, in yml directly specify the object. default: `{"first_name": "givenName", "last_name": "sn", "email": "mail"}` |
|
| `INVENTREE_LDAP_ALWAYS_UPDATE_USER` | `ldap.always_update_user` | Always update the user on each login, default: `true` |
|
||||||
| `ldap.always_update_user` | `INVENTREE_LDAP_ALWAYS_UPDATE_USER` | Always update the user on each login, default: `true` |
|
| `INVENTREE_LDAP_CACHE_TIMEOUT` | `ldap.cache_timeout` | cache timeout to reduce traffic with LDAP server, default: `3600` (1h) |
|
||||||
| `ldap.cache_timeout` | `INVENTREE_LDAP_CACHE_TIMEOUT` | cache timeout to reduce traffic with LDAP server, default: `3600` (1h) |
|
| `INVENTREE_LDAP_GROUP_SEARCH` | `ldap.group_search` | Base LDAP DN for group searching; required to enable group features |
|
||||||
| `ldap.group_search` | `INVENTREE_LDAP_GROUP_SEARCH` | Base LDAP DN for group searching; required to enable group features |
|
| `INVENTREE_LDAP_GROUP_OBJECT_CLASS` | `ldap.group_object_class` | The string to pass to the LDAP group search `(objectClass=<...>)`, default: `groupOfUniqueNames` |
|
||||||
| `ldap.group_object_class` | `INVENTREE_LDAP_GROUP_OBJECT_CLASS` | The string to pass to the LDAP group search `(objectClass=<...>)`, default: `groupOfUniqueNames` |
|
| `INVENTREE_LDAP_MIRROR_GROUPS` | `ldap.mirror_groups` | If `True`, mirror a user's LDAP group membership in the Django database, default: `False` |
|
||||||
| `ldap.mirror_groups` | `INVENTREE_LDAP_MIRROR_GROUPS` | If `True`, mirror a user's LDAP group membership in the Django database, default: `False` |
|
| `INVENTREE_LDAP_GROUP_TYPE_CLASS` | `ldap.group_type_class` | The group class to be imported from `django_auth_ldap.config` as a string, default: `'GroupOfUniqueNamesType'`|
|
||||||
| `ldap.group_type_class` | `INVENTREE_LDAP_GROUP_TYPE_CLASS` | The group class to be imported from `django_auth_ldap.config` as a string, default: `'GroupOfUniqueNamesType'`|
|
| `INVENTREE_LDAP_GROUP_TYPE_CLASS_ARGS` | `ldap.group_type_class_args` | A `list` of positional args to pass to the LDAP group type class, default `[]` |
|
||||||
| `ldap.group_type_class_args` | `INVENTREE_LDAP_GROUP_TYPE_CLASS_ARGS` | A `list` of positional args to pass to the LDAP group type class, default `[]` |
|
| `INVENTREE_LDAP_GROUP_TYPE_CLASS_KWARGS` | `ldap.group_type_class_kwargs` | A `dict` of keyword args to pass to the LDAP group type class, default `{'name_attr': 'cn'}` |
|
||||||
| `ldap.group_type_class_kwargs` | `INVENTREE_LDAP_GROUP_TYPE_CLASS_KWARGS` | A `dict` of keyword args to pass to the LDAP group type class, default `{'name_attr': 'cn'}` |
|
| `INVENTREE_LDAP_REQUIRE_GROUP` | `ldap.require_group` | If set, users _must_ be in this group to log in to InvenTree |
|
||||||
| `ldap.require_group` | `INVENTREE_LDAP_REQUIRE_GROUP` | If set, users _must_ be in this group to log in to InvenTree |
|
| `INVENTREE_LDAP_DENY_GROUP` | `ldap.deny_group` | If set, users _must not_ be in this group to log in to InvenTree |
|
||||||
| `ldap.deny_group` | `INVENTREE_LDAP_DENY_GROUP` | If set, users _must not_ be in this group to log in to InvenTree |
|
| `INVENTREE_LDAP_USER_FLAGS_BY_GROUP` | `ldap.user_flags_by_group` | LDAP group to InvenTree user flag map, can be json if used as env, in yml directly specify the object. See config template for example, default: `{}` |
|
||||||
| `ldap.user_flags_by_group` | `INVENTREE_LDAP_USER_FLAGS_BY_GROUP` | LDAP group to InvenTree user flag map, can be json if used as env, in yml directly specify the object. See config template for example, default: `{}` |
|
|
||||||
|
|
||||||
## Tracing support
|
## Tracing support
|
||||||
|
|
||||||
Starting with 0.14.0 InvenTree supports sending traces, logs and metrics to OpenTelemetry compatible endpoints (both HTTP and gRPC). A [list of vendors](https://opentelemetry.io/ecosystem/vendors) is available on the project site.
|
Starting with 0.14.0 InvenTree supports sending traces, logs and metrics to OpenTelemetry compatible endpoints (both HTTP and gRPC). A [list of vendors](https://opentelemetry.io/ecosystem/vendors) is available on the project site.
|
||||||
This can be used to track usage and performance of the InvenTree backend and connected services like databases, caches and more.
|
This can be used to track usage and performance of the InvenTree backend and connected services like databases, caches and more.
|
||||||
|
|
||||||
| config key | ENV Variable | Description |
|
{{ configtable() }}
|
||||||
| --- | --- | --- |
|
{{ configsetting("INVENTREE_TRACING_ENABLED") }} Enable OpenTelemetry |
|
||||||
| `tracing.enabled` | `INVENTREE_TRACING_ENABLED` | Set this to `True` to enable OpenTelemetry. |
|
{{ configsetting("INVENTREE_TRACING_ENDPOINT") }} General endpoint for information (not specific trace/log url) |
|
||||||
| `tracing.endpoint` | `INVENTREE_TRACING_ENDPOINT` | General endpoint for information (not specific trace/log url) |
|
{{ configsetting("INVENTREE_TRACING_HEADERS") }} HTTP headers that should be send with every request (often used for authentication). Format as a dict. |
|
||||||
| `tracing.headers` | `INVENTREE_TRACING_HEADERS` | HTTP headers that should be send with every request (often used for authentication). Format as a dict. |
|
{{ configsetting("INVENTREE_TRACING_AUTH") }} Auth headers that should be send with every requests (will be encoded to b64 and overwrite auth headers) |
|
||||||
| `tracing.auth.basic` | `INVENTREE_TRACING_AUTH_BASIC` | Auth headers that should be send with every requests (will be encoded to b64 and overwrite auth headers) |
|
{{ configsetting("INVENTREE_TRACING_IS_HTTP") }} Are the endpoints HTTP (True, default) or gRPC (False) |
|
||||||
| `tracing.is_http` | `INVENTREE_TRACING_IS_HTTP` | Are the endpoints HTTP (True, default) or gRPC (False) |
|
{{ configsetting("INVENTREE_TRACING_APPEND_HTTP") }} Append default url routes (v1) to `tracing.endpoint` |
|
||||||
| `tracing.append_http` | `INVENTREE_TRACING_APPEND_HTTP` | Append default url routes (v1) to `tracing.endpoint` |
|
{{ configsetting("INVENTREE_TRACING_CONSOLE") }} Print out all exports (additionally) to the console for debugging. Do not use in production |
|
||||||
| `tracing.console` | `INVENTREE_TRACING_CONSOLE` | Print out all exports (additionally) to the console for debugging. Do not use in production |
|
{{ configsetting("INVENTREE_TRACING_RESOURCES") }} Add additional resources to all exports. This can be used to add custom tags to the traces. Format as a dict. |
|
||||||
| `tracing.resources` | `INVENTREE_TRACING_RESOURCES` | Add additional resources to all exports. This can be used to add custom tags to the traces. Format as a dict. |
|
|
||||||
|
|
||||||
## Multi Site Support
|
## Multi Site Support
|
||||||
|
|
||||||
@@ -99,7 +97,6 @@ If your InvenTree instance is used in a multi-site environment, you can enable m
|
|||||||
!!! tip "Django Documentation"
|
!!! tip "Django Documentation"
|
||||||
For more information on multi-site support, refer to the [Django documentation]({% include "django.html" %}/ref/contrib/sites/).
|
For more information on multi-site support, refer to the [Django documentation]({% include "django.html" %}/ref/contrib/sites/).
|
||||||
|
|
||||||
| Environment Variable | Config Key | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_SITE_MULTI") }} Enable multiple sites |
|
||||||
| INVENTREE_SITE_MULTI | site_multi | Enable multiple sites | False |
|
{{ configsetting("INVENTREE_SITE_ID") }} Specify a fixed site ID |
|
||||||
| INVENTREE_SITE_ID | site_id | Specify a fixed site ID | _Not specified_ |
|
|
||||||
|
|||||||
+13
-13
@@ -17,19 +17,19 @@ The django-dbbackup library provides [multiple configuration options](https://ar
|
|||||||
|
|
||||||
The following configuration options are available for backup:
|
The following configuration options are available for backup:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_BACKUP_STORAGE") }} Backup storage backend. Refer to the [storage backend documentation](#storage-backend). |
|
||||||
| INVENTREE_BACKUP_STORAGE | backup_storage | Backup storage backend. Refer to the [storage backend documentation](#storage-backend). | django.core.files.storage.FileSystemStorage |
|
{{ configsetting("INVENTREE_BACKUP_DIR") }} Backup storage directory. |
|
||||||
| INVENTREE_BACKUP_DIR | backup_dir | Backup storage directory. | *No default* |
|
{{ configsetting("INVENTREE_BACKUP_OPTIONS") }} Specific options for the selected storage backend (dict) |
|
||||||
| INVENTREE_BACKUP_OPTIONS | backup_options | Specific options for the selected storage backend (dict) | *No default* |
|
{{ configsetting("INVENTREE_BACKUP_CONNECTOR_OPTIONS") }} Specific options for the database connector (dict). Refer to the [database connector options](#database-connector) |
|
||||||
| INVENTREE_BACKUP_CONNECTOR_OPTIONS | backup_connector_options | Specific options for the database connector (dict). Refer to the [database connector options](#database-connector). | *No default* |
|
{{ configsetting("INVENTREE_BACKUP_SEND_EMAIL") }} If True, an email is sent to the site admin when an error occurs during a backup or restore procedure. |
|
||||||
| INVENTREE_BACKUP_SEND_EMAIL | backup_send_email | If True, an email is sent to the site admin when an error occurs during a backup or restore procedure. | False |
|
{{ configsetting("INVENTREE_BACKUP_EMAIL_PREFIX") }} Prefix for the subject line of backup-related emails. |
|
||||||
| INVENTREE_BACKUP_EMAIL_PREFIX | backup_email_prefix | Prefix for the subject line of backup-related emails. | `[InvenTree Backup]` |
|
{{ configsetting("INVENTREE_BACKUP_GPG_RECIPIENT") }} Specify GPG recipient if using encryption for backups. |
|
||||||
| INVENTREE_BACKUP_GPG_RECIPIENT | backup_gpg_recipient | Specify GPG recipient if using encryption for backups. | *No default* |
|
{{ configsetting("INVENTREE_BACKUP_DATE_FORMAT") }} Date format string used to format timestamps in backup filenames. |
|
||||||
| INVENTREE_BACKUP_DATE_FORMAT | backup_date_format | Date format string used to format timestamps in backup filenames. | `%Y-%m-%d-%H%M%S` |
|
{{ configsetting("INVENTREE_BACKUP_DATABASE_FILENAME_TEMPLATE") }} Template string used to generate database backup filenames.
|
||||||
| INVENTREE_BACKUP_DATABASE_FILENAME_TEMPLATE | backup_database_filename_template | Template string used to generate database backup filenames. | `InvenTree-db-{datetime}.{extension}` |
|
{{ configsetting("INVENTREE_BACKUP_MEDIA_FILENAME_TEMPLATE") }} Template string used to generate media backup filenames. |
|
||||||
| INVENTREE_BACKUP_MEDIA_FILENAME_TEMPLATE | backup_media_filename_template | Template string used to generate media backup filenames. | `InvenTree-media-{datetime}.{extension}` |
|
{{ configsetting("INVENTREE_BACKUP_RESTORE_ALLOW_NEWER_VERSION") }} If True, allows restoring a backup created with a newer version of InvenTree. This is dangerous as it can lead to hard-to-debug data loss. |
|
||||||
| INVENTREE_BACKUP_RESTORE_ALLOW_NEWER_VERSION | backup_restore_allow_newer_version | If True, allows restoring a backup created with a newer version of InvenTree. This is dangerous as it can lead to hard-to-debug data loss. | False |
|
|
||||||
|
|
||||||
### Storage Backend
|
### Storage Backend
|
||||||
|
|
||||||
|
|||||||
+158
-168
@@ -46,6 +46,9 @@ Environment variable settings generally use the `INVENTREE_` prefix, and are all
|
|||||||
!!! warning "Available Variables"
|
!!! warning "Available Variables"
|
||||||
Some configuration options cannot be set via environment variables. Refer to the documentation below.
|
Some configuration options cannot be set via environment variables. Refer to the documentation below.
|
||||||
|
|
||||||
|
!!! info "Environment Variable Priority"
|
||||||
|
Note that a provided environment variable will override the value provided in the configuration file.
|
||||||
|
|
||||||
#### List Values
|
#### List Values
|
||||||
|
|
||||||
To specify a list value in an environment variable, use a comma-separated list. For example, to specify a list of trusted origins:
|
To specify a list value in an environment variable, use a comma-separated list. For example, to specify a list of trusted origins:
|
||||||
@@ -58,14 +61,13 @@ INVENTREE_TRUSTED_ORIGINS='https://inventree.example.com:8443,https://stock.exam
|
|||||||
|
|
||||||
The following basic options are available:
|
The following basic options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_SITE_URL") }} Specify a fixed site URL |
|
||||||
| INVENTREE_SITE_URL | site_url | Specify a fixed site URL | *Not specified* |
|
{{ configsetting("INVENTREE_TIMEZONE") }} Server timezone |
|
||||||
| INVENTREE_TIMEZONE | timezone | Server timezone | UTC |
|
{{ configsetting("INVENTREE_ADMIN_ENABLED") }} Enable the [django administrator interface]({% include "django.html" %}/ref/contrib/admin/) |
|
||||||
| INVENTREE_ADMIN_ENABLED | admin_enabled | Enable the [django administrator interface]({% include "django.html" %}/ref/contrib/admin/) | True |
|
{{ configsetting("INVENTREE_ADMIN_URL") }} URL for accessing [admin interface](../settings/admin.md) |
|
||||||
| INVENTREE_ADMIN_URL | admin_url | URL for accessing [admin interface](../settings/admin.md) | admin |
|
{{ configsetting("INVENTREE_LANGUAGE") }} Default language |
|
||||||
| INVENTREE_LANGUAGE | language | Default language | en-us |
|
{{ configsetting("INVENTREE_AUTO_UPDATE") }} Database migrations will be run automatically |
|
||||||
| INVENTREE_AUTO_UPDATE | auto_update | Database migrations will be run automatically | False |
|
|
||||||
|
|
||||||
### Site URL
|
### Site URL
|
||||||
|
|
||||||
@@ -89,18 +91,17 @@ With "auto update" enabled, the InvenTree server will automatically apply databa
|
|||||||
|
|
||||||
The following debugging / logging options are available:
|
The following debugging / logging options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_DEBUG") }} Enable [debug mode](./index.md#debug-mode) |
|
||||||
| INVENTREE_DEBUG | debug | Enable [debug mode](./index.md#debug-mode) | False |
|
{{ configsetting("INVENTREE_DB_LOGGING") }} Enable logging of database messages |
|
||||||
| INVENTREE_DEBUG_QUERYCOUNT | debug_querycount | Enable support for [django-querycount](../develop/index.md#django-querycount) middleware. | False |
|
{{ configsetting("INVENTREE_LOG_LEVEL") }} Set level of logging to terminal |
|
||||||
| INVENTREE_DEBUG_SILK | debug_silk | Enable support for [django-silk](../develop/index.md#django-silk) profiling tool. | False |
|
{{ configsetting("INVENTREE_JSON_LOG") }} Log messages as json |
|
||||||
| INVENTREE_DEBUG_SILK_PROFILING | debug_silk_profiling | Enable detailed profiling in django-silk | False |
|
{{ configsetting("INVENTREE_WRITE_LOG") }} Enable writing of log messages to file at config base |
|
||||||
| INVENTREE_DB_LOGGING | db_logging | Enable logging of database messages | False |
|
{{ configsetting("INVENTREE_CONSOLE_LOG") }} Enable logging to console |
|
||||||
| INVENTREE_LOG_LEVEL | log_level | Set level of logging to terminal | WARNING |
|
{{ configsetting("INVENTREE_SCHEMA_LEVEL") }} Set level of added schema extensions detail (0-3) 0 = including no additional detail |
|
||||||
| INVENTREE_JSON_LOG | json_log | log as json | False |
|
{{ configsetting("INVENTREE_DEBUG_QUERYCOUNT") }} Enable support for [django-querycount](../develop/index.md#django-querycount) middleware. |
|
||||||
| INVENTREE_WRITE_LOG | write_log | Enable writing of log messages to file at config base | False |
|
{{ configsetting("INVENTREE_DEBUG_SILK") }} Enable support for [django-silk](../develop/index.md#django-silk) profiling tool. |
|
||||||
| INVENTREE_CONSOLE_LOG | console_log | Enable logging to console | True |
|
| `INVENTREE_DEBUG_SILK_PROFILING` | `debug_silk_profiling` | False | Enable detailed profiling in django-silk |
|
||||||
| INVENTREE_SCHEMA_LEVEL | schema.level | Set level of added schema extensions detail (0-3) 0 = including no additional detail | 0 |
|
|
||||||
|
|
||||||
### Debug Mode
|
### Debug Mode
|
||||||
|
|
||||||
@@ -118,26 +119,24 @@ Depending on how your InvenTree installation is configured, you will need to pay
|
|||||||
!!! danger "Not Secure"
|
!!! danger "Not Secure"
|
||||||
Allowing access from any host is not secure, and should be adjusted for your installation.
|
Allowing access from any host is not secure, and should be adjusted for your installation.
|
||||||
|
|
||||||
!!! info "Environment Variables"
|
|
||||||
Note that a provided environment variable will override the value provided in the configuration file.
|
|
||||||
|
|
||||||
!!! success "INVENTREE_SITE_URL"
|
!!! success "INVENTREE_SITE_URL"
|
||||||
If you have specified the `INVENTREE_SITE_URL`, this will automatically be used as a trusted CSRF and CORS host (see below).
|
If you have specified the `INVENTREE_SITE_URL`, this will automatically be used as a trusted CSRF and CORS host (see below).
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_ALLOWED_HOSTS") }} List of allowed hosts |
|
||||||
| INVENTREE_ALLOWED_HOSTS | allowed_hosts | List of allowed hosts | `*` |
|
{{ configsetting("INVENTREE_TRUSTED_ORIGINS", default="Uses the *INVENTREE_SITE_URL* parameter, if set. Otherwise, an empty list.") }} List of trusted origins. Refer to the [django documentation]({% include "django.html" %}/ref/settings/#csrf-trusted-origins) |
|
||||||
| INVENTREE_TRUSTED_ORIGINS | trusted_origins | List of trusted origins. Refer to the [django documentation]({% include "django.html" %}/ref/settings/#csrf-trusted-origins) | Uses the *INVENTREE_SITE_URL* parameter, if set. Otherwise, an empty list. |
|
{{ configsetting("INVENTREE_CORS_ORIGIN_ALLOW_ALL") }} Allow all remote URLS for CORS checks |
|
||||||
| INVENTREE_CORS_ORIGIN_ALLOW_ALL | cors.allow_all | Allow all remote URLS for CORS checks | `False` |
|
{{ configsetting("INVENTREE_CORS_ORIGIN_WHITELIST", default="Uses the *INVENTREE_SITE_URL* parameter, if set. Otherwise, an empty list.") }} List of whitelisted CORS URLs. Refer to the [django-cors-headers documentation](https://github.com/adamchainz/django-cors-headers#cors_allowed_origins-sequencestr) |
|
||||||
| INVENTREE_CORS_ORIGIN_WHITELIST | cors.whitelist | List of whitelisted CORS URLs. Refer to the [django-cors-headers documentation](https://github.com/adamchainz/django-cors-headers#cors_allowed_origins-sequencestr) | Uses the *INVENTREE_SITE_URL* parameter, if set. Otherwise, an empty list. |
|
{{ configsetting("INVENTREE_CORS_ORIGIN_REGEX") }} List of regular expressions for CORS whitelisted URL patterns |
|
||||||
| INVENTREE_CORS_ORIGIN_REGEX | cors.regex | List of regular expressions for CORS whitelisted URL patterns | *Empty list* |
|
{{ configsetting("INVENTREE_CORS_ALLOW_CREDENTIALS") }} Allow cookies in cross-site requests |
|
||||||
| INVENTREE_CORS_ALLOW_CREDENTIALS | cors.allow_credentials | Allow cookies in cross-site requests | `True` |
|
{{ configsetting("INVENTREE_SITE_LAX_PROTOCOL") }} Ignore protocol mismatches on INVE-E7 site checks |
|
||||||
| INVENTREE_SITE_LAX_PROTOCOL | site_lax_protocol | Ignore protocol mismatches on INVE-E7 site checks | `True` |
|
{{ configsetting("INVENTREE_USE_X_FORWARDED_HOST") }} Use forwarded host header |
|
||||||
| INVENTREE_USE_X_FORWARDED_HOST | use_x_forwarded_host | Use forwarded host header | `False` |
|
{{ configsetting("INVENTREE_USE_X_FORWARDED_PORT") }} Use forwarded port header |
|
||||||
| INVENTREE_USE_X_FORWARDED_PORT | use_x_forwarded_port | Use forwarded port header | `False` |
|
{{ configsetting("INVENTREE_USE_X_FORWARDED_PROTO") }} Use forwarded protocol header |
|
||||||
| INVENTREE_USE_X_FORWARDED_PROTO | use_x_forwarded_proto | Use forwarded protocol header | `False` |
|
| `INVENTREE_X_FORWARDED_PROTO_NAME` | `x_forwarded_proto_name` | `HTTP_X_FORWARDED_PROTO` | Name of the header to use for forwarded protocol information |
|
||||||
| INVENTREE_SESSION_COOKIE_SECURE | cookie.secure | Enforce secure session cookies | `False` |
|
{{ configsetting("INVENTREE_SESSION_COOKIE_SECURE") }} Enforce secure session cookies |
|
||||||
| INVENTREE_COOKIE_SAMESITE | cookie.samesite | Session cookie mode. Must be one of `Strict | Lax | None | False`. Refer to the [mozilla developer docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) and the [django documentation]({% include "django.html" %}/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE) for more information. | False |
|
{{ configsetting("INVENTREE_COOKIE_SAMESITE") }} Session cookie mode. Must be one of `Strict | Lax | None | False`. Refer to the [mozilla developer docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) and the [django documentation]({% include "django.html" %}/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE) for more information. |
|
||||||
|
|
||||||
|
|
||||||
### Debug Mode
|
### Debug Mode
|
||||||
|
|
||||||
@@ -191,10 +190,9 @@ Django provides a powerful [administrator interface]({% include "django.html" %}
|
|||||||
|
|
||||||
The following admin site configuration options are available:
|
The following admin site configuration options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_ADMIN_ENABLED") }} Enable the django administrator interface |
|
||||||
| INVENTREE_ADMIN_ENABLED | admin_enabled | Enable the django administrator interface | True |
|
{{ configsetting("INVENTREE_ADMIN_URL") }} URL for accessing the admin interface |
|
||||||
| INVENTREE_ADMIN_URL | admin_url | URL for accessing the admin interface | admin |
|
|
||||||
|
|
||||||
!!! warning "Security"
|
!!! warning "Security"
|
||||||
Changing the admin URL is a simple way to improve security, but it is not a substitute for proper security practices.
|
Changing the admin URL is a simple way to improve security, but it is not a substitute for proper security practices.
|
||||||
@@ -203,12 +201,11 @@ The following admin site configuration options are available:
|
|||||||
|
|
||||||
An administrator account can be specified using the following environment variables:
|
An administrator account can be specified using the following environment variables:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_ADMIN_USER") }} Admin account username |
|
||||||
| INVENTREE_ADMIN_USER | admin_user | Admin account username | *Not specified* |
|
{{ configsetting("INVENTREE_ADMIN_PASSWORD") }} Admin account password |
|
||||||
| INVENTREE_ADMIN_PASSWORD | admin_password | Admin account password | *Not specified* |
|
{{ configsetting("INVENTREE_ADMIN_PASSWORD_FILE") }} Admin account password file |
|
||||||
| INVENTREE_ADMIN_PASSWORD_FILE | admin_password_file | Admin account password file | *Not specified* |
|
{{ configsetting("INVENTREE_ADMIN_EMAIL") }} Admin account email address |
|
||||||
| INVENTREE_ADMIN_EMAIL | admin_email |Admin account email address | *Not specified* |
|
|
||||||
|
|
||||||
You can either specify the password directly using `INVENTREE_ADMIN_PASSWORD`, or you can specify a file containing the password using `INVENTREE_ADMIN_PASSWORD_FILE` (this is useful for nix users).
|
You can either specify the password directly using `INVENTREE_ADMIN_PASSWORD`, or you can specify a file containing the password using `INVENTREE_ADMIN_PASSWORD_FILE` (this is useful for nix users).
|
||||||
|
|
||||||
@@ -238,12 +235,11 @@ A PEM-encoded file containing the oidc private key can be passed via the environ
|
|||||||
|
|
||||||
If not specified via environment variables, the fallback files (automatically generated as part of InvenTree installation) will be used.
|
If not specified via environment variables, the fallback files (automatically generated as part of InvenTree installation) will be used.
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_SECRET_KEY") }} Raw secret key value |
|
||||||
| INVENTREE_SECRET_KEY | secret_key | Raw secret key value | *Not specified* |
|
{{ configsetting("INVENTREE_SECRET_KEY_FILE") }} File containing secret key value |
|
||||||
| INVENTREE_SECRET_KEY_FILE | secret_key_file | File containing secret key value | *Not specified* |
|
{{ configsetting("INVENTREE_OIDC_PRIVATE_KEY") }} Raw private key value |
|
||||||
| INVENTREE_OIDC_PRIVATE_KEY | oidc_private_key | Raw private key value | *Not specified* |
|
{{ configsetting("INVENTREE_OIDC_PRIVATE_KEY_FILE", default="oidc.pem") }} File containing private key value in PEM format |
|
||||||
| INVENTREE_OIDC_PRIVATE_KEY_FILE | oidc_private_key_file | File containing private key value in PEM format | *Not specified* |
|
|
||||||
|
|
||||||
## Database Options
|
## Database Options
|
||||||
|
|
||||||
@@ -253,14 +249,14 @@ Database options are specified under the *database* heading in the configuration
|
|||||||
|
|
||||||
The following database options can be configured:
|
The following database options can be configured:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_DB_ENGINE") }} Database backend |
|
||||||
| INVENTREE_DB_ENGINE | database.ENGINE | Database backend | *Not specified* |
|
{{ configsetting("INVENTREE_DB_NAME") }} Database name |
|
||||||
| INVENTREE_DB_NAME | database.NAME | Database name | *Not specified* |
|
{{ configsetting("INVENTREE_DB_USER") }} Database username (if required) |
|
||||||
| INVENTREE_DB_USER | database.USER | Database username (if required) | *Not specified* |
|
{{ configsetting("INVENTREE_DB_PASSWORD") }} Database password (if required) |
|
||||||
| INVENTREE_DB_PASSWORD | database.PASSWORD | Database password (if required) | *Not specified* |
|
{{ configsetting("INVENTREE_DB_HOST") }} Database host address (if required) |
|
||||||
| INVENTREE_DB_HOST | database.HOST | Database host address (if required) | *Not specified* |
|
{{ configsetting("INVENTREE_DB_PORT") }} Database host port (if required) |
|
||||||
| INVENTREE_DB_PORT | database.PORT | Database host port (if required) | *Not specified* |
|
{{ configsetting("INVENTREE_DB_OPTIONS") }} Additional database options (as a JSON object) |
|
||||||
|
|
||||||
!!! tip "Database Password"
|
!!! tip "Database Password"
|
||||||
The value specified for `INVENTREE_DB_PASSWORD` should not contain comma `,` or colon `:` characters, otherwise the connection to the database may fail.
|
The value specified for `INVENTREE_DB_PASSWORD` should not contain comma `,` or colon `:` characters, otherwise the connection to the database may fail.
|
||||||
@@ -269,22 +265,20 @@ The following database options can be configured:
|
|||||||
|
|
||||||
If running with a PostgreSQL database backend, the following additional options are available:
|
If running with a PostgreSQL database backend, the following additional options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_DB_TIMEOUT", default="2") }} Database connection timeout (s) |
|
||||||
| INVENTREE_DB_TIMEOUT | database.timeout | Database connection timeout (s) | 2 |
|
| `INVENTREE_DB_TCP_KEEPALIVES` | database.tcp_keepalives | 1 | TCP keepalive |
|
||||||
| INVENTREE_DB_TCP_KEEPALIVES | database.tcp_keepalives | TCP keepalive | 1 |
|
| `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 1 | Idle TCP keepalive |
|
||||||
| INVENTREE_DB_TCP_KEEPALIVES_IDLE | database.tcp_keepalives_idle | Idle TCP keepalive | 1 |
|
| `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 1| TCP keepalive interval |
|
||||||
| INVENTREE_DB_TCP_KEEPALIVES_INTERVAL | database.tcp_keepalives_interval | TCP keepalive interval | 1|
|
| `INVENTREE_DB_TCP_KEEPALIVES_COUNT` | database.tcp_keepalives_count | 5 | TCP keepalive count |
|
||||||
| INVENTREE_DB_TCP_KEEPALIVES_COUNT | database.tcp_keepalives_count | TCP keepalive count | 5 |
|
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||||
| INVENTREE_DB_ISOLATION_SERIALIZABLE | database.serializable | Database isolation level configured to "serializable" | False |
|
|
||||||
|
|
||||||
### MySQL Settings
|
### MySQL Settings
|
||||||
|
|
||||||
If running with a MySQL database backend, the following additional options are available:
|
If running with a MySQL database backend, the following additional options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||||
| INVENTREE_DB_ISOLATION_SERIALIZABLE | database.serializable | Database isolation level configured to "serializable" | False |
|
|
||||||
|
|
||||||
### SQLite Settings
|
### SQLite Settings
|
||||||
|
|
||||||
@@ -293,10 +287,9 @@ If running with a MySQL database backend, the following additional options are a
|
|||||||
|
|
||||||
If running with a SQLite database backend, the following additional options are available:
|
If running with a SQLite database backend, the following additional options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
|
||||||
| INVENTREE_DB_TIMEOUT | database.timeout | Database connection timeout (s) | 10 |
|
| `INVENTREE_DB_WAL_MODE` | database.wal_mode | True | Enable Write-Ahead Logging (WAL) mode for SQLite databases |
|
||||||
| INVENTREE_DB_WAL_MODE | database.wal_mode | Enable Write-Ahead Logging (WAL) mode for SQLite databases | True |
|
|
||||||
|
|
||||||
## Caching
|
## Caching
|
||||||
|
|
||||||
@@ -314,21 +307,21 @@ Enabling global caching requires connection to a redis server (which is separate
|
|||||||
|
|
||||||
The following cache settings are available:
|
The following cache settings are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_CACHE_ENABLED") }} Enable redis caching |
|
||||||
| INVENTREE_CACHE_ENABLED | cache.enabled | Enable redis caching | False |
|
{{ configsetting("INVENTREE_CACHE_HOST") }} Cache server host |
|
||||||
| INVENTREE_CACHE_HOST | cache.host | Cache server host | *Not specified* |
|
{{ configsetting("INVENTREE_CACHE_PORT") }} Cache server port |
|
||||||
| INVENTREE_CACHE_PORT | cache.port | Cache server port | 6379 |
|
{{ configsetting("INVENTREE_CACHE_PASSWORD") }} Cache server password |
|
||||||
| INVENTREE_CACHE_PASSWORD | cache.password | Cache server password | none |
|
{{ configsetting("INVENTREE_CACHE_USER") }} Cache server username |
|
||||||
| INVENTREE_CACHE_USER | cache.user | Cache server username | none |
|
{{ configsetting("INVENTREE_CACHE_DB") }} Cache server database index |
|
||||||
| INVENTREE_CACHE_DB | cache.db | Cache server database index | 0 |
|
{{ configsetting("INVENTREE_CACHE_CONNECT_TIMEOUT") }} Cache connection timeout (seconds) |
|
||||||
| INVENTREE_CACHE_CONNECT_TIMEOUT | cache.connect_timeout | Cache connection timeout (seconds) | 3 |
|
{{ configsetting("INVENTREE_CACHE_TIMEOUT") }} Cache timeout (seconds) |
|
||||||
| INVENTREE_CACHE_TIMEOUT | cache.timeout | Cache timeout (seconds) | 3 |
|
{{ configsetting("INVENTREE_CACHE_TCP_KEEPALIVE") }} Cache TCP keepalive |
|
||||||
| INVENTREE_CACHE_TCP_KEEPALIVE | cache.tcp_keepalive | Cache TCP keepalive | True |
|
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_COUNT") }} Cache keepalive count |
|
||||||
| INVENTREE_CACHE_KEEPALIVE_COUNT | cache.keepalive_count | Cache keepalive count | 5 |
|
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_IDLE") }} Cache keepalive idle |
|
||||||
| INVENTREE_CACHE_KEEPALIVE_IDLE | cache.keepalive_idle | Cache keepalive idle | 1 |
|
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_INTERVAL") }} Cache keepalive interval |
|
||||||
| INVENTREE_CACHE_KEEPALIVE_INTERVAL | cache.keepalive_interval | Cache keepalive interval | 1 |
|
{{ configsetting("INVENTREE_CACHE_USER_TIMEOUT") }} Cache user timeout |
|
||||||
| INVENTREE_CACHE_USER_TIMEOUT | cache.user_timeout | Cache user timeout | 1000 |
|
|
||||||
|
|
||||||
!!! tip "Cache Password"
|
!!! tip "Cache Password"
|
||||||
The value specified for `INVENTREE_CACHE_PASSWORD` should not contain comma `,` or colon `:` characters, otherwise the connection to the cache server may fail.
|
The value specified for `INVENTREE_CACHE_PASSWORD` should not contain comma `,` or colon `:` characters, otherwise the connection to the cache server may fail.
|
||||||
@@ -339,17 +332,16 @@ To enable [email functionality](../settings/email.md), email settings must be co
|
|||||||
|
|
||||||
The following email settings are available:
|
The following email settings are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_EMAIL_BACKEND") }} Email backend module |
|
||||||
| INVENTREE_EMAIL_BACKEND | email.backend | Email backend module | django.core.mail.backends.smtp.EmailBackend |
|
{{ configsetting("INVENTREE_EMAIL_HOST") }} Email server host |
|
||||||
| INVENTREE_EMAIL_HOST | email.host | Email server host | *Not specified* |
|
{{ configsetting("INVENTREE_EMAIL_PORT") }} Email server port |
|
||||||
| INVENTREE_EMAIL_PORT | email.port | Email server port | 25 |
|
{{ configsetting("INVENTREE_EMAIL_USERNAME") }} Email account username |
|
||||||
| INVENTREE_EMAIL_USERNAME | email.username | Email account username | *Not specified* |
|
{{ configsetting("INVENTREE_EMAIL_PASSWORD") }} Email account password |
|
||||||
| INVENTREE_EMAIL_PASSWORD | email.password | Email account password | *Not specified* |
|
{{ configsetting("INVENTREE_EMAIL_TLS") }} Enable STARTTLS support (commonly port 567) |
|
||||||
| INVENTREE_EMAIL_TLS | email.tls | Enable STARTTLS support (commonly port 567) | False |
|
{{ configsetting("INVENTREE_EMAIL_SSL") }} Enable legacy SSL/TLS support (commonly port 465) |
|
||||||
| INVENTREE_EMAIL_SSL | email.ssl | Enable legacy SSL/TLS support (commonly port 465) | False |
|
{{ configsetting("INVENTREE_EMAIL_SENDER") }} Sending email address |
|
||||||
| INVENTREE_EMAIL_SENDER | email.sender | Sending email address | *Not specified* |
|
{{ configsetting("INVENTREE_EMAIL_PREFIX") }} Prefix for subject text |
|
||||||
| INVENTREE_EMAIL_PREFIX | email.prefix | Prefix for subject text | [InvenTree] |
|
|
||||||
|
|
||||||
### Email Backend
|
### Email Backend
|
||||||
|
|
||||||
@@ -366,11 +358,10 @@ The "sender" email address is the address from which InvenTree emails are sent (
|
|||||||
|
|
||||||
InvenTree requires some external directories for storing files:
|
InvenTree requires some external directories for storing files:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_STATIC_ROOT") }} [Static files](./processes.md#static-files) directory |
|
||||||
| INVENTREE_STATIC_ROOT | static_root | [Static files](./processes.md#static-files) directory | *Not specified* |
|
{{ configsetting("INVENTREE_MEDIA_ROOT") }} [Media files](./processes.md#media-files) directory |
|
||||||
| INVENTREE_MEDIA_ROOT | media_root | [Media files](./processes.md#media-files) directory | *Not specified* |
|
{{ configsetting("INVENTREE_BACKUP_DIR") }} Directory for backup files |
|
||||||
| INVENTREE_BACKUP_DIR | backup_dir | Backup files directory | *Not specified* |
|
|
||||||
|
|
||||||
!!! tip "Serving Files"
|
!!! tip "Serving Files"
|
||||||
Read the [proxy server documentation](./processes.md#proxy-server) for more information on hosting *static* and *media* files
|
Read the [proxy server documentation](./processes.md#proxy-server) for more information on hosting *static* and *media* files
|
||||||
@@ -404,43 +395,41 @@ Alternatively this location can be specified with the `INVENTREE_BACKUP_DIR` env
|
|||||||
|
|
||||||
It is also possible to use alternative storage backends for static and media files, at the moment there is direct provide direct support bundled for S3 and SFTP. Google cloud storage and Azure blob storage would also be supported by the [used library](https://django-storages.readthedocs.io), but require additional packages to be installed.
|
It is also possible to use alternative storage backends for static and media files, at the moment there is direct provide direct support bundled for S3 and SFTP. Google cloud storage and Azure blob storage would also be supported by the [used library](https://django-storages.readthedocs.io), but require additional packages to be installed.
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_STORAGE_TARGET") }} Storage target to use for static and media files, valid options: local, s3, sftp |
|
||||||
| INVENTREE_STORAGE_TARGET | storage.target | Storage target to use for static and media files, valid options: local, s3, sftp | local |
|
|
||||||
|
|
||||||
#### S3
|
#### S3
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
| `INVENTREE_S3_ACCESS_KEY` | storage.s3.access_key | *Not specified* | Access key |
|
||||||
| INVENTREE_S3_ACCESS_KEY | storage.s3.access_key | Access key | *Not specified* |
|
| `INVENTREE_S3_SECRET_KEY` | storage.s3.secret_key | *Not specified* | Secret key |
|
||||||
| INVENTREE_S3_SECRET_KEY | storage.s3.secret_key | Secret key | *Not specified* |
|
| `INVENTREE_S3_BUCKET_NAME` | storage.s3.bucket_name | *Not specified* | Bucket name, required by most providers |
|
||||||
| INVENTREE_S3_BUCKET_NAME | storage.s3.bucket_name | Bucket name, required by most providers | *Not specified* |
|
| `INVENTREE_S3_REGION_NAME` | storage.s3.region_name | *Not specified* | S3 region name |
|
||||||
| INVENTREE_S3_REGION_NAME | storage.s3.region_name | S3 region name | *Not specified* |
|
| `INVENTREE_S3_ENDPOINT_URL` | storage.s3.endpoint_url | *Not specified* | Custom S3 endpoint URL, defaults to AWS endpoints if not set |
|
||||||
| INVENTREE_S3_ENDPOINT_URL | storage.s3.endpoint_url | Custom S3 endpoint URL, defaults to AWS endpoints if not set | *Not specified* |
|
| `INVENTREE_S3_LOCATION` | storage.s3.location | inventree-server | Sub-Location that should be used |
|
||||||
| INVENTREE_S3_LOCATION | storage.s3.location | Sub-Location that should be used | inventree-server |
|
| `INVENTREE_S3_DEFAULT_ACL` | storage.s3.default_acl | *Not specified* | Default ACL for uploaded files, defaults to provider default if not set |
|
||||||
| INVENTREE_S3_DEFAULT_ACL | storage.s3.default_acl | Default ACL for uploaded files, defaults to provider default if not set | *Not specified* |
|
| `INVENTREE_S3_VERIFY_SSL` | storage.s3.verify_ssl | True | Verify SSL certificate for S3 endpoint |
|
||||||
| INVENTREE_S3_VERIFY_SSL | storage.s3.verify_ssl | Verify SSL certificate for S3 endpoint | True |
|
| `INVENTREE_S3_OVERWRITE` | storage.s3.overwrite | False | Overwrite existing files in S3 bucket |
|
||||||
| INVENTREE_S3_OVERWRITE | storage.s3.overwrite | Overwrite existing files in S3 bucket | False |
|
| `INVENTREE_S3_VIRTUAL` | storage.s3.virtual | False | Use virtual addressing style - by default False -> `path` style, `virtual` style if True |
|
||||||
| INVENTREE_S3_VIRTUAL | storage.s3.virtual | Use virtual addressing style - by default False -> `path` style, `virtual` style if True | False |
|
|
||||||
|
|
||||||
#### SFTP
|
#### SFTP
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
| `INVENTREE_SFTP_HOST` | storage.sftp.host | *Not specified* | SFTP host |
|
||||||
| INVENTREE_SFTP_HOST | storage.sftp.host | SFTP host | *Not specified* |
|
| `INVENTREE_SFTP_PARAMS` | storage.sftp.params | *Not specified* | SFTP connection parameters, see https://docs.paramiko.org/en/latest/api/client.html#paramiko.client.SSHClient.connect; e.g. `{'port': 22, 'user': 'usr', 'password': 'pwd'}` |
|
||||||
| INVENTREE_SFTP_PARAMS | storage.sftp.params | SFTP connection parameters, see https://docs.paramiko.org/en/latest/api/client.html#paramiko.client.SSHClient.connect; e.g. `{'port': 22, 'user': 'usr', 'password': 'pwd'}` | *Not specified* |
|
| `INVENTREE_SFTP_UID` | storage.sftp.uid | *Not specified* | SFTP user ID - not required |
|
||||||
| INVENTREE_SFTP_UID | storage.sftp.uid | SFTP user ID - not required | *Not specified* |
|
| `INVENTREE_SFTP_GID` | storage.sftp.gid | *Not specified* | SFTP group ID - not required |
|
||||||
| INVENTREE_SFTP_GID | storage.sftp.gid | SFTP group ID - not required | *Not specified* |
|
| `INVENTREE_SFTP_LOCATION` | storage.sftp.location | inventree-server | Sub-Location that should be used |
|
||||||
| INVENTREE_SFTP_LOCATION | storage.sftp.location | Sub-Location that should be used | inventree-server |
|
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
InvenTree provides allowance for additional sign-in options. The following options are not enabled by default, and care must be taken by the system administrator when configuring these settings.
|
InvenTree provides allowance for additional sign-in options. The following options are not enabled by default, and care must be taken by the system administrator when configuring these settings.
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_MFA_ENABLED") }} Enable multi-factor authentication support for the InvenTree server |
|
||||||
| INVENTREE_MFA_ENABLED | mfa_enabled | Enable or disable multi-factor authentication support for the InvenTree server | True |
|
{{ configsetting("INVENTREE_MFA_SUPPORTED_TYPES") }} List of supported multi-factor authentication types |
|
||||||
| INVENTREE_MFA_SUPPORTED_TYPES | mfa_supported_types | List of supported multi-factor authentication types | recovery_codes,totp,webauthn |
|
{{ configsetting("INVENTREE_USE_JWT") }} Enable support for JSON Web Tokens (JWT) for authentication |
|
||||||
|
|
||||||
### Single Sign On
|
### Single Sign On
|
||||||
|
|
||||||
@@ -455,11 +444,10 @@ There are multiple configuration parameters which must be specified (either in y
|
|||||||
|
|
||||||
The login-experience can be altered with the following settings:
|
The login-experience can be altered with the following settings:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_LOGIN_CONFIRM_DAYS") }} Duration for which confirmation links are valid |
|
||||||
| INVENTREE_LOGIN_CONFIRM_DAYS | login_confirm_days | Duration for which confirmation links are valid | 3 |
|
{{ configsetting("INVENTREE_LOGIN_ATTEMPTS") }} Count of allowed login attempts before blocking user |
|
||||||
| INVENTREE_LOGIN_ATTEMPTS | login_attempts | Count of allowed login attempts before blocking user | 5 |
|
{{ configsetting("INVENTREE_LOGIN_DEFAULT_HTTP_PROTOCOL", default="Uses the protocol specified in `INVENTREE_SITE_URL`, or defaults to *http*") }} Default protocol to use for login callbacks (e.g. using [SSO](#single-sign-on)) |
|
||||||
| INVENTREE_LOGIN_DEFAULT_HTTP_PROTOCOL | login_default_protocol | Default protocol to use for login callbacks (e.g. using [SSO](#single-sign-on)) | Uses the protocol specified in `INVENTREE_SITE_URL`, or defaults to *http* |
|
|
||||||
|
|
||||||
!!! tip "Default Protocol"
|
!!! tip "Default Protocol"
|
||||||
If you have specified `INVENTREE_SITE_URL`, the default protocol will be used from that setting. Otherwise, the default protocol will be *http*.
|
If you have specified `INVENTREE_SITE_URL`, the default protocol will be used from that setting. Otherwise, the default protocol will be *http*.
|
||||||
@@ -472,22 +460,20 @@ Custom authentication backends can be used by specifying them here. These can fo
|
|||||||
|
|
||||||
The following options are available for configuring the InvenTree [background worker process](./processes.md#background-worker):
|
The following options are available for configuring the InvenTree [background worker process](./processes.md#background-worker):
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_BACKGROUND_WORKERS") }} Number of background worker processes |
|
||||||
| INVENTREE_BACKGROUND_WORKERS | background.workers | Number of background worker processes | 1 |
|
{{ configsetting("INVENTREE_BACKGROUND_TIMEOUT") }} Timeout for background worker tasks (seconds) |
|
||||||
| INVENTREE_BACKGROUND_TIMEOUT | background.timeout | Timeout for background worker tasks (seconds) | 90 |
|
{{ configsetting("INVENTREE_BACKGROUND_RETRY") }} Time to wait before retrying a background task (seconds) |
|
||||||
| INVENTREE_BACKGROUND_RETRY | background.retry | Time to wait before retrying a background task (seconds) | 300 |
|
{{ configsetting("INVENTREE_BACKGROUND_MAX_ATTEMPTS") }} Maximum number of attempts for a background task |
|
||||||
| INVENTREE_BACKGROUND_MAX_ATTEMPTS | background.max_attempts | Maximum number of attempts for a background task | 5 |
|
|
||||||
|
|
||||||
## Sentry Integration
|
## Sentry Integration
|
||||||
|
|
||||||
The InvenTree server can be integrated with the [sentry.io](https://sentry.io) monitoring service, for error logging and performance tracking.
|
The InvenTree server can be integrated with the [sentry.io](https://sentry.io) monitoring service, for error logging and performance tracking.
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_SENTRY_ENABLED") }} Enable sentry.io integration |
|
||||||
| INVENTREE_SENTRY_ENABLED | sentry_enabled | Enable sentry.io integration | False |
|
{{ configsetting("INVENTREE_SENTRY_DSN", default="Defaults to InvenTree developer key") }} Sentry DSN (data source name) key |
|
||||||
| INVENTREE_SENTRY_DSN | sentry_dsn | Sentry DSN (data source name) key | *Defaults to InvenTree developer key* |
|
{{ configsetting("INVENTREE_SENTRY_SAMPLE_RATE") }} How often to send data samples (seconds) |
|
||||||
| INVENTREE_SENTRY_SAMPLE_RATE | sentry_sample_rate | How often to send data samples | 0.1 |
|
|
||||||
|
|
||||||
!!! info "Default DSN"
|
!!! info "Default DSN"
|
||||||
If enabled with the default DSN, server errors will be logged to a sentry.io account monitored by the InvenTree developers.
|
If enabled with the default DSN, server errors will be logged to a sentry.io account monitored by the InvenTree developers.
|
||||||
@@ -496,13 +482,11 @@ The InvenTree server can be integrated with the [sentry.io](https://sentry.io) m
|
|||||||
|
|
||||||
The logo and custom messages can be changed/set:
|
The logo and custom messages can be changed/set:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_CUSTOM_LOGO") }} Path to custom logo in the static files directory |
|
||||||
| INVENTREE_CUSTOM_LOGO | customize.logo | Path to custom logo in the static files directory | *Not specified* |
|
{{ configsetting("INVENTREE_CUSTOM_SPLASH") }} Path to custom splash screen in the static files directory |
|
||||||
| INVENTREE_CUSTOM_SPLASH | customize.splash | Path to custom splash screen in the static files directory | *Not specified* |
|
{{ configsetting("INVENTREE_SITE_HEADER") }} Custom header text for the django admin page |
|
||||||
| INVENTREE_CUSTOMIZE | customize.site_header | Custom site header in the Django admin | InvenTree Admin |
|
{{ configsetting("INVENTREE_CUSTOMIZE") }} JSON object containing custom messages for the login page, navbar, and Django admin site |
|
||||||
| INVENTREE_CUSTOMIZE | customize.login_message | Custom message for login page | *Not specified* |
|
|
||||||
| INVENTREE_CUSTOMIZE | customize.navbar_message | Custom message for navbar | *Not specified* |
|
|
||||||
|
|
||||||
The INVENTREE_CUSTOMIZE environment variable must contain a json object with the keys from the table above and
|
The INVENTREE_CUSTOMIZE environment variable must contain a json object with the keys from the table above and
|
||||||
the wanted values. Example:
|
the wanted values. Example:
|
||||||
@@ -547,15 +531,15 @@ INVENTREE_FRONTEND_SETTINGS='{"mobile_mode": "allow-ignore"}'
|
|||||||
|
|
||||||
The following [plugin](../plugins/index.md) configuration options are available:
|
The following [plugin](../plugins/index.md) configuration options are available:
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_PLUGINS_ENABLED") }} Enable plugin support |
|
||||||
| INVENTREE_PLUGINS_ENABLED | plugins_enabled | Enable plugin support | False |
|
{{ configsetting("INVENTREE_PLUGIN_NOINSTALL") }} Disable Plugin installation via API |
|
||||||
| INVENTREE_PLUGIN_NOINSTALL | plugin_noinstall | Disable Plugin installation via API - only use plugins.txt file | False |
|
{{ configsetting("INVENTREE_PLUGIN_FILE") }} Location of plugin installation file |
|
||||||
| INVENTREE_PLUGIN_FILE | plugins_plugin_file | Location of plugin installation file | *Not specified* |
|
| `INVENTREE_PLUGIN_DIR` | `plugin_dir` | *Not specified* | Location of external plugin directory |
|
||||||
| INVENTREE_PLUGIN_DIR | plugins_plugin_dir | Location of external plugin directory | *Not specified* |
|
{{ configsetting("INVENTREE_PLUGIN_RETRY") }} Number of tries to attempt loading a plugin before giving up |
|
||||||
| INVENTREE_PLUGINS_MANDATORY | plugins_mandatory | List of [plugins which are considered mandatory](../plugins/index.md#mandatory-third-party-plugins) | *Not specified* |
|
{{ configsetting("INVENTREE_PLUGINS_MANDATORY") }} List of [plugins which are considered mandatory](../plugins/index.md#mandatory-third-party-plugins) |
|
||||||
| INVENTREE_PLUGIN_DEV_SLUG | plugin_dev.slug | Specify plugin to run in [development mode](../plugins/creator.md#backend-configuration) | *Not specified* |
|
{{ configsetting("INVENTREE_PLUGIN_DEV_SLUG") }} Specify plugin to run in [development mode](../plugins/creator.md#backend-configuration) |
|
||||||
| INVENTREE_PLUGIN_DEV_HOST | plugin_dev.host | Specify host for development mode plugin | http://localhost:5174 |
|
{{ configsetting("INVENTREE_PLUGIN_DEV_HOST") }} Specify host for development mode plugin |
|
||||||
|
|
||||||
## Override Global Settings
|
## Override Global Settings
|
||||||
|
|
||||||
@@ -563,6 +547,12 @@ If required, [global settings values](../settings/global.md#override-global-sett
|
|||||||
|
|
||||||
To override global settings, provide a "dictionary" of settings overrides in the configuration file, or via an environment variable.
|
To override global settings, provide a "dictionary" of settings overrides in the configuration file, or via an environment variable.
|
||||||
|
|
||||||
| Environment Variable | Configuration File | Description | Default |
|
{{ configtable() }}
|
||||||
| --- | --- | --- | --- |
|
{{ configsetting("INVENTREE_GLOBAL_SETTINGS") }} JSON object containing global settings overrides |
|
||||||
| INVENTREE_GLOBAL_SETTINGS | global_settings | JSON object containing global settings overrides | *Not specified* |
|
|
||||||
|
## Other Settings
|
||||||
|
|
||||||
|
Other available settings, not categorized above, are detailed in the table below:
|
||||||
|
|
||||||
|
{{ configtable() }}
|
||||||
|
{{ configsetting("INVENTREE_EXTRA_URL_SCHEMES") }} Allow additional URL schemes for URL validation |
|
||||||
|
|||||||
@@ -87,13 +87,7 @@ If you are creating the initial database, you need to create an admin (superuser
|
|||||||
docker compose run inventree-server invoke superuser
|
docker compose run inventree-server invoke superuser
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, admin account details can be specified in the `.env` file, removing the need for this manual step:
|
Alternatively, admin account details can be specified using environment variables, or in the `.env` file, removing the need for this manual step. Refer to the [configuration documentation](./config.md#administrator-account) for more information.
|
||||||
|
|
||||||
| Variable | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| INVENTREE_ADMIN_USER | Admin account username |
|
|
||||||
| INVENTREE_ADMIN_PASSWORD | Admin account password |
|
|
||||||
| INVENTREE_ADMIN_EMAIL | Admin account email address |
|
|
||||||
|
|
||||||
!!! warning "Scrub Account Data"
|
!!! warning "Scrub Account Data"
|
||||||
Ensure that the admin account credentials are removed from the `.env` file after the first run, for security.
|
Ensure that the admin account credentials are removed from the `.env` file after the first run, for security.
|
||||||
@@ -242,8 +236,8 @@ This can be adjusted using the following environment variables:
|
|||||||
|
|
||||||
| Environment Variable | Default |
|
| Environment Variable | Default |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| INVENTREE_WEB_ADDR | 0.0.0.0 |
|
| `INVENTREE_WEB_ADDR` | 0.0.0.0 |
|
||||||
| INVENTREE_WEB_PORT | 8000 |
|
| `INVENTREE_WEB_PORT` | 8000 |
|
||||||
|
|
||||||
These variables are combined in the [Dockerfile]({{ sourcefile("contrib/container/Dockerfile") }}) to build the bind string passed to the InvenTree server on startup.
|
These variables are combined in the [Dockerfile]({{ sourcefile("contrib/container/Dockerfile") }}) to build the bind string passed to the InvenTree server on startup.
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ for key in [
|
|||||||
print(f' - {key}: {val}')
|
print(f' - {key}: {val}')
|
||||||
|
|
||||||
# Cached settings dict values
|
# Cached settings dict values
|
||||||
|
global CONFIG_SETTINGS
|
||||||
global GLOBAL_SETTINGS
|
global GLOBAL_SETTINGS
|
||||||
global USER_SETTINGS
|
global USER_SETTINGS
|
||||||
global TAGS
|
global TAGS
|
||||||
@@ -64,6 +65,7 @@ with open(settings_file, encoding='utf-8') as sf:
|
|||||||
|
|
||||||
GLOBAL_SETTINGS = settings['global']
|
GLOBAL_SETTINGS = settings['global']
|
||||||
USER_SETTINGS = settings['user']
|
USER_SETTINGS = settings['user']
|
||||||
|
CONFIG_SETTINGS = settings['config']
|
||||||
|
|
||||||
# Tags
|
# Tags
|
||||||
with open(gen_base.joinpath('inventree_tags.yml'), encoding='utf-8') as f:
|
with open(gen_base.joinpath('inventree_tags.yml'), encoding='utf-8') as f:
|
||||||
@@ -377,6 +379,34 @@ def define_env(env):
|
|||||||
|
|
||||||
return rendersetting(key, setting, short=short)
|
return rendersetting(key, setting, short=short)
|
||||||
|
|
||||||
|
@env.macro
|
||||||
|
def configtable():
|
||||||
|
"""Generate a header for the configuration settings table."""
|
||||||
|
return '| Environment Variable | Configuration File | Default | Description |\n| --- | --- | --- | --- |'
|
||||||
|
|
||||||
|
@env.macro
|
||||||
|
def configsetting(key: str, default: Optional[str] = None):
|
||||||
|
"""Extract information on a particular configuration setting.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
key: The name of the configuration setting to extract information for.
|
||||||
|
default: An optional default value to override the setting's default display value.
|
||||||
|
"""
|
||||||
|
global CONFIG_SETTINGS
|
||||||
|
setting = CONFIG_SETTINGS[key]
|
||||||
|
|
||||||
|
observe_setting(key, 'config')
|
||||||
|
|
||||||
|
cfg_key = setting.get('config_key', None)
|
||||||
|
cfg_key = f'`{cfg_key}`' if cfg_key else '-'
|
||||||
|
|
||||||
|
default = default or setting.get('default_value', None)
|
||||||
|
|
||||||
|
if default is None:
|
||||||
|
default = '*Not Specified*'
|
||||||
|
|
||||||
|
return f'| <span title="{key}" style="white-space: nowrap;"><code>{key}</code></span> | {cfg_key} | {default} |'
|
||||||
|
|
||||||
@env.macro
|
@env.macro
|
||||||
def tags_and_filters():
|
def tags_and_filters():
|
||||||
"""Return a list of all tags and filters."""
|
"""Return a list of all tags and filters."""
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ class InfoView(APIView):
|
|||||||
'instance': InvenTree.version.inventreeInstanceName(),
|
'instance': InvenTree.version.inventreeInstanceName(),
|
||||||
'apiVersion': InvenTree.version.inventreeApiVersion(),
|
'apiVersion': InvenTree.version.inventreeApiVersion(),
|
||||||
'worker_running': is_worker_running(),
|
'worker_running': is_worker_running(),
|
||||||
'worker_count': settings.BACKGROUND_WORKER_COUNT,
|
'worker_count': settings.Q_CLUSTER['workers'],
|
||||||
'worker_pending_tasks': self.worker_pending_tasks(),
|
'worker_pending_tasks': self.worker_pending_tasks(),
|
||||||
'plugins_enabled': settings.PLUGINS_ENABLED,
|
'plugins_enabled': settings.PLUGINS_ENABLED,
|
||||||
'plugins_install_disabled': settings.PLUGINS_INSTALL_DISABLED,
|
'plugins_install_disabled': settings.PLUGINS_INSTALL_DISABLED,
|
||||||
|
|||||||
@@ -94,17 +94,17 @@ def get_cache_config(global_cache: bool) -> dict:
|
|||||||
Returns:
|
Returns:
|
||||||
A dictionary containing the cache configuration options.
|
A dictionary containing the cache configuration options.
|
||||||
"""
|
"""
|
||||||
if global_cache:
|
|
||||||
# Build Redis URL with optional password
|
# Build Redis URL with optional password
|
||||||
password = cache_password()
|
password = cache_password()
|
||||||
user = cache_user() or ''
|
user = cache_user() or ''
|
||||||
|
host = cache_host()
|
||||||
|
port = cache_port()
|
||||||
|
db = cache_db()
|
||||||
|
|
||||||
if password:
|
if password:
|
||||||
redis_url = (
|
redis_url = f'redis://{user}:{password}@{host}:{port}/{db}'
|
||||||
f'redis://{user}:{password}@{cache_host()}:{cache_port()}/{cache_db()}'
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
redis_url = f'redis://{cache_host()}:{cache_port()}/{cache_db()}'
|
redis_url = f'redis://{host}:{port}/{db}'
|
||||||
|
|
||||||
keepalive_options = {
|
keepalive_options = {
|
||||||
'TCP_KEEPCNT': cache_setting('keepalive_count', 5, typecast=int),
|
'TCP_KEEPCNT': cache_setting('keepalive_count', 5, typecast=int),
|
||||||
@@ -113,19 +113,15 @@ def get_cache_config(global_cache: bool) -> dict:
|
|||||||
'TCP_USER_TIMEOUT': cache_setting('user_timeout', 1000, typecast=int),
|
'TCP_USER_TIMEOUT': cache_setting('user_timeout', 1000, typecast=int),
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
global_cache_config = {
|
||||||
'BACKEND': 'django_redis.cache.RedisCache',
|
'BACKEND': 'django_redis.cache.RedisCache',
|
||||||
'LOCATION': redis_url,
|
'LOCATION': redis_url,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
||||||
'SOCKET_CONNECT_TIMEOUT': cache_setting(
|
'SOCKET_CONNECT_TIMEOUT': cache_setting('connect_timeout', 5, typecast=int),
|
||||||
'connect_timeout', 5, typecast=int
|
|
||||||
),
|
|
||||||
'SOCKET_TIMEOUT': cache_setting('timeout', 3, typecast=int),
|
'SOCKET_TIMEOUT': cache_setting('timeout', 3, typecast=int),
|
||||||
'CONNECTION_POOL_KWARGS': {
|
'CONNECTION_POOL_KWARGS': {
|
||||||
'socket_keepalive': cache_setting(
|
'socket_keepalive': cache_setting('tcp_keepalive', True, typecast=bool),
|
||||||
'tcp_keepalive', True, typecast=bool
|
|
||||||
),
|
|
||||||
'socket_keepalive_options': {
|
'socket_keepalive_options': {
|
||||||
# Only include options which are available on this platform
|
# Only include options which are available on this platform
|
||||||
# e.g. MacOS does not have TCP_KEEPIDLE and TCP_USER_TIMEOUT
|
# e.g. MacOS does not have TCP_KEEPIDLE and TCP_USER_TIMEOUT
|
||||||
@@ -137,6 +133,10 @@ def get_cache_config(global_cache: bool) -> dict:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if global_cache:
|
||||||
|
# Only return the global cache configuration if the global cache is enabled
|
||||||
|
return global_cache_config
|
||||||
|
else:
|
||||||
# Default: Use django local memory cache
|
# Default: Use django local memory cache
|
||||||
return {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}
|
return {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}
|
||||||
|
|
||||||
|
|||||||
@@ -270,10 +270,13 @@ def get_setting(env_var=None, config_key=None, default_value=None, typecast=None
|
|||||||
|
|
||||||
def set_metadata(source: str):
|
def set_metadata(source: str):
|
||||||
"""Set lookup metadata for the setting."""
|
"""Set lookup metadata for the setting."""
|
||||||
|
global CONFIG_LOOKUPS
|
||||||
|
|
||||||
key = env_var or config_key
|
key = env_var or config_key
|
||||||
CONFIG_LOOKUPS[key] = {
|
CONFIG_LOOKUPS[key] = {
|
||||||
'env_var': env_var,
|
'env_var': env_var,
|
||||||
'config_key': config_key,
|
'config_key': config_key,
|
||||||
|
'default_value': default_value,
|
||||||
'source': source,
|
'source': source,
|
||||||
'accessed': datetime.datetime.now(),
|
'accessed': datetime.datetime.now(),
|
||||||
}
|
}
|
||||||
@@ -544,13 +547,14 @@ def get_frontend_settings(debug=True):
|
|||||||
'INVENTREE_FRONTEND_SETTINGS', 'frontend_settings', {}, typecast=dict
|
'INVENTREE_FRONTEND_SETTINGS', 'frontend_settings', {}, typecast=dict
|
||||||
)
|
)
|
||||||
|
|
||||||
|
base_url = get_setting(
|
||||||
|
'INVENTREE_FRONTEND_URL_BASE', 'frontend_url_base', 'web', typecast=str
|
||||||
|
)
|
||||||
|
|
||||||
# Set the base URL for the user interface
|
# Set the base URL for the user interface
|
||||||
# This is the UI path e.g. '/web/'
|
# This is the UI path e.g. '/web/'
|
||||||
if 'base_url' not in frontend_settings:
|
if 'base_url' not in frontend_settings:
|
||||||
frontend_settings['base_url'] = (
|
frontend_settings['base_url'] = base_url
|
||||||
get_setting('INVENTREE_FRONTEND_URL_BASE', 'frontend_url_base', 'web')
|
|
||||||
or 'web'
|
|
||||||
)
|
|
||||||
|
|
||||||
# If provided, specify the API host
|
# If provided, specify the API host
|
||||||
api_host = frontend_settings.get('api_host', None) or get_setting(
|
api_host = frontend_settings.get('api_host', None) or get_setting(
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
"""Export settings information to a JSON file."""
|
"""Export settings information to a JSON file."""
|
||||||
from common.models import InvenTreeSetting, InvenTreeUserSetting
|
from common.models import InvenTreeSetting, InvenTreeUserSetting
|
||||||
|
from InvenTree.config import CONFIG_LOOKUPS
|
||||||
|
|
||||||
settings = {'global': {}, 'user': {}}
|
settings = {'global': {}, 'user': {}, 'config': {}}
|
||||||
|
|
||||||
# Global settings
|
# Global settings
|
||||||
for key, setting in InvenTreeSetting.SETTINGS.items():
|
for key, setting in InvenTreeSetting.SETTINGS.items():
|
||||||
@@ -45,6 +46,18 @@ class Command(BaseCommand):
|
|||||||
'units': str(setting.get('units', '')),
|
'units': str(setting.get('units', '')),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Configuration settings
|
||||||
|
for key, config in CONFIG_LOOKUPS.items():
|
||||||
|
default_value = config.get('default_value', None)
|
||||||
|
if default_value is not None:
|
||||||
|
default_value = str(default_value)
|
||||||
|
|
||||||
|
settings['config'][key] = {
|
||||||
|
'env_var': str(config.get('env_var', '')),
|
||||||
|
'config_key': str(config.get('config_key', '')),
|
||||||
|
'default_value': default_value,
|
||||||
|
}
|
||||||
|
|
||||||
filename = kwargs.get('filename', 'inventree_settings.json')
|
filename = kwargs.get('filename', 'inventree_settings.json')
|
||||||
|
|
||||||
with open(filename, 'w', encoding='utf-8') as f:
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
"""Configuration settings specific to a particular database backend."""
|
"""Configuration settings specific to a particular database backend."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
from InvenTree.config import get_boolean_setting, get_setting
|
from InvenTree.config import get_boolean_setting, get_setting
|
||||||
@@ -7,6 +9,62 @@ from InvenTree.config import get_boolean_setting, get_setting
|
|||||||
logger = structlog.get_logger('inventree')
|
logger = structlog.get_logger('inventree')
|
||||||
|
|
||||||
|
|
||||||
|
def get_db_backend():
|
||||||
|
"""Return the database backend configuration."""
|
||||||
|
db_config = {
|
||||||
|
'ENGINE': get_setting('INVENTREE_DB_ENGINE', 'database.engine', None),
|
||||||
|
'NAME': get_setting('INVENTREE_DB_NAME', 'database.name', None),
|
||||||
|
'USER': get_setting('INVENTREE_DB_USER', 'database.user', None),
|
||||||
|
'PASSWORD': get_setting('INVENTREE_DB_PASSWORD', 'database.password', None),
|
||||||
|
'HOST': get_setting('INVENTREE_DB_HOST', 'database.host', None),
|
||||||
|
'PORT': get_setting('INVENTREE_DB_PORT', 'database.port', 5432, typecast=int),
|
||||||
|
'OPTIONS': get_setting(
|
||||||
|
'INVENTREE_DB_OPTIONS', 'database.options', {}, typecast=dict
|
||||||
|
)
|
||||||
|
or {},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for required keys
|
||||||
|
required_keys = ['ENGINE', 'NAME']
|
||||||
|
|
||||||
|
for key in required_keys:
|
||||||
|
if not db_config[key]:
|
||||||
|
raise ValueError(
|
||||||
|
f'Missing required database configuration key: INVENTREE_DB_{key}'
|
||||||
|
)
|
||||||
|
|
||||||
|
DB_ENGINE = db_config['ENGINE'].lower()
|
||||||
|
|
||||||
|
# Correct common misspelling
|
||||||
|
if DB_ENGINE == 'sqlite':
|
||||||
|
DB_ENGINE = 'sqlite3' # pragma: no cover
|
||||||
|
|
||||||
|
if DB_ENGINE in ['sqlite3', 'postgresql', 'mysql']:
|
||||||
|
# Prepend the required python module string
|
||||||
|
DB_ENGINE = f'django.db.backends.{DB_ENGINE}'
|
||||||
|
db_config['ENGINE'] = DB_ENGINE
|
||||||
|
|
||||||
|
if 'sqlite' in DB_ENGINE:
|
||||||
|
db_name = str(Path(db_config['NAME']).resolve())
|
||||||
|
db_config['NAME'] = db_name
|
||||||
|
|
||||||
|
logger.info('DB_ENGINE: %s', DB_ENGINE)
|
||||||
|
logger.info('DB_NAME: %s', db_config['NAME'])
|
||||||
|
logger.info('DB_HOST: %s', db_config.get('HOST', "''"))
|
||||||
|
|
||||||
|
# Set testing options for the database
|
||||||
|
db_config['TEST'] = {'CHARSET': 'utf8'}
|
||||||
|
|
||||||
|
# Set collation option for mysql test database
|
||||||
|
if 'mysql' in DB_ENGINE:
|
||||||
|
db_config['TEST']['COLLATION'] = 'utf8_general_ci' # pragma: no cover
|
||||||
|
|
||||||
|
# Specify database specific configuration
|
||||||
|
set_db_options(DB_ENGINE, db_config['OPTIONS'])
|
||||||
|
|
||||||
|
return db_config
|
||||||
|
|
||||||
|
|
||||||
def set_db_options(engine: str, db_options: dict):
|
def set_db_options(engine: str, db_options: dict):
|
||||||
"""Update database options based on the specified database backend.
|
"""Update database options based on the specified database backend.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
"""Configuration of LDAP support for InvenTree."""
|
||||||
|
|
||||||
|
from InvenTree.config import get_boolean_setting, get_setting
|
||||||
|
|
||||||
|
|
||||||
|
def get_ldap_config(debug: bool = False) -> dict:
|
||||||
|
"""Return a dictionary of LDAP configuration settings.
|
||||||
|
|
||||||
|
The returned settings will be updated into the globals() object,
|
||||||
|
and will be used to configure the LDAP authentication backend.
|
||||||
|
"""
|
||||||
|
import django_auth_ldap.config # type: ignore[unresolved-import]
|
||||||
|
import ldap # type: ignore[unresolved-import]
|
||||||
|
|
||||||
|
# get global options from dict and use ldap.OPT_* as keys and values
|
||||||
|
global_options_dict = get_setting(
|
||||||
|
'INVENTREE_LDAP_GLOBAL_OPTIONS',
|
||||||
|
'ldap.global_options',
|
||||||
|
default_value=None,
|
||||||
|
typecast=dict,
|
||||||
|
)
|
||||||
|
|
||||||
|
global_options = {}
|
||||||
|
|
||||||
|
for k, v in global_options_dict.items():
|
||||||
|
# keys are always ldap.OPT_* constants
|
||||||
|
k_attr = getattr(ldap, k, None)
|
||||||
|
if not k.startswith('OPT_') or k_attr is None:
|
||||||
|
print(f"[LDAP] ldap.global_options, key '{k}' not found, skipping...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# values can also be other strings, e.g. paths
|
||||||
|
v_attr = v
|
||||||
|
if v.startswith('OPT_'):
|
||||||
|
v_attr = getattr(ldap, v, None)
|
||||||
|
|
||||||
|
if v_attr is None:
|
||||||
|
print(f"[LDAP] ldap.global_options, value key '{v}' not found, skipping...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
global_options[k_attr] = v_attr
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('[LDAP] ldap.global_options =', global_options)
|
||||||
|
|
||||||
|
group_type_class = get_setting(
|
||||||
|
'INVENTREE_LDAP_GROUP_TYPE_CLASS',
|
||||||
|
'ldap.group_type_class',
|
||||||
|
'GroupOfUniqueNamesType',
|
||||||
|
str,
|
||||||
|
)
|
||||||
|
|
||||||
|
group_type_class_args = get_setting(
|
||||||
|
'INVENTREE_LDAP_GROUP_TYPE_CLASS_ARGS', 'ldap.group_type_class_args', [], list
|
||||||
|
)
|
||||||
|
|
||||||
|
group_type_class_kwargs = get_setting(
|
||||||
|
'INVENTREE_LDAP_GROUP_TYPE_CLASS_KWARGS',
|
||||||
|
'ldap.group_type_class_kwargs',
|
||||||
|
{'name_attr': 'cn'},
|
||||||
|
dict,
|
||||||
|
)
|
||||||
|
|
||||||
|
group_object_class = get_setting(
|
||||||
|
'INVENTREE_LDAP_GROUP_OBJECT_CLASS',
|
||||||
|
'ldap.group_object_class',
|
||||||
|
'groupOfUniqueNames',
|
||||||
|
str,
|
||||||
|
)
|
||||||
|
|
||||||
|
ldap_config = {
|
||||||
|
'AUTH_LDAP_GLOBAL_OPTIONS': global_options,
|
||||||
|
'AUTH_LDAP_SERVER_URI': get_setting(
|
||||||
|
'INVENTREE_LDAP_SERVER_URI', 'ldap.server_uri'
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_START_TLS': get_boolean_setting(
|
||||||
|
'INVENTREE_LDAP_START_TLS', 'ldap.start_tls', False
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_BIND_DN': get_setting('INVENTREE_LDAP_BIND_DN', 'ldap.bind_dn'),
|
||||||
|
'AUTH_LDAP_BIND_PASSWORD': get_setting(
|
||||||
|
'INVENTREE_LDAP_BIND_PASSWORD', 'ldap.bind_password'
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_USER_SEARCH': django_auth_ldap.config.LDAPSearch(
|
||||||
|
get_setting('INVENTREE_LDAP_SEARCH_BASE_DN', 'ldap.search_base_dn'),
|
||||||
|
ldap.SCOPE_SUBTREE,
|
||||||
|
str(
|
||||||
|
get_setting(
|
||||||
|
'INVENTREE_LDAP_SEARCH_FILTER_STR',
|
||||||
|
'ldap.search_filter_str',
|
||||||
|
'(uid= %(user)s)',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_USER_DN_TEMPLATE': get_setting(
|
||||||
|
'INVENTREE_LDAP_USER_DN_TEMPLATE', 'ldap.user_dn_template'
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_USER_ATTR_MAP': get_setting(
|
||||||
|
'INVENTREE_LDAP_USER_ATTR_MAP',
|
||||||
|
'ldap.user_attr_map',
|
||||||
|
{'first_name': 'givenName', 'last_name': 'sn', 'email': 'mail'},
|
||||||
|
dict,
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_ALWAYS_UPDATE_USER': get_boolean_setting(
|
||||||
|
'INVENTREE_LDAP_ALWAYS_UPDATE_USER', 'ldap.always_update_user', True
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_CACHE_TIMEOUT': get_setting(
|
||||||
|
'INVENTREE_LDAP_CACHE_TIMEOUT', 'ldap.cache_timeout', 3600, int
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_MIRROR_GROUPS': get_boolean_setting(
|
||||||
|
'INVENTREE_LDAP_MIRROR_GROUPS', 'ldap.mirror_groups', False
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_GROUP_OBJECT_CLASS': group_object_class,
|
||||||
|
'AUTH_LDAP_GROUP_SEARCH': django_auth_ldap.config.LDAPSearch(
|
||||||
|
get_setting('INVENTREE_LDAP_GROUP_SEARCH', 'ldap.group_search'),
|
||||||
|
ldap.SCOPE_SUBTREE,
|
||||||
|
f'(objectClass={group_object_class})',
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_GROUP_TYPE_CLASS': group_type_class,
|
||||||
|
'AUTH_LDAP_GROUP_TYPE_CLASS_ARGS': [*group_type_class_args],
|
||||||
|
'AUTH_LDAP_GROUP_TYPE_CLASS_KWARGS': {**group_type_class_kwargs},
|
||||||
|
'AUTH_LDAP_GROUP_TYPE': getattr(django_auth_ldap.config, group_type_class)(
|
||||||
|
*group_type_class_args, **group_type_class_kwargs
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_REQUIRE_GROUP': get_setting(
|
||||||
|
'INVENTREE_LDAP_REQUIRE_GROUP', 'ldap.require_group'
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_DENY_GROUP': get_setting(
|
||||||
|
'INVENTREE_LDAP_DENY_GROUP', 'ldap.deny_group'
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_USER_FLAGS_BY_GROUP': get_setting(
|
||||||
|
'INVENTREE_LDAP_USER_FLAGS_BY_GROUP',
|
||||||
|
'ldap.user_flags_by_group',
|
||||||
|
default_value=None,
|
||||||
|
typecast=dict,
|
||||||
|
),
|
||||||
|
'AUTH_LDAP_FIND_GROUP_PERMS': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ldap_config
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
"""Start-up configuration options for InvenTree tracing integrations."""
|
||||||
|
|
||||||
|
import structlog
|
||||||
|
|
||||||
|
from InvenTree.config import get_boolean_setting, get_setting
|
||||||
|
from InvenTree.tracing import setup_instruments, setup_tracing
|
||||||
|
|
||||||
|
logger = structlog.get_logger('inventree')
|
||||||
|
|
||||||
|
|
||||||
|
def configure_tracing(db_engine: str, enabled: bool, tags: dict) -> dict:
|
||||||
|
"""Configure tracing integrations for InvenTree.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
db_engine: The database engine being used
|
||||||
|
enabled: Whether tracing is enabled
|
||||||
|
tags: A dictionary of tags to be included in tracing spans, with keys prefixed by
|
||||||
|
"""
|
||||||
|
endpoint = get_setting('INVENTREE_TRACING_ENDPOINT', 'tracing.endpoint', None)
|
||||||
|
headers = (
|
||||||
|
get_setting('INVENTREE_TRACING_HEADERS', 'tracing.headers', None, typecast=dict)
|
||||||
|
or {}
|
||||||
|
)
|
||||||
|
|
||||||
|
if enabled and endpoint:
|
||||||
|
logger.info('Tracing enabled with endpoint: %s', endpoint)
|
||||||
|
|
||||||
|
TRACING_DETAILS = {
|
||||||
|
'endpoint': endpoint,
|
||||||
|
'headers': headers,
|
||||||
|
'resources_input': {
|
||||||
|
**{'inventree.env.' + k: v for k, v in tags.items()},
|
||||||
|
**get_setting(
|
||||||
|
'INVENTREE_TRACING_RESOURCES',
|
||||||
|
'tracing.resources',
|
||||||
|
default_value=None,
|
||||||
|
typecast=dict,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
'console': get_boolean_setting(
|
||||||
|
'INVENTREE_TRACING_CONSOLE', 'tracing.console', False
|
||||||
|
),
|
||||||
|
'auth': get_setting(
|
||||||
|
'INVENTREE_TRACING_AUTH', 'tracing.auth', default_value=None, typecast=dict
|
||||||
|
),
|
||||||
|
'is_http': get_setting('INVENTREE_TRACING_IS_HTTP', 'tracing.is_http', True),
|
||||||
|
'append_http': get_boolean_setting(
|
||||||
|
'INVENTREE_TRACING_APPEND_HTTP', 'tracing.append_http', True
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
if not enabled:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if endpoint:
|
||||||
|
setup_tracing(**TRACING_DETAILS)
|
||||||
|
setup_instruments(db_engine)
|
||||||
|
else:
|
||||||
|
logger.warning('OpenTelemetry tracing not enabled because endpoint is not set')
|
||||||
|
|
||||||
|
return TRACING_DETAILS
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
"""Configuration settings for the InvenTree background worker process."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from InvenTree.config import get_setting
|
||||||
|
|
||||||
|
|
||||||
|
def get_worker_config(
|
||||||
|
db_engine: str,
|
||||||
|
global_cache: bool = False,
|
||||||
|
sentry_dsn: str = '',
|
||||||
|
debug: bool = False,
|
||||||
|
) -> dict:
|
||||||
|
"""Return a dictionary of configuration settings for the background worker.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
db_engine: The database engine being used (e.g. 'sqlite', 'postgresql', 'mysql')
|
||||||
|
global_cache: Whether a global redis cache is enabled
|
||||||
|
sentry_dsn: The DSN for sentry.io integration (if enabled)
|
||||||
|
debug: Whether the application is running in debug mode
|
||||||
|
|
||||||
|
Ref: https://django-q2.readthedocs.io/en/master/configure.html
|
||||||
|
"""
|
||||||
|
BACKGROUND_WORKER_TIMEOUT = int(
|
||||||
|
get_setting('INVENTREE_BACKGROUND_TIMEOUT', 'background.timeout', 90)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set the retry time for background workers to be slightly longer than the worker timeout, to ensure that workers have time to timeout before being retried
|
||||||
|
BACKGROUND_WORKER_RETRY = max(
|
||||||
|
int(get_setting('INVENTREE_BACKGROUND_RETRY', 'background.retry', 300)),
|
||||||
|
BACKGROUND_WORKER_TIMEOUT + 120,
|
||||||
|
)
|
||||||
|
|
||||||
|
BACKGROUND_WORKER_ATTEMPTS = int(
|
||||||
|
get_setting('INVENTREE_BACKGROUND_MAX_ATTEMPTS', 'background.max_attempts', 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prevent running multiple background workers if global cache is disabled
|
||||||
|
# This is to prevent scheduling conflicts due to the lack of a shared cache
|
||||||
|
BACKGROUND_WORKER_COUNT = int(
|
||||||
|
get_setting('INVENTREE_BACKGROUND_WORKERS', 'background.workers', 4)
|
||||||
|
)
|
||||||
|
|
||||||
|
# If global cache is disabled, we cannot run multiple background workers
|
||||||
|
if not global_cache:
|
||||||
|
BACKGROUND_WORKER_COUNT = 1
|
||||||
|
|
||||||
|
# If running with SQLite, limit background worker threads to 1 to prevent database locking issues
|
||||||
|
if 'sqlite' in db_engine:
|
||||||
|
BACKGROUND_WORKER_COUNT = 1
|
||||||
|
|
||||||
|
# Check if '--sync' was passed in the command line
|
||||||
|
if '--sync' in sys.argv and '--noreload' in sys.argv and debug:
|
||||||
|
SYNC_TASKS = True
|
||||||
|
else:
|
||||||
|
SYNC_TASKS = False
|
||||||
|
|
||||||
|
# Clean up sys.argv so Django doesn't complain about an unknown argument
|
||||||
|
if SYNC_TASKS:
|
||||||
|
sys.argv.remove('--sync')
|
||||||
|
|
||||||
|
# django-q background worker configuration
|
||||||
|
config = {
|
||||||
|
'name': 'InvenTree',
|
||||||
|
'label': 'Background Tasks',
|
||||||
|
'workers': BACKGROUND_WORKER_COUNT,
|
||||||
|
'timeout': BACKGROUND_WORKER_TIMEOUT,
|
||||||
|
'retry': BACKGROUND_WORKER_RETRY,
|
||||||
|
'max_attempts': BACKGROUND_WORKER_ATTEMPTS,
|
||||||
|
'save_limit': 1000,
|
||||||
|
'queue_limit': 50,
|
||||||
|
'catch_up': False,
|
||||||
|
'bulk': 10,
|
||||||
|
'orm': 'default',
|
||||||
|
'cache': 'default',
|
||||||
|
'sync': SYNC_TASKS,
|
||||||
|
'poll': 1.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
if global_cache:
|
||||||
|
# If using external redis cache, make the cache the broker for Django Q
|
||||||
|
config['django_redis'] = 'worker'
|
||||||
|
|
||||||
|
if sentry_dsn:
|
||||||
|
# If sentry is enabled, configure django-q to report errors to sentry
|
||||||
|
config['error_reporter'] = {'sentry': {'dsn': sentry_dsn}}
|
||||||
|
|
||||||
|
return config
|
||||||
@@ -12,7 +12,6 @@ database setup in this file.
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||||
|
|
||||||
@@ -33,7 +32,16 @@ from InvenTree.version import checkMinPythonVersion, inventreeCommitHash
|
|||||||
from users.oauth2_scopes import oauth2_scopes
|
from users.oauth2_scopes import oauth2_scopes
|
||||||
|
|
||||||
from . import config
|
from . import config
|
||||||
from .setting import db_backend, locales, markdown, spectacular, storages
|
from .setting import (
|
||||||
|
db_backend,
|
||||||
|
ldap,
|
||||||
|
locales,
|
||||||
|
markdown,
|
||||||
|
spectacular,
|
||||||
|
storages,
|
||||||
|
tracing,
|
||||||
|
worker,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import django_stubs_ext
|
import django_stubs_ext
|
||||||
@@ -81,6 +89,8 @@ DEBUG = get_boolean_setting('INVENTREE_DEBUG', 'debug', False)
|
|||||||
# Internal flag to determine if we are running in docker mode
|
# Internal flag to determine if we are running in docker mode
|
||||||
DOCKER = get_boolean_setting('INVENTREE_DOCKER', default_value=False)
|
DOCKER = get_boolean_setting('INVENTREE_DOCKER', default_value=False)
|
||||||
|
|
||||||
|
AUTO_UPDATE = get_boolean_setting('INVENTREE_AUTO_UPDATE', 'auto_update', False)
|
||||||
|
|
||||||
# Configure logging settings
|
# Configure logging settings
|
||||||
LOG_LEVEL = get_setting('INVENTREE_LOG_LEVEL', 'log_level', 'WARNING')
|
LOG_LEVEL = get_setting('INVENTREE_LOG_LEVEL', 'log_level', 'WARNING')
|
||||||
JSON_LOG = get_boolean_setting('INVENTREE_JSON_LOG', 'json_log', False)
|
JSON_LOG = get_boolean_setting('INVENTREE_JSON_LOG', 'json_log', False)
|
||||||
@@ -222,9 +232,7 @@ PLUGIN_TESTING_EVENTS_ASYNC = False # Flag if events are tested asynchronously
|
|||||||
PLUGIN_TESTING_RELOAD = False # Flag if plugin reloading is in testing (check_reload)
|
PLUGIN_TESTING_RELOAD = False # Flag if plugin reloading is in testing (check_reload)
|
||||||
|
|
||||||
# Plugin development settings
|
# Plugin development settings
|
||||||
PLUGIN_DEV_SLUG = (
|
PLUGIN_DEV_SLUG = get_setting('INVENTREE_PLUGIN_DEV_SLUG', 'plugin_dev.slug')
|
||||||
get_setting('INVENTREE_PLUGIN_DEV_SLUG', 'plugin_dev.slug') if DEBUG else None
|
|
||||||
)
|
|
||||||
|
|
||||||
PLUGIN_DEV_HOST = get_setting(
|
PLUGIN_DEV_HOST = get_setting(
|
||||||
'INVENTREE_PLUGIN_DEV_HOST', 'plugin_dev.host', 'http://localhost:5174'
|
'INVENTREE_PLUGIN_DEV_HOST', 'plugin_dev.host', 'http://localhost:5174'
|
||||||
@@ -386,9 +394,12 @@ MIDDLEWARE = CONFIG.get(
|
|||||||
|
|
||||||
# In DEBUG mode, add support for django-silk
|
# In DEBUG mode, add support for django-silk
|
||||||
# Ref: https://silk.readthedocs.io/en/latest/
|
# Ref: https://silk.readthedocs.io/en/latest/
|
||||||
DJANGO_SILK_ENABLED = DEBUG and get_boolean_setting( # pragma: no cover
|
DJANGO_SILK_ENABLED = (
|
||||||
|
get_boolean_setting( # pragma: no cover
|
||||||
'INVENTREE_DEBUG_SILK', 'debug_silk', False
|
'INVENTREE_DEBUG_SILK', 'debug_silk', False
|
||||||
)
|
)
|
||||||
|
and DEBUG
|
||||||
|
)
|
||||||
|
|
||||||
if DJANGO_SILK_ENABLED: # pragma: no cover
|
if DJANGO_SILK_ENABLED: # pragma: no cover
|
||||||
MIDDLEWARE.append('silk.middleware.SilkyMiddleware')
|
MIDDLEWARE.append('silk.middleware.SilkyMiddleware')
|
||||||
@@ -401,8 +412,11 @@ if DJANGO_SILK_ENABLED: # pragma: no cover
|
|||||||
|
|
||||||
# In DEBUG mode, add support for django-querycount
|
# In DEBUG mode, add support for django-querycount
|
||||||
# Ref: https://github.com/bradmontgomery/django-querycount
|
# Ref: https://github.com/bradmontgomery/django-querycount
|
||||||
if DEBUG and get_boolean_setting( # pragma: no cover
|
if (
|
||||||
|
get_boolean_setting( # pragma: no cover
|
||||||
'INVENTREE_DEBUG_QUERYCOUNT', 'debug_querycount', False
|
'INVENTREE_DEBUG_QUERYCOUNT', 'debug_querycount', False
|
||||||
|
)
|
||||||
|
and DEBUG
|
||||||
):
|
):
|
||||||
MIDDLEWARE.append('querycount.middleware.QueryCountMiddleware')
|
MIDDLEWARE.append('querycount.middleware.QueryCountMiddleware')
|
||||||
logger.debug('Running with debug_querycount middleware enabled')
|
logger.debug('Running with debug_querycount middleware enabled')
|
||||||
@@ -437,14 +451,14 @@ AUTHENTICATION_BACKENDS = (
|
|||||||
|
|
||||||
# LDAP support
|
# LDAP support
|
||||||
LDAP_AUTH = get_boolean_setting('INVENTREE_LDAP_ENABLED', 'ldap.enabled', False)
|
LDAP_AUTH = get_boolean_setting('INVENTREE_LDAP_ENABLED', 'ldap.enabled', False)
|
||||||
if LDAP_AUTH: # pragma: no cover
|
LDAP_DEBUG = (
|
||||||
import django_auth_ldap.config # type: ignore[unresolved-import]
|
get_boolean_setting('INVENTREE_LDAP_DEBUG', 'ldap.debug', False) and LDAP_AUTH
|
||||||
import ldap # type: ignore[unresolved-import]
|
)
|
||||||
|
|
||||||
|
if LDAP_AUTH: # pragma: no cover
|
||||||
AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend')
|
AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend')
|
||||||
|
|
||||||
# debug mode to troubleshoot configuration
|
# debug mode to troubleshoot configuration
|
||||||
LDAP_DEBUG = get_boolean_setting('INVENTREE_LDAP_DEBUG', 'ldap.debug', False)
|
|
||||||
if LDAP_DEBUG:
|
if LDAP_DEBUG:
|
||||||
if 'loggers' not in LOGGING:
|
if 'loggers' not in LOGGING:
|
||||||
LOGGING['loggers'] = {}
|
LOGGING['loggers'] = {}
|
||||||
@@ -453,113 +467,10 @@ if LDAP_AUTH: # pragma: no cover
|
|||||||
'handlers': DEFAULT_LOG_HANDLER,
|
'handlers': DEFAULT_LOG_HANDLER,
|
||||||
}
|
}
|
||||||
|
|
||||||
# get global options from dict and use ldap.OPT_* as keys and values
|
# Determine LDAP settings
|
||||||
global_options_dict = get_setting(
|
ldap_settings = ldap.get_ldap_config(debug=LDAP_DEBUG)
|
||||||
'INVENTREE_LDAP_GLOBAL_OPTIONS',
|
globals().update(ldap_settings)
|
||||||
'ldap.global_options',
|
|
||||||
default_value=None,
|
|
||||||
typecast=dict,
|
|
||||||
)
|
|
||||||
global_options = {}
|
|
||||||
for k, v in global_options_dict.items():
|
|
||||||
# keys are always ldap.OPT_* constants
|
|
||||||
k_attr = getattr(ldap, k, None)
|
|
||||||
if not k.startswith('OPT_') or k_attr is None:
|
|
||||||
print(f"[LDAP] ldap.global_options, key '{k}' not found, skipping...")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# values can also be other strings, e.g. paths
|
|
||||||
v_attr = v
|
|
||||||
if v.startswith('OPT_'):
|
|
||||||
v_attr = getattr(ldap, v, None)
|
|
||||||
|
|
||||||
if v_attr is None:
|
|
||||||
print(f"[LDAP] ldap.global_options, value key '{v}' not found, skipping...")
|
|
||||||
continue
|
|
||||||
|
|
||||||
global_options[k_attr] = v_attr
|
|
||||||
AUTH_LDAP_GLOBAL_OPTIONS = global_options
|
|
||||||
if LDAP_DEBUG:
|
|
||||||
print('[LDAP] ldap.global_options =', global_options)
|
|
||||||
|
|
||||||
AUTH_LDAP_SERVER_URI = get_setting('INVENTREE_LDAP_SERVER_URI', 'ldap.server_uri')
|
|
||||||
AUTH_LDAP_START_TLS = get_boolean_setting(
|
|
||||||
'INVENTREE_LDAP_START_TLS', 'ldap.start_tls', False
|
|
||||||
)
|
|
||||||
AUTH_LDAP_BIND_DN = get_setting('INVENTREE_LDAP_BIND_DN', 'ldap.bind_dn')
|
|
||||||
AUTH_LDAP_BIND_PASSWORD = get_setting(
|
|
||||||
'INVENTREE_LDAP_BIND_PASSWORD', 'ldap.bind_password'
|
|
||||||
)
|
|
||||||
AUTH_LDAP_USER_SEARCH = django_auth_ldap.config.LDAPSearch(
|
|
||||||
get_setting('INVENTREE_LDAP_SEARCH_BASE_DN', 'ldap.search_base_dn'),
|
|
||||||
ldap.SCOPE_SUBTREE,
|
|
||||||
str(
|
|
||||||
get_setting(
|
|
||||||
'INVENTREE_LDAP_SEARCH_FILTER_STR',
|
|
||||||
'ldap.search_filter_str',
|
|
||||||
'(uid= %(user)s)',
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
AUTH_LDAP_USER_DN_TEMPLATE = get_setting(
|
|
||||||
'INVENTREE_LDAP_USER_DN_TEMPLATE', 'ldap.user_dn_template'
|
|
||||||
)
|
|
||||||
AUTH_LDAP_USER_ATTR_MAP = get_setting(
|
|
||||||
'INVENTREE_LDAP_USER_ATTR_MAP',
|
|
||||||
'ldap.user_attr_map',
|
|
||||||
{'first_name': 'givenName', 'last_name': 'sn', 'email': 'mail'},
|
|
||||||
dict,
|
|
||||||
)
|
|
||||||
AUTH_LDAP_ALWAYS_UPDATE_USER = get_boolean_setting(
|
|
||||||
'INVENTREE_LDAP_ALWAYS_UPDATE_USER', 'ldap.always_update_user', True
|
|
||||||
)
|
|
||||||
AUTH_LDAP_CACHE_TIMEOUT = get_setting(
|
|
||||||
'INVENTREE_LDAP_CACHE_TIMEOUT', 'ldap.cache_timeout', 3600, int
|
|
||||||
)
|
|
||||||
|
|
||||||
AUTH_LDAP_MIRROR_GROUPS = get_boolean_setting(
|
|
||||||
'INVENTREE_LDAP_MIRROR_GROUPS', 'ldap.mirror_groups', False
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_OBJECT_CLASS = get_setting(
|
|
||||||
'INVENTREE_LDAP_GROUP_OBJECT_CLASS',
|
|
||||||
'ldap.group_object_class',
|
|
||||||
'groupOfUniqueNames',
|
|
||||||
str,
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_SEARCH = django_auth_ldap.config.LDAPSearch(
|
|
||||||
get_setting('INVENTREE_LDAP_GROUP_SEARCH', 'ldap.group_search'),
|
|
||||||
ldap.SCOPE_SUBTREE,
|
|
||||||
f'(objectClass={AUTH_LDAP_GROUP_OBJECT_CLASS})',
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_TYPE_CLASS = get_setting(
|
|
||||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS',
|
|
||||||
'ldap.group_type_class',
|
|
||||||
'GroupOfUniqueNamesType',
|
|
||||||
str,
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_TYPE_CLASS_ARGS = get_setting(
|
|
||||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS_ARGS', 'ldap.group_type_class_args', [], list
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_TYPE_CLASS_KWARGS = get_setting(
|
|
||||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS_KWARGS',
|
|
||||||
'ldap.group_type_class_kwargs',
|
|
||||||
{'name_attr': 'cn'},
|
|
||||||
dict,
|
|
||||||
)
|
|
||||||
AUTH_LDAP_GROUP_TYPE = getattr(django_auth_ldap.config, AUTH_LDAP_GROUP_TYPE_CLASS)(
|
|
||||||
*AUTH_LDAP_GROUP_TYPE_CLASS_ARGS, **AUTH_LDAP_GROUP_TYPE_CLASS_KWARGS
|
|
||||||
)
|
|
||||||
AUTH_LDAP_REQUIRE_GROUP = get_setting(
|
|
||||||
'INVENTREE_LDAP_REQUIRE_GROUP', 'ldap.require_group'
|
|
||||||
)
|
|
||||||
AUTH_LDAP_DENY_GROUP = get_setting('INVENTREE_LDAP_DENY_GROUP', 'ldap.deny_group')
|
|
||||||
AUTH_LDAP_USER_FLAGS_BY_GROUP = get_setting(
|
|
||||||
'INVENTREE_LDAP_USER_FLAGS_BY_GROUP',
|
|
||||||
'ldap.user_flags_by_group',
|
|
||||||
default_value=None,
|
|
||||||
typecast=dict,
|
|
||||||
)
|
|
||||||
AUTH_LDAP_FIND_GROUP_PERMS = True
|
|
||||||
|
|
||||||
# Allow secure http developer server in debug mode
|
# Allow secure http developer server in debug mode
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
@@ -642,107 +553,11 @@ Configure the database backend based on the user-specified values.
|
|||||||
|
|
||||||
logger.debug('Configuring database backend:')
|
logger.debug('Configuring database backend:')
|
||||||
|
|
||||||
# Extract database configuration from the config.yaml file
|
# Load database configuration from the config file and environment variables
|
||||||
db_config = CONFIG.get('database', None) if CONFIG else None
|
database = db_backend.get_db_backend()
|
||||||
|
DB_ENGINE = database['ENGINE']
|
||||||
|
|
||||||
if not db_config:
|
DATABASES = {'default': database}
|
||||||
db_config = {}
|
|
||||||
|
|
||||||
# Environment variables take preference over config file!
|
|
||||||
|
|
||||||
db_keys = ['ENGINE', 'NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']
|
|
||||||
|
|
||||||
for key in db_keys:
|
|
||||||
# First, check the environment variables
|
|
||||||
env_key = f'INVENTREE_DB_{key}'
|
|
||||||
env_var = os.environ.get(env_key, None)
|
|
||||||
|
|
||||||
if env_var:
|
|
||||||
# Make use PORT is int
|
|
||||||
if key == 'PORT':
|
|
||||||
try:
|
|
||||||
env_var = int(env_var)
|
|
||||||
except ValueError:
|
|
||||||
logger.exception('Invalid number for %s: %s', env_key, env_var)
|
|
||||||
# Override configuration value
|
|
||||||
db_config[key] = env_var
|
|
||||||
|
|
||||||
# Check that required database configuration options are specified
|
|
||||||
required_keys = ['ENGINE', 'NAME']
|
|
||||||
|
|
||||||
# Ensure all database keys are upper case
|
|
||||||
db_config = {key.upper(): value for key, value in db_config.items()}
|
|
||||||
|
|
||||||
for key in required_keys:
|
|
||||||
if key not in db_config: # pragma: no cover
|
|
||||||
error_msg = (
|
|
||||||
f'Missing required database configuration value `INVENTREE_DB_{key}`'
|
|
||||||
)
|
|
||||||
logger.error(error_msg)
|
|
||||||
|
|
||||||
print('Error: ' + error_msg)
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Special considerations for the database 'ENGINE' setting.
|
|
||||||
It can be specified in config.yaml (or envvar) as either (for example):
|
|
||||||
- sqlite3
|
|
||||||
- django.db.backends.sqlite3
|
|
||||||
- django.db.backends.postgresql
|
|
||||||
"""
|
|
||||||
|
|
||||||
DB_ENGINE = db_config['ENGINE'].lower()
|
|
||||||
|
|
||||||
# Correct common misspelling
|
|
||||||
if DB_ENGINE == 'sqlite':
|
|
||||||
DB_ENGINE = 'sqlite3' # pragma: no cover
|
|
||||||
|
|
||||||
if DB_ENGINE in ['sqlite3', 'postgresql', 'mysql']:
|
|
||||||
# Prepend the required python module string
|
|
||||||
DB_ENGINE = f'django.db.backends.{DB_ENGINE}'
|
|
||||||
db_config['ENGINE'] = DB_ENGINE
|
|
||||||
|
|
||||||
db_name = db_config['NAME']
|
|
||||||
db_host = db_config.get('HOST', "''")
|
|
||||||
|
|
||||||
if 'sqlite' in DB_ENGINE:
|
|
||||||
db_name = str(Path(db_name).resolve())
|
|
||||||
db_config['NAME'] = db_name
|
|
||||||
|
|
||||||
logger.info('DB_ENGINE: %s', DB_ENGINE)
|
|
||||||
logger.info('DB_NAME: %s', db_name)
|
|
||||||
logger.info('DB_HOST: %s', db_host)
|
|
||||||
|
|
||||||
"""
|
|
||||||
In addition to base-level database configuration, we may wish to specify specific options to the database backend
|
|
||||||
Ref: https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-OPTIONS
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 'OPTIONS' or 'options' can be specified in config.yaml
|
|
||||||
# Set useful sensible timeouts for a transactional webserver to communicate
|
|
||||||
# with its database server, that is, if the webserver is having issues
|
|
||||||
# connecting to the database server (such as a replica failover) don't sit and
|
|
||||||
# wait for possibly an hour or more, just tell the client something went wrong
|
|
||||||
# and let the client retry when they want to.
|
|
||||||
db_options = db_config.get('OPTIONS', db_config.get('options'))
|
|
||||||
|
|
||||||
if db_options is None:
|
|
||||||
db_options = {}
|
|
||||||
|
|
||||||
# Set database-specific options
|
|
||||||
db_backend.set_db_options(DB_ENGINE, db_options)
|
|
||||||
|
|
||||||
# Provide OPTIONS dict back to the database configuration dict
|
|
||||||
db_config['OPTIONS'] = db_options
|
|
||||||
|
|
||||||
# Set testing options for the database
|
|
||||||
db_config['TEST'] = {'CHARSET': 'utf8'}
|
|
||||||
|
|
||||||
# Set collation option for mysql test database
|
|
||||||
if 'mysql' in DB_ENGINE:
|
|
||||||
db_config['TEST']['COLLATION'] = 'utf8_general_ci' # pragma: no cover
|
|
||||||
|
|
||||||
DATABASES = {'default': db_config}
|
|
||||||
|
|
||||||
# login settings
|
# login settings
|
||||||
REMOTE_LOGIN = get_boolean_setting(
|
REMOTE_LOGIN = get_boolean_setting(
|
||||||
@@ -776,133 +591,28 @@ if SENTRY_ENABLED and SENTRY_DSN and not TESTING: # pragma: no cover
|
|||||||
init_sentry(SENTRY_DSN, SENTRY_SAMPLE_RATE, inventree_tags)
|
init_sentry(SENTRY_DSN, SENTRY_SAMPLE_RATE, inventree_tags)
|
||||||
|
|
||||||
# OpenTelemetry tracing
|
# OpenTelemetry tracing
|
||||||
TRACING_ENABLED = get_boolean_setting(
|
TRACING_ENABLED = (
|
||||||
'INVENTREE_TRACING_ENABLED', 'tracing.enabled', False
|
get_boolean_setting('INVENTREE_TRACING_ENABLED', 'tracing.enabled', False)
|
||||||
)
|
and not isRunningBackup()
|
||||||
TRACING_DETAILS: Optional[dict] = None
|
|
||||||
|
|
||||||
if TRACING_ENABLED and not isRunningBackup(): # pragma: no cover
|
|
||||||
from InvenTree.tracing import setup_instruments, setup_tracing
|
|
||||||
|
|
||||||
_t_endpoint = get_setting('INVENTREE_TRACING_ENDPOINT', 'tracing.endpoint', None)
|
|
||||||
_t_headers = get_setting('INVENTREE_TRACING_HEADERS', 'tracing.headers', None, dict)
|
|
||||||
|
|
||||||
if _t_headers is None:
|
|
||||||
_t_headers = {}
|
|
||||||
|
|
||||||
if _t_endpoint:
|
|
||||||
logger.info('OpenTelemetry tracing enabled')
|
|
||||||
|
|
||||||
TRACING_DETAILS = (
|
|
||||||
TRACING_DETAILS
|
|
||||||
if TRACING_DETAILS
|
|
||||||
else {
|
|
||||||
'endpoint': _t_endpoint,
|
|
||||||
'headers': _t_headers,
|
|
||||||
'resources_input': {
|
|
||||||
**{'inventree.env.' + k: v for k, v in inventree_tags.items()},
|
|
||||||
**get_setting(
|
|
||||||
'INVENTREE_TRACING_RESOURCES',
|
|
||||||
'tracing.resources',
|
|
||||||
default_value=None,
|
|
||||||
typecast=dict,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
'console': get_boolean_setting(
|
|
||||||
'INVENTREE_TRACING_CONSOLE', 'tracing.console', False
|
|
||||||
),
|
|
||||||
'auth': get_setting(
|
|
||||||
'INVENTREE_TRACING_AUTH',
|
|
||||||
'tracing.auth',
|
|
||||||
default_value=None,
|
|
||||||
typecast=dict,
|
|
||||||
),
|
|
||||||
'is_http': get_setting(
|
|
||||||
'INVENTREE_TRACING_IS_HTTP', 'tracing.is_http', True
|
|
||||||
),
|
|
||||||
'append_http': get_boolean_setting(
|
|
||||||
'INVENTREE_TRACING_APPEND_HTTP', 'tracing.append_http', True
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Run tracing/logging instrumentation
|
TRACING_DETAILS: Optional[dict] = tracing.configure_tracing(
|
||||||
setup_tracing(**TRACING_DETAILS)
|
DB_ENGINE, TRACING_ENABLED, inventree_tags
|
||||||
setup_instruments(DB_ENGINE)
|
)
|
||||||
else:
|
|
||||||
logger.warning('OpenTelemetry tracing not enabled because endpoint is not set')
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# Cache configuration
|
# Cache configuration
|
||||||
GLOBAL_CACHE_ENABLED = is_global_cache_enabled()
|
GLOBAL_CACHE_ENABLED = is_global_cache_enabled()
|
||||||
|
|
||||||
CACHES = {'default': get_cache_config(GLOBAL_CACHE_ENABLED)}
|
CACHES = {'default': get_cache_config(GLOBAL_CACHE_ENABLED)}
|
||||||
|
|
||||||
BACKGROUND_WORKER_TIMEOUT = int(
|
# Background task processing with django-q
|
||||||
get_setting('INVENTREE_BACKGROUND_TIMEOUT', 'background.timeout', 90)
|
Q_CLUSTER = worker.get_worker_config(
|
||||||
|
DB_ENGINE,
|
||||||
|
global_cache=GLOBAL_CACHE_ENABLED,
|
||||||
|
sentry_dsn=SENTRY_DSN if SENTRY_ENABLED and SENTRY_DSN else None,
|
||||||
|
debug=DEBUG,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set the retry time for background workers to be slightly longer than the worker timeout, to ensure that workers have time to timeout before being retried
|
|
||||||
BACKGROUND_WORKER_RETRY = max(
|
|
||||||
int(get_setting('INVENTREE_BACKGROUND_RETRY', 'background.retry', 300)),
|
|
||||||
BACKGROUND_WORKER_TIMEOUT + 120,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Prevent running multiple background workers if global cache is disabled
|
|
||||||
# This is to prevent scheduling conflicts due to the lack of a shared cache
|
|
||||||
BACKGROUND_WORKER_COUNT = (
|
|
||||||
int(get_setting('INVENTREE_BACKGROUND_WORKERS', 'background.workers', 4))
|
|
||||||
if GLOBAL_CACHE_ENABLED
|
|
||||||
else 1
|
|
||||||
)
|
|
||||||
|
|
||||||
# If running with SQLite, limit background worker threads to 1 to prevent database locking issues
|
|
||||||
if 'sqlite' in DB_ENGINE:
|
|
||||||
BACKGROUND_WORKER_COUNT = 1
|
|
||||||
|
|
||||||
BACKGROUND_WORKER_ATTEMPTS = int(
|
|
||||||
get_setting('INVENTREE_BACKGROUND_MAX_ATTEMPTS', 'background.max_attempts', 5)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if '--sync' was passed in the command line
|
|
||||||
if '--sync' in sys.argv and '--noreload' in sys.argv and DEBUG:
|
|
||||||
SYNC_TASKS = True
|
|
||||||
else:
|
|
||||||
SYNC_TASKS = False
|
|
||||||
|
|
||||||
# Clean up sys.argv so Django doesn't complain about an unknown argument
|
|
||||||
if SYNC_TASKS:
|
|
||||||
sys.argv.remove('--sync')
|
|
||||||
|
|
||||||
# django-q background worker configuration
|
|
||||||
Q_CLUSTER = {
|
|
||||||
'name': 'InvenTree',
|
|
||||||
'label': 'Background Tasks',
|
|
||||||
'workers': BACKGROUND_WORKER_COUNT,
|
|
||||||
'timeout': BACKGROUND_WORKER_TIMEOUT,
|
|
||||||
'retry': BACKGROUND_WORKER_RETRY,
|
|
||||||
'max_attempts': BACKGROUND_WORKER_ATTEMPTS,
|
|
||||||
'save_limit': 1000,
|
|
||||||
'queue_limit': 50,
|
|
||||||
'catch_up': False,
|
|
||||||
'bulk': 10,
|
|
||||||
'orm': 'default',
|
|
||||||
'cache': 'default',
|
|
||||||
'sync': SYNC_TASKS,
|
|
||||||
'poll': 1.5,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Configure django-q sentry integration
|
|
||||||
if SENTRY_ENABLED and SENTRY_DSN: # pragma: no cover
|
|
||||||
Q_CLUSTER['error_reporter'] = {'sentry': {'dsn': SENTRY_DSN}}
|
|
||||||
|
|
||||||
if GLOBAL_CACHE_ENABLED: # pragma: no cover
|
|
||||||
# If using external redis cache, make the cache the broker for Django Q
|
|
||||||
# as well
|
|
||||||
Q_CLUSTER['django_redis'] = 'worker'
|
|
||||||
|
|
||||||
|
|
||||||
SILENCED_SYSTEM_CHECKS = ['templates.E003', 'templates.W003']
|
SILENCED_SYSTEM_CHECKS = ['templates.E003', 'templates.W003']
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
@@ -976,10 +686,10 @@ INTERNAL_EMAIL_BACKEND = get_setting(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# SMTP backend
|
# SMTP backend
|
||||||
EMAIL_HOST = get_setting('INVENTREE_EMAIL_HOST', 'email.host', '')
|
EMAIL_HOST = get_setting('INVENTREE_EMAIL_HOST', 'email.host')
|
||||||
EMAIL_PORT = get_setting('INVENTREE_EMAIL_PORT', 'email.port', 25, typecast=int)
|
EMAIL_PORT = get_setting('INVENTREE_EMAIL_PORT', 'email.port', 25, typecast=int)
|
||||||
EMAIL_HOST_USER = get_setting('INVENTREE_EMAIL_USERNAME', 'email.username', '')
|
EMAIL_HOST_USER = get_setting('INVENTREE_EMAIL_USERNAME', 'email.username')
|
||||||
EMAIL_HOST_PASSWORD = get_setting('INVENTREE_EMAIL_PASSWORD', 'email.password', '')
|
EMAIL_HOST_PASSWORD = get_setting('INVENTREE_EMAIL_PASSWORD', 'email.password')
|
||||||
EMAIL_USE_TLS = get_boolean_setting('INVENTREE_EMAIL_TLS', 'email.tls', False)
|
EMAIL_USE_TLS = get_boolean_setting('INVENTREE_EMAIL_TLS', 'email.tls', False)
|
||||||
EMAIL_USE_SSL = get_boolean_setting('INVENTREE_EMAIL_SSL', 'email.ssl', False)
|
EMAIL_USE_SSL = get_boolean_setting('INVENTREE_EMAIL_SSL', 'email.ssl', False)
|
||||||
# Anymail
|
# Anymail
|
||||||
@@ -1150,16 +860,14 @@ LANGUAGE_COOKIE_SAMESITE = COOKIE_MODE
|
|||||||
- Otherwise, use the value specified in the configuration file (or env var)
|
- Otherwise, use the value specified in the configuration file (or env var)
|
||||||
"""
|
"""
|
||||||
COOKIE_SECURE = (
|
COOKIE_SECURE = (
|
||||||
False
|
get_boolean_setting('INVENTREE_SESSION_COOKIE_SECURE', 'cookie.secure', False)
|
||||||
if DEBUG
|
or SESSION_COOKIE_SAMESITE == 'None'
|
||||||
else (
|
|
||||||
SESSION_COOKIE_SAMESITE == 'None'
|
|
||||||
or get_boolean_setting(
|
|
||||||
'INVENTREE_SESSION_COOKIE_SECURE', 'cookie.secure', False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Override COOKIE_SECURE value in DEBUG mode
|
||||||
|
if DEBUG:
|
||||||
|
COOKIE_SECURE = False
|
||||||
|
|
||||||
CSRF_COOKIE_SECURE = COOKIE_SECURE
|
CSRF_COOKIE_SECURE = COOKIE_SECURE
|
||||||
SESSION_COOKIE_SECURE = COOKIE_SECURE
|
SESSION_COOKIE_SECURE = COOKIE_SECURE
|
||||||
LANGUAGE_COOKIE_SECURE = COOKIE_SECURE
|
LANGUAGE_COOKIE_SECURE = COOKIE_SECURE
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ from maintenance_mode.core import (
|
|||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
|
|
||||||
from common.settings import get_global_setting, set_global_setting
|
from common.settings import get_global_setting, set_global_setting
|
||||||
from InvenTree.config import get_setting
|
|
||||||
from plugin import registry
|
from plugin import registry
|
||||||
|
|
||||||
from .version import isInvenTreeUpToDate
|
from .version import isInvenTreeUpToDate
|
||||||
@@ -822,7 +821,7 @@ def check_for_migrations(force: bool = False, reload_registry: bool = True) -> b
|
|||||||
set_pending_migrations(n)
|
set_pending_migrations(n)
|
||||||
|
|
||||||
# Test if auto-updates are enabled
|
# Test if auto-updates are enabled
|
||||||
if not force and not get_setting('INVENTREE_AUTO_UPDATE', 'auto_update'):
|
if not force and not settings.AUTO_UPDATE:
|
||||||
logger.info('Auto-update is disabled - skipping migrations')
|
logger.info('Auto-update is disabled - skipping migrations')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -381,7 +381,16 @@ class ConfigSerializer(serializers.Serializer):
|
|||||||
"""Return the configuration data as a dictionary."""
|
"""Return the configuration data as a dictionary."""
|
||||||
if not isinstance(instance, str):
|
if not isinstance(instance, str):
|
||||||
instance = list(instance.keys())[0]
|
instance = list(instance.keys())[0]
|
||||||
return {'key': instance, **self.instance.get(instance)}
|
|
||||||
|
data = {'key': instance}
|
||||||
|
|
||||||
|
for k, v in self.instance.get(instance, {}).items():
|
||||||
|
if k == 'default_value':
|
||||||
|
# Skip sensitive default values
|
||||||
|
continue
|
||||||
|
data[k] = v
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class NotesImageSerializer(InvenTreeModelSerializer):
|
class NotesImageSerializer(InvenTreeModelSerializer):
|
||||||
|
|||||||
@@ -1864,8 +1864,13 @@ def export_definitions(c, basedir: str = ''):
|
|||||||
"""Export various definitions."""
|
"""Export various definitions."""
|
||||||
if basedir != '' and basedir.endswith('/') is False:
|
if basedir != '' and basedir.endswith('/') is False:
|
||||||
basedir += '/'
|
basedir += '/'
|
||||||
|
|
||||||
base_path = Path(basedir, 'generated').resolve()
|
base_path = Path(basedir, 'generated').resolve()
|
||||||
|
|
||||||
|
if not base_path.exists():
|
||||||
|
info(f'Creating export directory: {base_path}')
|
||||||
|
base_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
filenames = [
|
filenames = [
|
||||||
base_path.joinpath('inventree_settings.json'),
|
base_path.joinpath('inventree_settings.json'),
|
||||||
base_path.joinpath('inventree_tags.yml'),
|
base_path.joinpath('inventree_tags.yml'),
|
||||||
@@ -2298,11 +2303,18 @@ def doc_schema(c):
|
|||||||
help={
|
help={
|
||||||
'address': 'Host and port to run the server on (default: localhost:8080)',
|
'address': 'Host and port to run the server on (default: localhost:8080)',
|
||||||
'compile_schema': 'Compile the API schema documentation first (default: False)',
|
'compile_schema': 'Compile the API schema documentation first (default: False)',
|
||||||
|
'export_settings': 'Export settings definitions before starting the server (default: True)',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
def docs_server(c, address='localhost:8080', compile_schema=False):
|
def docs_server(
|
||||||
|
c,
|
||||||
|
address='localhost:8080',
|
||||||
|
compile_schema: bool = False,
|
||||||
|
export_settings: bool = True,
|
||||||
|
):
|
||||||
"""Start a local mkdocs server to view the documentation."""
|
"""Start a local mkdocs server to view the documentation."""
|
||||||
# Extract settings definitions
|
# Extract settings definitions
|
||||||
|
if export_settings:
|
||||||
export_definitions(c, basedir='docs')
|
export_definitions(c, basedir='docs')
|
||||||
|
|
||||||
if compile_schema:
|
if compile_schema:
|
||||||
|
|||||||
Reference in New Issue
Block a user