mirror of
https://github.com/inventree/InvenTree.git
synced 2026-04-25 04:23: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 = {
|
||||
'global': ['SERVER_RESTART_REQUIRED'],
|
||||
'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, {})
|
||||
observed = observed_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:
|
||||
|
||||
| Name | Function | Value |
|
||||
| ---- | -------- | ----- |
|
||||
| INVENTREE_PLUGINS_ENABLED | Enables the use of 3rd party plugins | True |
|
||||
| INVENTREE_PLUGIN_TESTING | Enables enables all plugins no matter of their active state in the db or built-in flag | True |
|
||||
| INVENTREE_PLUGIN_TESTING_SETUP | Enables the url mixin | True |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_PLUGINS_ENABLED") }} Enables the use of 3rd party plugins |
|
||||
{{ configsetting("INVENTREE_PLUGIN_TESTING") }} Enables enables all plugins no matter of their active state in the db or built-in flag |
|
||||
{{ configsetting("INVENTREE_PLUGIN_TESTING_SETUP") }} Enables the url mixin |
|
||||
|
||||
### 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:
|
||||
|
||||
| Environment Variable |Configuration File | Description | More Info |
|
||||
| --- | --- | --- | --- |
|
||||
| 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) |
|
||||
| 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) |
|
||||
{{ 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 |
|
||||
{{ configsetting("INVENTREE_SOCIAL_PROVIDERS") }} A *dict* of settings specific to the [installed providers](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:
|
||||
|
||||
|
||||
+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.
|
||||
|
||||
| config key | ENV Variable | Description |
|
||||
| --- | --- | --- |
|
||||
| `ldap.enabled` | `INVENTREE_LDAP_ENABLED` | Set this to `True` to enable LDAP. |
|
||||
| `ldap.debug` | `INVENTREE_LDAP_DEBUG` | Set this to `True` to activate debug mode, useful for troubleshooting ldap configurations. |
|
||||
| `ldap.server_uri` | `INVENTREE_LDAP_SERVER_URI` | LDAP Server URI, e.g. `ldaps://example.org` |
|
||||
| `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`) |
|
||||
| `ldap.bind_dn` | `INVENTREE_LDAP_BIND_DN` | LDAP bind dn, e.g. `cn=admin,dc=example,dc=org` |
|
||||
| `ldap.bind_password` | `INVENTREE_LDAP_BIND_PASSWORD` | LDAP bind password |
|
||||
| `ldap.search_base_dn` | `INVENTREE_LDAP_SEARCH_BASE_DN` | LDAP search base dn, e.g. `cn=Users,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` |
|
||||
| `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) |
|
||||
| `ldap.search_filter_str`| `INVENTREE_LDAP_SEARCH_FILTER_STR` | LDAP search filter str, default: `uid=%(user)s` |
|
||||
| `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"}` |
|
||||
| `ldap.always_update_user` | `INVENTREE_LDAP_ALWAYS_UPDATE_USER` | Always update the user on each login, default: `true` |
|
||||
| `ldap.cache_timeout` | `INVENTREE_LDAP_CACHE_TIMEOUT` | cache timeout to reduce traffic with LDAP server, default: `3600` (1h) |
|
||||
| `ldap.group_search` | `INVENTREE_LDAP_GROUP_SEARCH` | Base LDAP DN for group searching; required to enable group features |
|
||||
| `ldap.group_object_class` | `INVENTREE_LDAP_GROUP_OBJECT_CLASS` | The string to pass to the LDAP group search `(objectClass=<...>)`, default: `groupOfUniqueNames` |
|
||||
| `ldap.mirror_groups` | `INVENTREE_LDAP_MIRROR_GROUPS` | If `True`, mirror a user's LDAP group membership in the Django database, default: `False` |
|
||||
| `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'`|
|
||||
| `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 `[]` |
|
||||
| `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'}` |
|
||||
| `ldap.require_group` | `INVENTREE_LDAP_REQUIRE_GROUP` | If set, users _must_ 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 |
|
||||
| `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: `{}` |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_LDAP_ENABLED") }} Enable LDAP support |
|
||||
{{ configsetting("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` |
|
||||
| `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`) |
|
||||
| `INVENTREE_LDAP_BIND_DN` | `ldap.bind_dn` | LDAP bind dn, e.g. `cn=admin,dc=example,dc=org` |
|
||||
| `INVENTREE_LDAP_BIND_PASSWORD` | `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` |
|
||||
| `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` |
|
||||
| `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) |
|
||||
| `INVENTREE_LDAP_SEARCH_FILTER_STR`| `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"}` |
|
||||
| `INVENTREE_LDAP_ALWAYS_UPDATE_USER` | `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) |
|
||||
| `INVENTREE_LDAP_GROUP_SEARCH` | `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` |
|
||||
| `INVENTREE_LDAP_MIRROR_GROUPS` | `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'`|
|
||||
| `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 `[]` |
|
||||
| `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'}` |
|
||||
| `INVENTREE_LDAP_REQUIRE_GROUP` | `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 |
|
||||
| `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: `{}` |
|
||||
|
||||
## 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.
|
||||
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 |
|
||||
| --- | --- | --- |
|
||||
| `tracing.enabled` | `INVENTREE_TRACING_ENABLED` | Set this to `True` to enable OpenTelemetry. |
|
||||
| `tracing.endpoint` | `INVENTREE_TRACING_ENDPOINT` | General endpoint for information (not specific trace/log url) |
|
||||
| `tracing.headers` | `INVENTREE_TRACING_HEADERS` | HTTP headers that should be send with every request (often used for authentication). Format as a dict. |
|
||||
| `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) |
|
||||
| `tracing.is_http` | `INVENTREE_TRACING_IS_HTTP` | Are the endpoints HTTP (True, default) or gRPC (False) |
|
||||
| `tracing.append_http` | `INVENTREE_TRACING_APPEND_HTTP` | Append default url routes (v1) to `tracing.endpoint` |
|
||||
| `tracing.console` | `INVENTREE_TRACING_CONSOLE` | Print out all exports (additionally) to the console for debugging. Do not use in production |
|
||||
| `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. |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_TRACING_ENABLED") }} Enable OpenTelemetry |
|
||||
{{ configsetting("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. |
|
||||
{{ configsetting("INVENTREE_TRACING_AUTH") }} 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) |
|
||||
{{ configsetting("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 |
|
||||
{{ 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. |
|
||||
|
||||
## 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"
|
||||
For more information on multi-site support, refer to the [Django documentation]({% include "django.html" %}/ref/contrib/sites/).
|
||||
|
||||
| Environment Variable | Config Key | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_SITE_MULTI | site_multi | Enable multiple sites | False |
|
||||
| INVENTREE_SITE_ID | site_id | Specify a fixed site ID | _Not specified_ |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_SITE_MULTI") }} Enable multiple sites |
|
||||
{{ configsetting("INVENTREE_SITE_ID") }} Specify a fixed site ID |
|
||||
|
||||
+13
-13
@@ -17,19 +17,19 @@ The django-dbbackup library provides [multiple configuration options](https://ar
|
||||
|
||||
The following configuration options are available for backup:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_BACKUP_STORAGE | backup_storage | Backup storage backend. Refer to the [storage backend documentation](#storage-backend). | django.core.files.storage.FileSystemStorage |
|
||||
| INVENTREE_BACKUP_DIR | backup_dir | Backup storage directory. | *No default* |
|
||||
| INVENTREE_BACKUP_OPTIONS | backup_options | Specific options for the selected storage backend (dict) | *No default* |
|
||||
| INVENTREE_BACKUP_CONNECTOR_OPTIONS | backup_connector_options | Specific options for the database connector (dict). Refer to the [database connector options](#database-connector). | *No default* |
|
||||
| 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 |
|
||||
| INVENTREE_BACKUP_EMAIL_PREFIX | backup_email_prefix | Prefix for the subject line of backup-related emails. | `[InvenTree Backup]` |
|
||||
| INVENTREE_BACKUP_GPG_RECIPIENT | backup_gpg_recipient | Specify GPG recipient if using encryption for backups. | *No default* |
|
||||
| INVENTREE_BACKUP_DATE_FORMAT | backup_date_format | Date format string used to format timestamps in backup filenames. | `%Y-%m-%d-%H%M%S` |
|
||||
| INVENTREE_BACKUP_DATABASE_FILENAME_TEMPLATE | backup_database_filename_template | Template string used to generate database backup filenames. | `InvenTree-db-{datetime}.{extension}` |
|
||||
| INVENTREE_BACKUP_MEDIA_FILENAME_TEMPLATE | backup_media_filename_template | Template string used to generate media backup filenames. | `InvenTree-media-{datetime}.{extension}` |
|
||||
| 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 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_BACKUP_STORAGE") }} Backup storage backend. Refer to the [storage backend documentation](#storage-backend). |
|
||||
{{ configsetting("INVENTREE_BACKUP_DIR") }} Backup storage directory. |
|
||||
{{ configsetting("INVENTREE_BACKUP_OPTIONS") }} Specific options for the selected storage backend (dict) |
|
||||
{{ configsetting("INVENTREE_BACKUP_CONNECTOR_OPTIONS") }} Specific options for the database connector (dict). Refer to the [database connector options](#database-connector) |
|
||||
{{ 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. |
|
||||
{{ configsetting("INVENTREE_BACKUP_EMAIL_PREFIX") }} Prefix for the subject line of backup-related emails. |
|
||||
{{ configsetting("INVENTREE_BACKUP_GPG_RECIPIENT") }} Specify GPG recipient if using encryption for backups. |
|
||||
{{ configsetting("INVENTREE_BACKUP_DATE_FORMAT") }} Date format string used to format timestamps in backup filenames. |
|
||||
{{ configsetting("INVENTREE_BACKUP_DATABASE_FILENAME_TEMPLATE") }} Template string used to generate database backup filenames.
|
||||
{{ configsetting("INVENTREE_BACKUP_MEDIA_FILENAME_TEMPLATE") }} Template string used to generate media backup filenames. |
|
||||
{{ 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. |
|
||||
|
||||
|
||||
### Storage Backend
|
||||
|
||||
|
||||
+158
-168
@@ -46,6 +46,9 @@ Environment variable settings generally use the `INVENTREE_` prefix, and are all
|
||||
!!! warning "Available Variables"
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_SITE_URL | site_url | Specify a fixed site URL | *Not specified* |
|
||||
| INVENTREE_TIMEZONE | timezone | Server timezone | UTC |
|
||||
| INVENTREE_ADMIN_ENABLED | admin_enabled | Enable the [django administrator interface]({% include "django.html" %}/ref/contrib/admin/) | True |
|
||||
| INVENTREE_ADMIN_URL | admin_url | URL for accessing [admin interface](../settings/admin.md) | admin |
|
||||
| INVENTREE_LANGUAGE | language | Default language | en-us |
|
||||
| INVENTREE_AUTO_UPDATE | auto_update | Database migrations will be run automatically | False |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_SITE_URL") }} Specify a fixed site URL |
|
||||
{{ configsetting("INVENTREE_TIMEZONE") }} Server timezone |
|
||||
{{ configsetting("INVENTREE_ADMIN_ENABLED") }} Enable the [django administrator interface]({% include "django.html" %}/ref/contrib/admin/) |
|
||||
{{ configsetting("INVENTREE_ADMIN_URL") }} URL for accessing [admin interface](../settings/admin.md) |
|
||||
{{ configsetting("INVENTREE_LANGUAGE") }} Default language |
|
||||
{{ configsetting("INVENTREE_AUTO_UPDATE") }} Database migrations will be run automatically |
|
||||
|
||||
### Site URL
|
||||
|
||||
@@ -89,18 +91,17 @@ With "auto update" enabled, the InvenTree server will automatically apply databa
|
||||
|
||||
The following debugging / logging options are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_DEBUG | debug | Enable [debug mode](./index.md#debug-mode) | False |
|
||||
| INVENTREE_DEBUG_QUERYCOUNT | debug_querycount | Enable support for [django-querycount](../develop/index.md#django-querycount) middleware. | False |
|
||||
| INVENTREE_DEBUG_SILK | debug_silk | Enable support for [django-silk](../develop/index.md#django-silk) profiling tool. | False |
|
||||
| INVENTREE_DEBUG_SILK_PROFILING | debug_silk_profiling | Enable detailed profiling in django-silk | False |
|
||||
| INVENTREE_DB_LOGGING | db_logging | Enable logging of database messages | False |
|
||||
| INVENTREE_LOG_LEVEL | log_level | Set level of logging to terminal | WARNING |
|
||||
| INVENTREE_JSON_LOG | json_log | log as json | False |
|
||||
| INVENTREE_WRITE_LOG | write_log | Enable writing of log messages to file at config base | False |
|
||||
| INVENTREE_CONSOLE_LOG | console_log | Enable logging to console | True |
|
||||
| INVENTREE_SCHEMA_LEVEL | schema.level | Set level of added schema extensions detail (0-3) 0 = including no additional detail | 0 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DEBUG") }} Enable [debug mode](./index.md#debug-mode) |
|
||||
{{ configsetting("INVENTREE_DB_LOGGING") }} Enable logging of database messages |
|
||||
{{ configsetting("INVENTREE_LOG_LEVEL") }} Set level of logging to terminal |
|
||||
{{ configsetting("INVENTREE_JSON_LOG") }} Log messages as json |
|
||||
{{ configsetting("INVENTREE_WRITE_LOG") }} Enable writing of log messages to file at config base |
|
||||
{{ configsetting("INVENTREE_CONSOLE_LOG") }} Enable logging to console |
|
||||
{{ configsetting("INVENTREE_SCHEMA_LEVEL") }} Set level of added schema extensions detail (0-3) 0 = including no additional detail |
|
||||
{{ configsetting("INVENTREE_DEBUG_QUERYCOUNT") }} Enable support for [django-querycount](../develop/index.md#django-querycount) middleware. |
|
||||
{{ configsetting("INVENTREE_DEBUG_SILK") }} Enable support for [django-silk](../develop/index.md#django-silk) profiling tool. |
|
||||
| `INVENTREE_DEBUG_SILK_PROFILING` | `debug_silk_profiling` | False | Enable detailed profiling in django-silk |
|
||||
|
||||
### Debug Mode
|
||||
|
||||
@@ -118,26 +119,24 @@ Depending on how your InvenTree installation is configured, you will need to pay
|
||||
!!! danger "Not Secure"
|
||||
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"
|
||||
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 |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_ALLOWED_HOSTS | allowed_hosts | List of allowed hosts | `*` |
|
||||
| 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. |
|
||||
| INVENTREE_CORS_ORIGIN_ALLOW_ALL | cors.allow_all | Allow all remote URLS for CORS checks | `False` |
|
||||
| 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. |
|
||||
| INVENTREE_CORS_ORIGIN_REGEX | cors.regex | List of regular expressions for CORS whitelisted URL patterns | *Empty list* |
|
||||
| INVENTREE_CORS_ALLOW_CREDENTIALS | cors.allow_credentials | Allow cookies in cross-site requests | `True` |
|
||||
| INVENTREE_SITE_LAX_PROTOCOL | site_lax_protocol | Ignore protocol mismatches on INVE-E7 site checks | `True` |
|
||||
| INVENTREE_USE_X_FORWARDED_HOST | use_x_forwarded_host | Use forwarded host header | `False` |
|
||||
| INVENTREE_USE_X_FORWARDED_PORT | use_x_forwarded_port | Use forwarded port header | `False` |
|
||||
| INVENTREE_USE_X_FORWARDED_PROTO | use_x_forwarded_proto | Use forwarded protocol header | `False` |
|
||||
| INVENTREE_SESSION_COOKIE_SECURE | cookie.secure | Enforce secure session cookies | `False` |
|
||||
| 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 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_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) |
|
||||
{{ configsetting("INVENTREE_CORS_ORIGIN_ALLOW_ALL") }} Allow all remote URLS for CORS checks |
|
||||
{{ 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) |
|
||||
{{ configsetting("INVENTREE_CORS_ORIGIN_REGEX") }} List of regular expressions for CORS whitelisted URL patterns |
|
||||
{{ configsetting("INVENTREE_CORS_ALLOW_CREDENTIALS") }} Allow cookies in cross-site requests |
|
||||
{{ configsetting("INVENTREE_SITE_LAX_PROTOCOL") }} Ignore protocol mismatches on INVE-E7 site checks |
|
||||
{{ configsetting("INVENTREE_USE_X_FORWARDED_HOST") }} Use forwarded host header |
|
||||
{{ configsetting("INVENTREE_USE_X_FORWARDED_PORT") }} Use forwarded port header |
|
||||
{{ configsetting("INVENTREE_USE_X_FORWARDED_PROTO") }} Use forwarded protocol header |
|
||||
| `INVENTREE_X_FORWARDED_PROTO_NAME` | `x_forwarded_proto_name` | `HTTP_X_FORWARDED_PROTO` | Name of the header to use for forwarded protocol information |
|
||||
{{ configsetting("INVENTREE_SESSION_COOKIE_SECURE") }} Enforce secure session cookies |
|
||||
{{ 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
|
||||
|
||||
@@ -191,10 +190,9 @@ Django provides a powerful [administrator interface]({% include "django.html" %}
|
||||
|
||||
The following admin site configuration options are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_ADMIN_ENABLED | admin_enabled | Enable the django administrator interface | True |
|
||||
| INVENTREE_ADMIN_URL | admin_url | URL for accessing the admin interface | admin |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_ADMIN_ENABLED") }} Enable the django administrator interface |
|
||||
{{ configsetting("INVENTREE_ADMIN_URL") }} URL for accessing the admin interface |
|
||||
|
||||
!!! warning "Security"
|
||||
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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_ADMIN_USER | admin_user | Admin account username | *Not specified* |
|
||||
| INVENTREE_ADMIN_PASSWORD | admin_password | Admin account password | *Not specified* |
|
||||
| INVENTREE_ADMIN_PASSWORD_FILE | admin_password_file | Admin account password file | *Not specified* |
|
||||
| INVENTREE_ADMIN_EMAIL | admin_email |Admin account email address | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_ADMIN_USER") }} Admin account username |
|
||||
{{ configsetting("INVENTREE_ADMIN_PASSWORD") }} Admin account password |
|
||||
{{ configsetting("INVENTREE_ADMIN_PASSWORD_FILE") }} Admin account password file |
|
||||
{{ configsetting("INVENTREE_ADMIN_EMAIL") }} Admin account email address |
|
||||
|
||||
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.
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_SECRET_KEY | secret_key | Raw secret key value | *Not specified* |
|
||||
| INVENTREE_SECRET_KEY_FILE | secret_key_file | File containing secret key value | *Not specified* |
|
||||
| INVENTREE_OIDC_PRIVATE_KEY | oidc_private_key | Raw private key value | *Not specified* |
|
||||
| INVENTREE_OIDC_PRIVATE_KEY_FILE | oidc_private_key_file | File containing private key value in PEM format | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_SECRET_KEY") }} Raw secret key value |
|
||||
{{ configsetting("INVENTREE_SECRET_KEY_FILE") }} File containing secret key value |
|
||||
{{ configsetting("INVENTREE_OIDC_PRIVATE_KEY") }} Raw private key value |
|
||||
{{ configsetting("INVENTREE_OIDC_PRIVATE_KEY_FILE", default="oidc.pem") }} File containing private key value in PEM format |
|
||||
|
||||
## Database Options
|
||||
|
||||
@@ -253,14 +249,14 @@ Database options are specified under the *database* heading in the configuration
|
||||
|
||||
The following database options can be configured:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_DB_ENGINE | database.ENGINE | Database backend | *Not specified* |
|
||||
| INVENTREE_DB_NAME | database.NAME | Database name | *Not specified* |
|
||||
| INVENTREE_DB_USER | database.USER | Database username (if required) | *Not specified* |
|
||||
| INVENTREE_DB_PASSWORD | database.PASSWORD | Database password (if required) | *Not specified* |
|
||||
| INVENTREE_DB_HOST | database.HOST | Database host address (if required) | *Not specified* |
|
||||
| INVENTREE_DB_PORT | database.PORT | Database host port (if required) | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DB_ENGINE") }} Database backend |
|
||||
{{ configsetting("INVENTREE_DB_NAME") }} Database name |
|
||||
{{ configsetting("INVENTREE_DB_USER") }} Database username (if required) |
|
||||
{{ configsetting("INVENTREE_DB_PASSWORD") }} Database password (if required) |
|
||||
{{ configsetting("INVENTREE_DB_HOST") }} Database host address (if required) |
|
||||
{{ configsetting("INVENTREE_DB_PORT") }} Database host port (if required) |
|
||||
{{ configsetting("INVENTREE_DB_OPTIONS") }} Additional database options (as a JSON object) |
|
||||
|
||||
!!! 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.
|
||||
@@ -269,22 +265,20 @@ The following database options can be configured:
|
||||
|
||||
If running with a PostgreSQL database backend, the following additional options are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_DB_TIMEOUT | database.timeout | Database connection timeout (s) | 2 |
|
||||
| INVENTREE_DB_TCP_KEEPALIVES | database.tcp_keepalives | TCP keepalive | 1 |
|
||||
| INVENTREE_DB_TCP_KEEPALIVES_IDLE | database.tcp_keepalives_idle | Idle TCP keepalive | 1 |
|
||||
| INVENTREE_DB_TCP_KEEPALIVES_INTERVAL | database.tcp_keepalives_interval | TCP keepalive interval | 1|
|
||||
| INVENTREE_DB_TCP_KEEPALIVES_COUNT | database.tcp_keepalives_count | TCP keepalive count | 5 |
|
||||
| INVENTREE_DB_ISOLATION_SERIALIZABLE | database.serializable | Database isolation level configured to "serializable" | False |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DB_TIMEOUT", default="2") }} Database connection timeout (s) |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES` | database.tcp_keepalives | 1 | TCP keepalive |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 1 | Idle TCP keepalive |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 1| TCP keepalive interval |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_COUNT` | database.tcp_keepalives_count | 5 | TCP keepalive count |
|
||||
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||
|
||||
### MySQL Settings
|
||||
|
||||
If running with a MySQL database backend, the following additional options are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_DB_ISOLATION_SERIALIZABLE | database.serializable | Database isolation level configured to "serializable" | False |
|
||||
{{ configtable() }}
|
||||
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||
|
||||
### 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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_DB_TIMEOUT | database.timeout | Database connection timeout (s) | 10 |
|
||||
| INVENTREE_DB_WAL_MODE | database.wal_mode | Enable Write-Ahead Logging (WAL) mode for SQLite databases | True |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
|
||||
| `INVENTREE_DB_WAL_MODE` | database.wal_mode | True | Enable Write-Ahead Logging (WAL) mode for SQLite databases |
|
||||
|
||||
## Caching
|
||||
|
||||
@@ -314,21 +307,21 @@ Enabling global caching requires connection to a redis server (which is separate
|
||||
|
||||
The following cache settings are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_CACHE_ENABLED | cache.enabled | Enable redis caching | False |
|
||||
| INVENTREE_CACHE_HOST | cache.host | Cache server host | *Not specified* |
|
||||
| INVENTREE_CACHE_PORT | cache.port | Cache server port | 6379 |
|
||||
| INVENTREE_CACHE_PASSWORD | cache.password | Cache server password | none |
|
||||
| INVENTREE_CACHE_USER | cache.user | Cache server username | none |
|
||||
| INVENTREE_CACHE_DB | cache.db | Cache server database index | 0 |
|
||||
| INVENTREE_CACHE_CONNECT_TIMEOUT | cache.connect_timeout | Cache connection timeout (seconds) | 3 |
|
||||
| INVENTREE_CACHE_TIMEOUT | cache.timeout | Cache timeout (seconds) | 3 |
|
||||
| INVENTREE_CACHE_TCP_KEEPALIVE | cache.tcp_keepalive | Cache TCP keepalive | True |
|
||||
| INVENTREE_CACHE_KEEPALIVE_COUNT | cache.keepalive_count | Cache keepalive count | 5 |
|
||||
| INVENTREE_CACHE_KEEPALIVE_IDLE | cache.keepalive_idle | Cache keepalive idle | 1 |
|
||||
| INVENTREE_CACHE_KEEPALIVE_INTERVAL | cache.keepalive_interval | Cache keepalive interval | 1 |
|
||||
| INVENTREE_CACHE_USER_TIMEOUT | cache.user_timeout | Cache user timeout | 1000 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_CACHE_ENABLED") }} Enable redis caching |
|
||||
{{ configsetting("INVENTREE_CACHE_HOST") }} Cache server host |
|
||||
{{ configsetting("INVENTREE_CACHE_PORT") }} Cache server port |
|
||||
{{ configsetting("INVENTREE_CACHE_PASSWORD") }} Cache server password |
|
||||
{{ configsetting("INVENTREE_CACHE_USER") }} Cache server username |
|
||||
{{ configsetting("INVENTREE_CACHE_DB") }} Cache server database index |
|
||||
{{ configsetting("INVENTREE_CACHE_CONNECT_TIMEOUT") }} Cache connection timeout (seconds) |
|
||||
{{ configsetting("INVENTREE_CACHE_TIMEOUT") }} Cache timeout (seconds) |
|
||||
{{ configsetting("INVENTREE_CACHE_TCP_KEEPALIVE") }} Cache TCP keepalive |
|
||||
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_COUNT") }} Cache keepalive count |
|
||||
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_IDLE") }} Cache keepalive idle |
|
||||
{{ configsetting("INVENTREE_CACHE_KEEPALIVE_INTERVAL") }} Cache keepalive interval |
|
||||
{{ configsetting("INVENTREE_CACHE_USER_TIMEOUT") }} Cache user timeout |
|
||||
|
||||
|
||||
!!! 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.
|
||||
@@ -339,17 +332,16 @@ To enable [email functionality](../settings/email.md), email settings must be co
|
||||
|
||||
The following email settings are available:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_EMAIL_BACKEND | email.backend | Email backend module | django.core.mail.backends.smtp.EmailBackend |
|
||||
| INVENTREE_EMAIL_HOST | email.host | Email server host | *Not specified* |
|
||||
| INVENTREE_EMAIL_PORT | email.port | Email server port | 25 |
|
||||
| INVENTREE_EMAIL_USERNAME | email.username | Email account username | *Not specified* |
|
||||
| INVENTREE_EMAIL_PASSWORD | email.password | Email account password | *Not specified* |
|
||||
| INVENTREE_EMAIL_TLS | email.tls | Enable STARTTLS support (commonly port 567) | False |
|
||||
| INVENTREE_EMAIL_SSL | email.ssl | Enable legacy SSL/TLS support (commonly port 465) | False |
|
||||
| INVENTREE_EMAIL_SENDER | email.sender | Sending email address | *Not specified* |
|
||||
| INVENTREE_EMAIL_PREFIX | email.prefix | Prefix for subject text | [InvenTree] |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_EMAIL_BACKEND") }} Email backend module |
|
||||
{{ configsetting("INVENTREE_EMAIL_HOST") }} Email server host |
|
||||
{{ configsetting("INVENTREE_EMAIL_PORT") }} Email server port |
|
||||
{{ configsetting("INVENTREE_EMAIL_USERNAME") }} Email account username |
|
||||
{{ configsetting("INVENTREE_EMAIL_PASSWORD") }} Email account password |
|
||||
{{ configsetting("INVENTREE_EMAIL_TLS") }} Enable STARTTLS support (commonly port 567) |
|
||||
{{ configsetting("INVENTREE_EMAIL_SSL") }} Enable legacy SSL/TLS support (commonly port 465) |
|
||||
{{ configsetting("INVENTREE_EMAIL_SENDER") }} Sending email address |
|
||||
{{ configsetting("INVENTREE_EMAIL_PREFIX") }} Prefix for subject text |
|
||||
|
||||
### 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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_STATIC_ROOT | static_root | [Static files](./processes.md#static-files) directory | *Not specified* |
|
||||
| INVENTREE_MEDIA_ROOT | media_root | [Media files](./processes.md#media-files) directory | *Not specified* |
|
||||
| INVENTREE_BACKUP_DIR | backup_dir | Backup files directory | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_STATIC_ROOT") }} [Static files](./processes.md#static-files) directory |
|
||||
{{ configsetting("INVENTREE_MEDIA_ROOT") }} [Media files](./processes.md#media-files) directory |
|
||||
{{ configsetting("INVENTREE_BACKUP_DIR") }} Directory for backup files |
|
||||
|
||||
!!! tip "Serving 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.
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_STORAGE_TARGET | storage.target | Storage target to use for static and media files, valid options: local, s3, sftp | local |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_STORAGE_TARGET") }} Storage target to use for static and media files, valid options: local, s3, sftp |
|
||||
|
||||
|
||||
#### S3
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_S3_ACCESS_KEY | storage.s3.access_key | Access key | *Not specified* |
|
||||
| INVENTREE_S3_SECRET_KEY | storage.s3.secret_key | Secret key | *Not specified* |
|
||||
| INVENTREE_S3_BUCKET_NAME | storage.s3.bucket_name | Bucket name, required by most providers | *Not specified* |
|
||||
| INVENTREE_S3_REGION_NAME | storage.s3.region_name | S3 region name | *Not specified* |
|
||||
| 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 | Sub-Location that should be used | inventree-server |
|
||||
| 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 | Verify SSL certificate for S3 endpoint | True |
|
||||
| INVENTREE_S3_OVERWRITE | storage.s3.overwrite | Overwrite existing files in S3 bucket | False |
|
||||
| INVENTREE_S3_VIRTUAL | storage.s3.virtual | Use virtual addressing style - by default False -> `path` style, `virtual` style if True | False |
|
||||
{{ configtable() }}
|
||||
| `INVENTREE_S3_ACCESS_KEY` | storage.s3.access_key | *Not specified* | Access key |
|
||||
| `INVENTREE_S3_SECRET_KEY` | storage.s3.secret_key | *Not specified* | Secret key |
|
||||
| `INVENTREE_S3_BUCKET_NAME` | storage.s3.bucket_name | *Not specified* | Bucket name, required by most providers |
|
||||
| `INVENTREE_S3_REGION_NAME` | storage.s3.region_name | *Not specified* | S3 region name |
|
||||
| `INVENTREE_S3_ENDPOINT_URL` | storage.s3.endpoint_url | *Not specified* | Custom S3 endpoint URL, defaults to AWS endpoints if not set |
|
||||
| `INVENTREE_S3_LOCATION` | storage.s3.location | inventree-server | Sub-Location that should be used |
|
||||
| `INVENTREE_S3_DEFAULT_ACL` | storage.s3.default_acl | *Not specified* | Default ACL for uploaded files, defaults to provider default if not set |
|
||||
| `INVENTREE_S3_VERIFY_SSL` | storage.s3.verify_ssl | True | Verify SSL certificate for S3 endpoint |
|
||||
| `INVENTREE_S3_OVERWRITE` | storage.s3.overwrite | False | Overwrite existing files in S3 bucket |
|
||||
| `INVENTREE_S3_VIRTUAL` | storage.s3.virtual | False | Use virtual addressing style - by default False -> `path` style, `virtual` style if True |
|
||||
|
||||
#### SFTP
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_SFTP_HOST | storage.sftp.host | SFTP host | *Not specified* |
|
||||
| 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 | SFTP user ID - not required | *Not specified* |
|
||||
| INVENTREE_SFTP_GID | storage.sftp.gid | SFTP group ID - not required | *Not specified* |
|
||||
| INVENTREE_SFTP_LOCATION | storage.sftp.location | Sub-Location that should be used | inventree-server |
|
||||
{{ configtable() }}
|
||||
| `INVENTREE_SFTP_HOST` | storage.sftp.host | *Not specified* | SFTP host |
|
||||
| `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_UID` | storage.sftp.uid | *Not specified* | SFTP user ID - not required |
|
||||
| `INVENTREE_SFTP_GID` | storage.sftp.gid | *Not specified* | SFTP group ID - not required |
|
||||
| `INVENTREE_SFTP_LOCATION` | storage.sftp.location | inventree-server | Sub-Location that should be used |
|
||||
|
||||
## 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.
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_MFA_ENABLED | mfa_enabled | Enable or disable multi-factor authentication support for the InvenTree server | True |
|
||||
| INVENTREE_MFA_SUPPORTED_TYPES | mfa_supported_types | List of supported multi-factor authentication types | recovery_codes,totp,webauthn |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_MFA_ENABLED") }} Enable multi-factor authentication support for the InvenTree server |
|
||||
{{ configsetting("INVENTREE_MFA_SUPPORTED_TYPES") }} List of supported multi-factor authentication types |
|
||||
{{ configsetting("INVENTREE_USE_JWT") }} Enable support for JSON Web Tokens (JWT) for authentication |
|
||||
|
||||
### 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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_LOGIN_CONFIRM_DAYS | login_confirm_days | Duration for which confirmation links are valid | 3 |
|
||||
| INVENTREE_LOGIN_ATTEMPTS | login_attempts | Count of allowed login attempts before blocking user | 5 |
|
||||
| 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* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_LOGIN_CONFIRM_DAYS") }} Duration for which confirmation links are valid |
|
||||
{{ configsetting("INVENTREE_LOGIN_ATTEMPTS") }} Count of allowed login attempts before blocking user |
|
||||
{{ 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)) |
|
||||
|
||||
!!! 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*.
|
||||
@@ -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):
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_BACKGROUND_WORKERS | background.workers | Number of background worker processes | 1 |
|
||||
| INVENTREE_BACKGROUND_TIMEOUT | background.timeout | Timeout for background worker tasks (seconds) | 90 |
|
||||
| INVENTREE_BACKGROUND_RETRY | background.retry | Time to wait before retrying a background task (seconds) | 300 |
|
||||
| INVENTREE_BACKGROUND_MAX_ATTEMPTS | background.max_attempts | Maximum number of attempts for a background task | 5 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_BACKGROUND_WORKERS") }} Number of background worker processes |
|
||||
{{ configsetting("INVENTREE_BACKGROUND_TIMEOUT") }} Timeout for background worker tasks (seconds) |
|
||||
{{ configsetting("INVENTREE_BACKGROUND_RETRY") }} Time to wait before retrying a background task (seconds) |
|
||||
{{ configsetting("INVENTREE_BACKGROUND_MAX_ATTEMPTS") }} Maximum number of attempts for a background task |
|
||||
|
||||
## Sentry Integration
|
||||
|
||||
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 |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_SENTRY_ENABLED | sentry_enabled | Enable sentry.io integration | False |
|
||||
| INVENTREE_SENTRY_DSN | sentry_dsn | Sentry DSN (data source name) key | *Defaults to InvenTree developer key* |
|
||||
| INVENTREE_SENTRY_SAMPLE_RATE | sentry_sample_rate | How often to send data samples | 0.1 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_SENTRY_ENABLED") }} Enable sentry.io integration |
|
||||
{{ configsetting("INVENTREE_SENTRY_DSN", default="Defaults to InvenTree developer key") }} Sentry DSN (data source name) key |
|
||||
{{ configsetting("INVENTREE_SENTRY_SAMPLE_RATE") }} How often to send data samples (seconds) |
|
||||
|
||||
!!! info "Default DSN"
|
||||
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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_CUSTOM_LOGO | customize.logo | Path to custom logo in the static files directory | *Not specified* |
|
||||
| INVENTREE_CUSTOM_SPLASH | customize.splash | Path to custom splash screen in the static files directory | *Not specified* |
|
||||
| INVENTREE_CUSTOMIZE | customize.site_header | Custom site header in the Django admin | InvenTree Admin |
|
||||
| INVENTREE_CUSTOMIZE | customize.login_message | Custom message for login page | *Not specified* |
|
||||
| INVENTREE_CUSTOMIZE | customize.navbar_message | Custom message for navbar | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_CUSTOM_LOGO") }} Path to custom logo in the static files directory |
|
||||
{{ configsetting("INVENTREE_CUSTOM_SPLASH") }} Path to custom splash screen in the static files directory |
|
||||
{{ configsetting("INVENTREE_SITE_HEADER") }} Custom header text for the django admin page |
|
||||
{{ configsetting("INVENTREE_CUSTOMIZE") }} JSON object containing custom messages for the login page, navbar, and Django admin site |
|
||||
|
||||
The INVENTREE_CUSTOMIZE environment variable must contain a json object with the keys from the table above and
|
||||
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:
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_PLUGINS_ENABLED | plugins_enabled | Enable plugin support | False |
|
||||
| INVENTREE_PLUGIN_NOINSTALL | plugin_noinstall | Disable Plugin installation via API - only use plugins.txt file | False |
|
||||
| INVENTREE_PLUGIN_FILE | plugins_plugin_file | Location of plugin installation file | *Not specified* |
|
||||
| INVENTREE_PLUGIN_DIR | plugins_plugin_dir | Location of external plugin directory | *Not specified* |
|
||||
| INVENTREE_PLUGINS_MANDATORY | plugins_mandatory | List of [plugins which are considered mandatory](../plugins/index.md#mandatory-third-party-plugins) | *Not specified* |
|
||||
| INVENTREE_PLUGIN_DEV_SLUG | plugin_dev.slug | Specify plugin to run in [development mode](../plugins/creator.md#backend-configuration) | *Not specified* |
|
||||
| INVENTREE_PLUGIN_DEV_HOST | plugin_dev.host | Specify host for development mode plugin | http://localhost:5174 |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_PLUGINS_ENABLED") }} Enable plugin support |
|
||||
{{ configsetting("INVENTREE_PLUGIN_NOINSTALL") }} Disable Plugin installation via API |
|
||||
{{ configsetting("INVENTREE_PLUGIN_FILE") }} Location of plugin installation file |
|
||||
| `INVENTREE_PLUGIN_DIR` | `plugin_dir` | *Not specified* | Location of external plugin directory |
|
||||
{{ configsetting("INVENTREE_PLUGIN_RETRY") }} Number of tries to attempt loading a plugin before giving up |
|
||||
{{ configsetting("INVENTREE_PLUGINS_MANDATORY") }} List of [plugins which are considered mandatory](../plugins/index.md#mandatory-third-party-plugins) |
|
||||
{{ configsetting("INVENTREE_PLUGIN_DEV_SLUG") }} Specify plugin to run in [development mode](../plugins/creator.md#backend-configuration) |
|
||||
{{ configsetting("INVENTREE_PLUGIN_DEV_HOST") }} Specify host for development mode plugin |
|
||||
|
||||
## 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.
|
||||
|
||||
| Environment Variable | Configuration File | Description | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| INVENTREE_GLOBAL_SETTINGS | global_settings | JSON object containing global settings overrides | *Not specified* |
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_GLOBAL_SETTINGS") }} JSON object containing global settings overrides |
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
Alternatively, admin account details can be specified in the `.env` file, removing the need for this manual step:
|
||||
|
||||
| Variable | Description |
|
||||
| --- | --- |
|
||||
| INVENTREE_ADMIN_USER | Admin account username |
|
||||
| INVENTREE_ADMIN_PASSWORD | Admin account password |
|
||||
| INVENTREE_ADMIN_EMAIL | Admin account email address |
|
||||
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.
|
||||
|
||||
!!! warning "Scrub Account Data"
|
||||
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 |
|
||||
| --- | --- |
|
||||
| INVENTREE_WEB_ADDR | 0.0.0.0 |
|
||||
| INVENTREE_WEB_PORT | 8000 |
|
||||
| `INVENTREE_WEB_ADDR` | 0.0.0.0 |
|
||||
| `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.
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ for key in [
|
||||
print(f' - {key}: {val}')
|
||||
|
||||
# Cached settings dict values
|
||||
global CONFIG_SETTINGS
|
||||
global GLOBAL_SETTINGS
|
||||
global USER_SETTINGS
|
||||
global TAGS
|
||||
@@ -64,6 +65,7 @@ with open(settings_file, encoding='utf-8') as sf:
|
||||
|
||||
GLOBAL_SETTINGS = settings['global']
|
||||
USER_SETTINGS = settings['user']
|
||||
CONFIG_SETTINGS = settings['config']
|
||||
|
||||
# Tags
|
||||
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)
|
||||
|
||||
@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
|
||||
def tags_and_filters():
|
||||
"""Return a list of all tags and filters."""
|
||||
|
||||
@@ -297,7 +297,7 @@ class InfoView(APIView):
|
||||
'instance': InvenTree.version.inventreeInstanceName(),
|
||||
'apiVersion': InvenTree.version.inventreeApiVersion(),
|
||||
'worker_running': is_worker_running(),
|
||||
'worker_count': settings.BACKGROUND_WORKER_COUNT,
|
||||
'worker_count': settings.Q_CLUSTER['workers'],
|
||||
'worker_pending_tasks': self.worker_pending_tasks(),
|
||||
'plugins_enabled': settings.PLUGINS_ENABLED,
|
||||
'plugins_install_disabled': settings.PLUGINS_INSTALL_DISABLED,
|
||||
|
||||
@@ -94,17 +94,17 @@ def get_cache_config(global_cache: bool) -> dict:
|
||||
Returns:
|
||||
A dictionary containing the cache configuration options.
|
||||
"""
|
||||
if global_cache:
|
||||
# Build Redis URL with optional password
|
||||
password = cache_password()
|
||||
user = cache_user() or ''
|
||||
host = cache_host()
|
||||
port = cache_port()
|
||||
db = cache_db()
|
||||
|
||||
if password:
|
||||
redis_url = (
|
||||
f'redis://{user}:{password}@{cache_host()}:{cache_port()}/{cache_db()}'
|
||||
)
|
||||
redis_url = f'redis://{user}:{password}@{host}:{port}/{db}'
|
||||
else:
|
||||
redis_url = f'redis://{cache_host()}:{cache_port()}/{cache_db()}'
|
||||
redis_url = f'redis://{host}:{port}/{db}'
|
||||
|
||||
keepalive_options = {
|
||||
'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),
|
||||
}
|
||||
|
||||
return {
|
||||
global_cache_config = {
|
||||
'BACKEND': 'django_redis.cache.RedisCache',
|
||||
'LOCATION': redis_url,
|
||||
'OPTIONS': {
|
||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
||||
'SOCKET_CONNECT_TIMEOUT': cache_setting(
|
||||
'connect_timeout', 5, typecast=int
|
||||
),
|
||||
'SOCKET_CONNECT_TIMEOUT': cache_setting('connect_timeout', 5, typecast=int),
|
||||
'SOCKET_TIMEOUT': cache_setting('timeout', 3, typecast=int),
|
||||
'CONNECTION_POOL_KWARGS': {
|
||||
'socket_keepalive': cache_setting(
|
||||
'tcp_keepalive', True, typecast=bool
|
||||
),
|
||||
'socket_keepalive': cache_setting('tcp_keepalive', True, typecast=bool),
|
||||
'socket_keepalive_options': {
|
||||
# Only include options which are available on this platform
|
||||
# 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
|
||||
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):
|
||||
"""Set lookup metadata for the setting."""
|
||||
global CONFIG_LOOKUPS
|
||||
|
||||
key = env_var or config_key
|
||||
CONFIG_LOOKUPS[key] = {
|
||||
'env_var': env_var,
|
||||
'config_key': config_key,
|
||||
'default_value': default_value,
|
||||
'source': source,
|
||||
'accessed': datetime.datetime.now(),
|
||||
}
|
||||
@@ -544,13 +547,14 @@ def get_frontend_settings(debug=True):
|
||||
'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
|
||||
# This is the UI path e.g. '/web/'
|
||||
if 'base_url' not in frontend_settings:
|
||||
frontend_settings['base_url'] = (
|
||||
get_setting('INVENTREE_FRONTEND_URL_BASE', 'frontend_url_base', 'web')
|
||||
or 'web'
|
||||
)
|
||||
frontend_settings['base_url'] = base_url
|
||||
|
||||
# If provided, specify the API host
|
||||
api_host = frontend_settings.get('api_host', None) or get_setting(
|
||||
|
||||
@@ -24,8 +24,9 @@ class Command(BaseCommand):
|
||||
def handle(self, *args, **kwargs):
|
||||
"""Export settings information to a JSON file."""
|
||||
from common.models import InvenTreeSetting, InvenTreeUserSetting
|
||||
from InvenTree.config import CONFIG_LOOKUPS
|
||||
|
||||
settings = {'global': {}, 'user': {}}
|
||||
settings = {'global': {}, 'user': {}, 'config': {}}
|
||||
|
||||
# Global settings
|
||||
for key, setting in InvenTreeSetting.SETTINGS.items():
|
||||
@@ -45,6 +46,18 @@ class Command(BaseCommand):
|
||||
'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')
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""Configuration settings specific to a particular database backend."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import structlog
|
||||
|
||||
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')
|
||||
|
||||
|
||||
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):
|
||||
"""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 os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
@@ -33,7 +32,16 @@ from InvenTree.version import checkMinPythonVersion, inventreeCommitHash
|
||||
from users.oauth2_scopes import oauth2_scopes
|
||||
|
||||
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:
|
||||
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
|
||||
DOCKER = get_boolean_setting('INVENTREE_DOCKER', default_value=False)
|
||||
|
||||
AUTO_UPDATE = get_boolean_setting('INVENTREE_AUTO_UPDATE', 'auto_update', False)
|
||||
|
||||
# Configure logging settings
|
||||
LOG_LEVEL = get_setting('INVENTREE_LOG_LEVEL', 'log_level', 'WARNING')
|
||||
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 development settings
|
||||
PLUGIN_DEV_SLUG = (
|
||||
get_setting('INVENTREE_PLUGIN_DEV_SLUG', 'plugin_dev.slug') if DEBUG else None
|
||||
)
|
||||
PLUGIN_DEV_SLUG = get_setting('INVENTREE_PLUGIN_DEV_SLUG', 'plugin_dev.slug')
|
||||
|
||||
PLUGIN_DEV_HOST = get_setting(
|
||||
'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
|
||||
# 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
|
||||
)
|
||||
and DEBUG
|
||||
)
|
||||
|
||||
if DJANGO_SILK_ENABLED: # pragma: no cover
|
||||
MIDDLEWARE.append('silk.middleware.SilkyMiddleware')
|
||||
@@ -401,8 +412,11 @@ if DJANGO_SILK_ENABLED: # pragma: no cover
|
||||
|
||||
# In DEBUG mode, add support for 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
|
||||
)
|
||||
and DEBUG
|
||||
):
|
||||
MIDDLEWARE.append('querycount.middleware.QueryCountMiddleware')
|
||||
logger.debug('Running with debug_querycount middleware enabled')
|
||||
@@ -437,14 +451,14 @@ AUTHENTICATION_BACKENDS = (
|
||||
|
||||
# LDAP support
|
||||
LDAP_AUTH = get_boolean_setting('INVENTREE_LDAP_ENABLED', 'ldap.enabled', False)
|
||||
if LDAP_AUTH: # pragma: no cover
|
||||
import django_auth_ldap.config # type: ignore[unresolved-import]
|
||||
import ldap # type: ignore[unresolved-import]
|
||||
LDAP_DEBUG = (
|
||||
get_boolean_setting('INVENTREE_LDAP_DEBUG', 'ldap.debug', False) and LDAP_AUTH
|
||||
)
|
||||
|
||||
if LDAP_AUTH: # pragma: no cover
|
||||
AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend')
|
||||
|
||||
# debug mode to troubleshoot configuration
|
||||
LDAP_DEBUG = get_boolean_setting('INVENTREE_LDAP_DEBUG', 'ldap.debug', False)
|
||||
if LDAP_DEBUG:
|
||||
if 'loggers' not in LOGGING:
|
||||
LOGGING['loggers'] = {}
|
||||
@@ -453,113 +467,10 @@ if LDAP_AUTH: # pragma: no cover
|
||||
'handlers': DEFAULT_LOG_HANDLER,
|
||||
}
|
||||
|
||||
# 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
|
||||
# Determine LDAP settings
|
||||
ldap_settings = ldap.get_ldap_config(debug=LDAP_DEBUG)
|
||||
globals().update(ldap_settings)
|
||||
|
||||
# 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
|
||||
if DEBUG:
|
||||
@@ -642,107 +553,11 @@ Configure the database backend based on the user-specified values.
|
||||
|
||||
logger.debug('Configuring database backend:')
|
||||
|
||||
# Extract database configuration from the config.yaml file
|
||||
db_config = CONFIG.get('database', None) if CONFIG else None
|
||||
# Load database configuration from the config file and environment variables
|
||||
database = db_backend.get_db_backend()
|
||||
DB_ENGINE = database['ENGINE']
|
||||
|
||||
if not db_config:
|
||||
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}
|
||||
DATABASES = {'default': database}
|
||||
|
||||
# login settings
|
||||
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)
|
||||
|
||||
# OpenTelemetry tracing
|
||||
TRACING_ENABLED = get_boolean_setting(
|
||||
'INVENTREE_TRACING_ENABLED', 'tracing.enabled', False
|
||||
)
|
||||
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
|
||||
),
|
||||
}
|
||||
TRACING_ENABLED = (
|
||||
get_boolean_setting('INVENTREE_TRACING_ENABLED', 'tracing.enabled', False)
|
||||
and not isRunningBackup()
|
||||
)
|
||||
|
||||
# Run tracing/logging instrumentation
|
||||
setup_tracing(**TRACING_DETAILS)
|
||||
setup_instruments(DB_ENGINE)
|
||||
else:
|
||||
logger.warning('OpenTelemetry tracing not enabled because endpoint is not set')
|
||||
|
||||
# endregion
|
||||
TRACING_DETAILS: Optional[dict] = tracing.configure_tracing(
|
||||
DB_ENGINE, TRACING_ENABLED, inventree_tags
|
||||
)
|
||||
|
||||
# Cache configuration
|
||||
GLOBAL_CACHE_ENABLED = is_global_cache_enabled()
|
||||
|
||||
CACHES = {'default': get_cache_config(GLOBAL_CACHE_ENABLED)}
|
||||
|
||||
BACKGROUND_WORKER_TIMEOUT = int(
|
||||
get_setting('INVENTREE_BACKGROUND_TIMEOUT', 'background.timeout', 90)
|
||||
# Background task processing with django-q
|
||||
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']
|
||||
|
||||
# Password validation
|
||||
@@ -976,10 +686,10 @@ INTERNAL_EMAIL_BACKEND = get_setting(
|
||||
)
|
||||
|
||||
# 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_HOST_USER = get_setting('INVENTREE_EMAIL_USERNAME', 'email.username', '')
|
||||
EMAIL_HOST_PASSWORD = get_setting('INVENTREE_EMAIL_PASSWORD', 'email.password', '')
|
||||
EMAIL_HOST_USER = get_setting('INVENTREE_EMAIL_USERNAME', 'email.username')
|
||||
EMAIL_HOST_PASSWORD = get_setting('INVENTREE_EMAIL_PASSWORD', 'email.password')
|
||||
EMAIL_USE_TLS = get_boolean_setting('INVENTREE_EMAIL_TLS', 'email.tls', False)
|
||||
EMAIL_USE_SSL = get_boolean_setting('INVENTREE_EMAIL_SSL', 'email.ssl', False)
|
||||
# Anymail
|
||||
@@ -1150,16 +860,14 @@ LANGUAGE_COOKIE_SAMESITE = COOKIE_MODE
|
||||
- Otherwise, use the value specified in the configuration file (or env var)
|
||||
"""
|
||||
COOKIE_SECURE = (
|
||||
False
|
||||
if DEBUG
|
||||
else (
|
||||
SESSION_COOKIE_SAMESITE == 'None'
|
||||
or get_boolean_setting(
|
||||
'INVENTREE_SESSION_COOKIE_SECURE', 'cookie.secure', False
|
||||
)
|
||||
)
|
||||
get_boolean_setting('INVENTREE_SESSION_COOKIE_SECURE', 'cookie.secure', False)
|
||||
or SESSION_COOKIE_SAMESITE == 'None'
|
||||
)
|
||||
|
||||
# Override COOKIE_SECURE value in DEBUG mode
|
||||
if DEBUG:
|
||||
COOKIE_SECURE = False
|
||||
|
||||
CSRF_COOKIE_SECURE = COOKIE_SECURE
|
||||
SESSION_COOKIE_SECURE = COOKIE_SECURE
|
||||
LANGUAGE_COOKIE_SECURE = COOKIE_SECURE
|
||||
|
||||
@@ -29,7 +29,6 @@ from maintenance_mode.core import (
|
||||
from opentelemetry import trace
|
||||
|
||||
from common.settings import get_global_setting, set_global_setting
|
||||
from InvenTree.config import get_setting
|
||||
from plugin import registry
|
||||
|
||||
from .version import isInvenTreeUpToDate
|
||||
@@ -822,7 +821,7 @@ def check_for_migrations(force: bool = False, reload_registry: bool = True) -> b
|
||||
set_pending_migrations(n)
|
||||
|
||||
# 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')
|
||||
return False
|
||||
|
||||
|
||||
@@ -381,7 +381,16 @@ class ConfigSerializer(serializers.Serializer):
|
||||
"""Return the configuration data as a dictionary."""
|
||||
if not isinstance(instance, str):
|
||||
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):
|
||||
|
||||
@@ -1864,8 +1864,13 @@ def export_definitions(c, basedir: str = ''):
|
||||
"""Export various definitions."""
|
||||
if basedir != '' and basedir.endswith('/') is False:
|
||||
basedir += '/'
|
||||
|
||||
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 = [
|
||||
base_path.joinpath('inventree_settings.json'),
|
||||
base_path.joinpath('inventree_tags.yml'),
|
||||
@@ -2298,11 +2303,18 @@ def doc_schema(c):
|
||||
help={
|
||||
'address': 'Host and port to run the server on (default: localhost:8080)',
|
||||
'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."""
|
||||
# Extract settings definitions
|
||||
if export_settings:
|
||||
export_definitions(c, basedir='docs')
|
||||
|
||||
if compile_schema:
|
||||
|
||||
Reference in New Issue
Block a user