From c49c1f7633cdcf8930210c283c22801dcb5f271e Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Tue, 30 Jul 2024 19:02:56 -0400 Subject: [PATCH 1/4] [qa] Automatic reformatting of code and docs --- .coveragerc | 10 - CHANGES.rst | 455 ++- CONTRIBUTING.rst | 3 +- README.rst | 3258 +++++++++-------- openwisp_controller/admin.py | 1 + .../config/base/multitenancy.py | 1 - openwisp_controller/config/base/vpn.py | 108 +- .../config/migrations/0003_template_tags.py | 1 - .../migrations/0004_add_device_model.py | 1 - .../migrations/0006_config_device_not_null.py | 1 - .../config/migrations/0007_simplify_config.py | 1 - .../config/migrations/0008_update_indexes.py | 1 - .../config/migrations/0009_device_system.py | 1 - .../migrations/0010_auto_20180106_1814.py | 1 - .../0011_update_device_mac_address.py | 1 - .../migrations/0012_auto_20180219_1501.py | 1 - ...ast_ip_management_ip_and_status_applied.py | 1 - .../migrations/0014_device_hardware_id.py | 1 - ...plate_name_organization_unique_together.py | 1 - .../config/migrations/0018_config_context.py | 1 - ...ac_add_hardware_id_name_unique_together.py | 1 - .../0020_remove_config_organization.py | 1 - .../config/migrations/0021_vpn_key.py | 1 - .../config/migrations/0022_vpn_format_dh.py | 1 - .../config/migrations/0023_update_context.py | 1 - .../migrations/0024_update_context_data.py | 1 - .../migrations/0025_update_device_key.py | 1 - .../migrations/0026_hardware_id_not_unique.py | 1 - .../0027_add_indexes_on_ip_fields.py | 1 - .../0028_template_default_values.py | 1 - .../0029_merge_django_netjsonconfig.py | 1 - .../migrations/0030_django_taggit_update.py | 1 - .../migrations/0031_update_vpn_dh_param.py | 1 - .../0032_update_legacy_vpn_backend.py | 1 - .../0033_name_unique_per_organization.py | 1 - .../migrations/0034_template_required.py | 1 - .../0035_device_name_unique_optional.py | 1 - .../config/migrations/0036_device_group.py | 1 - .../migrations/0037_alter_taggedtemplate.py | 1 - .../config/migrations/0038_vpn_subnet.py | 1 - .../migrations/0039_wireguard_vxlan_ipam.py | 1 - .../migrations/0040_vpnclient_ip_setnull.py | 1 - ...s_organizationconfigsettings_permission.py | 1 - .../0042_multiple_wireguard_tunnels.py | 1 - .../migrations/0043_devicegroup_templates.py | 1 - .../migrations/0044_config_error_reason.py | 1 - .../0045_alter_vpn_webhook_endpoint.py | 1 - .../migrations/0046_organizationlimits.py | 1 - .../migrations/0047_add_organizationlimits.py | 1 - .../0048_wifi_radio_band_migration.py | 1 - .../migrations/0049_devicegroup_context.py | 1 - .../0050_alter_vpnclient_unique_together.py | 1 - ...0051_organizationconfigsettings_context.py | 1 - .../migrations/0052_vpn_node_network_id.py | 1 - .../migrations/0053_vpnclient_secret.py | 1 - openwisp_controller/config/static/support.css | 4 + openwisp_controller/config/tasks_zerotier.py | 1 - .../config/tests/test_admin.py | 1 - .../config/tests/test_controller.py | 1 - .../config/tests/test_notifications.py | 1 - openwisp_controller/config/tests/utils.py | 1 + .../connection/migrations/0001_initial.py | 1 - .../migrations/0002_credentials_auto_add.py | 1 - .../migrations/0004_django3_1_upgrade.py | 1 - .../0005_device_connection_failure_reason.py | 1 - .../0006_name_unique_per_organization.py | 1 - .../connection/migrations/0007_command.py | 1 - ...08_remove_conflicting_deviceconnections.py | 1 - ..._alter_deviceconnection_unique_together.py | 1 - openwisp_controller/connection/tests/utils.py | 1 - .../geo/migrations/0001_initial.py | 1 - ...alter_devicelocation_floorplan_location.py | 1 - openwisp_controller/pki/base/models.py | 1 - .../pki/migrations/0001_initial.py | 1 - .../migrations/0002_add_organization_name.py | 1 - .../pki/migrations/0004_auto_20180106_1814.py | 1 - .../0005_organizational_unit_name.py | 1 - .../0006_add_x509_passphrase_field.py | 1 - .../migrations/0008_serial_number_length.py | 1 - .../0009_common_name_maxlength_64.py | 1 - .../0010_common_name_organization_unique.py | 1 - ...1_disallowed_blank_key_length_or_digest.py | 1 - .../migrations/0001_initial.py | 1 - .../0003_related_field_allow_blank.py | 1 - .../migrations/0004_index_rule_on_delete.py | 1 - .../0005_number_of_subnets_and_ips.py | 1 - pyproject.toml | 24 + setup.cfg | 10 - .../sample_config/migrations/0001_initial.py | 1 - .../0003_name_unique_per_organization.py | 1 - .../migrations/0004_devicegroup_templates.py | 1 - .../0005_add_organizationalloweddevice.py | 1 - .../migrations/0001_initial.py | 1 - .../0003_name_unique_per_organization.py | 1 - .../sample_geo/migrations/0001_initial.py | 1 - ...alter_devicelocation_floorplan_location.py | 1 - .../sample_pki/migrations/0001_initial.py | 1 - ...3_disallowed_blank_key_length_or_digest.py | 1 - .../migrations/0001_initial.py | 1 - .../sample_users/migrations/0001_initial.py | 1 - .../migrations/0004_default_groups.py | 1 - tests/openwisp2/sample_users/tests.py | 1 - 102 files changed, 2090 insertions(+), 1876 deletions(-) delete mode 100644 .coveragerc create mode 100644 openwisp_controller/config/static/support.css create mode 100644 pyproject.toml diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 511d53593..000000000 --- a/.coveragerc +++ /dev/null @@ -1,10 +0,0 @@ -[run] -omit = - /*/test* - /tests - /*/__init__.py - /setup.py - /*/migrations/* -source = openwisp_controller -parallel = true -concurrency = multiprocessing diff --git a/CHANGES.rst b/CHANGES.rst index 899d22b6d..147c62f34 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,22 +23,22 @@ Version 1.0.2 [2022-07-01] Bugfixes ~~~~~~~~ -- Fixed `device's "changed" signals emitting on the creation - of new device `_ -- Fixed *django-reversion's* recovery buttons were hidden from users - of the "Operator" group in the admin dashboard of ``Certificate`` and ``CA`` - models +- Fixed `device's "changed" signals emitting on the creation of new device + `_ +- Fixed *django-reversion's* recovery buttons were hidden from users of + the "Operator" group in the admin dashboard of ``Certificate`` and + ``CA`` models - Removed `hardcoded static URLs - `_ - which created issues when static files are served using an - external service (e.g. S3 storage buckets) -- Fixed `permissions for "Operator" and "Administrator" groups to - access "OrganizationConfigSettings" objects + `_ which + created issues when static files are served using an external service + (e.g. S3 storage buckets) +- Fixed `permissions for "Operator" and "Administrator" groups to access + "OrganizationConfigSettings" objects `_ - Fixed `support for multiple wireguard tunnels on the same devices `_ -- Fixed `"/api/v1/controller/device/{id}/" REST API endpoint not - updating the device's configuration backend +- Fixed `"/api/v1/controller/device/{id}/" REST API endpoint not updating + the device's configuration backend `_ Version 1.0.1 [2022-05-11] @@ -47,17 +47,13 @@ Version 1.0.1 [2022-05-11] Bugfixes ~~~~~~~~ -- Admin: show main group information in ``DeviceGroupAdmin`` list: - - name - - organization - - modified - - created -- Fixed uncaught exception triggered on the deletion of - VPN client certificates +- Admin: show main group information in ``DeviceGroupAdmin`` list: - name + - organization - modified - created +- Fixed uncaught exception triggered on the deletion of VPN client + certificates - SSH connection: fixed OpenWrt <= 19 authentication failure -- The SSH connection is now explicitly closed when - the authentication fails to avoid leaving lingering SSH - connection objects open +- The SSH connection is now explicitly closed when the authentication + fails to avoid leaving lingering SSH connection objects open Version 1.0.0 [2022-04-29] -------------------------- @@ -89,42 +85,43 @@ Features - Added caching for ``DeviceChecksumView`` - Added support for ED25519 SSH keys in ``Credentials`` - Added `Device Groups - `_ - to organize devices of a particular organization -- Configuration push updates now use the SIGUSR1 signal to reload openwisp-config + `_ to + organize devices of a particular organization +- Configuration push updates now use the SIGUSR1 signal to reload + openwisp-config - The device list admin page now allows to search for location address Changes ~~~~~~~ Backward incompatible changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++++++++++++++++++++++++++++++ -- Since django-sortedm2m, the widget we use to implement ordered templates, - clears all the many to many relationships every time it has to make changes, - we had to stop deleting ``VpnClient`` instances related to VPN templates - on ``post_clear`` m2m signals - If you wrote any custom derivative which relies on calls like +- Since django-sortedm2m, the widget we use to implement ordered + templates, clears all the many to many relationships every time it has + to make changes, we had to stop deleting ``VpnClient`` instances related + to VPN templates on ``post_clear`` m2m signals If you wrote any custom + derivative which relies on calls like ``device.config.templates.clear()`` to delete related ``VpnClient`` instances and their x509 certificates, you will have to update your code - to remove all the templates using their primary keys, - instead of using ``clear()`` -- The default behavior for the resolution of conflicting management - IPs between devices of different organizations has been changed; - by default, in this new version, the system assumes it's using only - 1 management tunnel for all the organizations, so different devices - from any organization will not have the same management IP to avoid - conflicts. The old behaviour can be restored by setting + to remove all the templates using their primary keys, instead of using + ``clear()`` +- The default behavior for the resolution of conflicting management IPs + between devices of different organizations has been changed; by default, + in this new version, the system assumes it's using only 1 management + tunnel for all the organizations, so different devices from any + organization will not have the same management IP to avoid conflicts. + The old behaviour can be restored by setting `OPENWISP_CONTROLLER_SHARED_MANAGEMENT_IP_ADDRESS_SPACE `_ to ``False`` -- ``OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST`` has been renamed - to ``OPENWISP_CONTROLLER_CONFIG_BACKEND_FIELD_SHOWN`` +- ``OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST`` has been renamed to + ``OPENWISP_CONTROLLER_CONFIG_BACKEND_FIELD_SHOWN`` - ``Device.check_management_ip_changed`` has been changed to private API ``Device._check_management_ip_changed`` Dependencies -^^^^^^^^^^^^ +++++++++++++ - Dropped support for Python 3.6 - Dropped support for Django 2.2 @@ -151,38 +148,37 @@ Dependencies - Added django-cache-memoize to 0.1 Other changes -^^^^^^^^^^^^^ ++++++++++++++ - `Reworked implementation of config_modified signal `_: - - the signal is now always emitted on templates changes m2m events, - also if ``config.status`` is modified, with the differences that - only post_add and post_remove m2m events are used, while - ``post_clear`` is ignored, which fixes the duplicate signal emission - caused by the implementation of sortedm2m; + - the signal is now always emitted on templates changes m2m events, also + if ``config.status`` is modified, with the differences that only + post_add and post_remove m2m events are used, while ``post_clear`` is + ignored, which fixes the duplicate signal emission caused by the + implementation of sortedm2m; - added ``action`` and ``previous_status`` arguments, which allow to understand where the ``config_modified`` signal is being emitted from, - this allows more advanced usage of the signal by custom implementations + this allows more advanced usage of the signal by custom + implementations -- Context variable follows template order: - If two or more applied templates have "default_values" with the same keys, - then the context variables of the template which comes later in the order - will be used +- Context variable follows template order: If two or more applied + templates have "default_values" with the same keys, then the context + variables of the template which comes later in the order will be used - New credentials created with ``auto_add`` set to ``True`` will get added to the existing devices in a background task. This improves the responsiveness of the web application - Decoupled admin LogEntry from Template model -- Device admin only lists relevant templates, i.e. - templates that are shared or belong to the device's organization +- Device admin only lists relevant templates, i.e. templates that are + shared or belong to the device's organization - Improved UX of `system-defined variables `_ -- Name of ``Vpn``, ``Template`` and ``Credentials`` objects is - unique only within the same organization and within the shared - objects -- Added functionality to configure connection failure reasons - for which the system should not send notifications. - Added ``old_failure_reason`` parameter in +- Name of ``Vpn``, ``Template`` and ``Credentials`` objects is unique only + within the same organization and within the shared objects +- Added functionality to configure connection failure reasons for which + the system should not send notifications. Added ``old_failure_reason`` + parameter in ``openwisp_controller.connection.signals.is_working_changed`` signal - Allowed searching devices using their location address in Device admin. - Removed deprecated ``api/device-location/`` endpoint @@ -192,28 +188,29 @@ Other changes Bugfixes ~~~~~~~~ -- Fixed a bug which caused ``VpnClient`` instances to be recreated every time - the configuration templates of a device were changed, - which caused x590 certificates to be destroyed and recreated as well -- Hardened config validation of OpenVPN backend. The validation fails - if the ``openvpn`` key is missing from the configuration -- Fixed a bug that caused issues in updating related ``Config`` whenever - a template's ``default_values`` were changed +- Fixed a bug which caused ``VpnClient`` instances to be recreated every + time the configuration templates of a device were changed, which caused + x590 certificates to be destroyed and recreated as well +- Hardened config validation of OpenVPN backend. The validation fails if + the ``openvpn`` key is missing from the configuration +- Fixed a bug that caused issues in updating related ``Config`` whenever a + template's ``default_values`` were changed - Fixed pop-up view of CA and Cert not displaying data -- Fixed config status stays ``applied`` after clearing all device templates +- Fixed config status stays ``applied`` after clearing all device + templates - Fixed ``VpnClient`` not created when multiple VPN templates are added -- Fixed configuration editor raising validation error when using variables in - fields with ``maxLength`` set +- Fixed configuration editor raising validation error when using variables + in fields with ``maxLength`` set - Fixed connection notifications reporting outdated status -- Fixed migrations referencing non-swappable OpenWISP modules that - broke OpenWISP's extensibility +- Fixed migrations referencing non-swappable OpenWISP modules that broke + OpenWISP's extensibility - Fixed bugs in restoring deleted devices using ``django-reversion`` - Fixed cloning of shared templates -- Disallowed blank values for ``key_length`` or ``digest`` fields for ``CA`` - and ``Cert`` objects +- Disallowed blank values for ``key_length`` or ``digest`` fields for + ``CA`` and ``Cert`` objects - Fixed template ordering bug in the configuration preview on Device admin - The order of templates was not always retained when - generating the preview of a config object + The order of templates was not always retained when generating the + preview of a config object Version 0.8.4 [2021-04-09] -------------------------- @@ -221,26 +218,34 @@ Version 0.8.4 [2021-04-09] Bugfixes ~~~~~~~~ -- Fixed `bug in connection module `_ - that raised ``UnicodeDecodeError``, improved logging and ignored unicode +- Fixed `bug in connection module + `_ that + raised ``UnicodeDecodeError``, improved logging and ignored unicode conversion issues -- Fixed `context loading from default values of templates overwriting system - defined variables `_ - in device admin -- Fixed `default template selection not updating after changing backend field `_ - in device admin +- Fixed `context loading from default values of templates overwriting + system defined variables + `_ in device + admin +- Fixed `default template selection not updating after changing backend + field `_ in + device admin - Fixed JSONSchema widget to enable working with a single schema -- Fixed `related configuration not getting updated after template "default_values" are changed `_ -- Fixed `bug which caused the unsaved changes alert in device admin `_ - when location of device is present -- Fixed `bug replacing manually entered device information with empty string `_ -- Fixed `multiple requests for fetching default template values in device admin `_ +- Fixed `related configuration not getting updated after template + "default_values" are changed + `_ +- Fixed `bug which caused the unsaved changes alert in device admin + `_ when + location of device is present +- Fixed `bug replacing manually entered device information with empty + string `_ +- Fixed `multiple requests for fetching default template values in device + admin `_ Security ~~~~~~~~ -- Patched security bugs in internal HTTP endpoints which allowed to obtain UUID - of other organizations and other sensitive information +- Patched security bugs in internal HTTP endpoints which allowed to obtain + UUID of other organizations and other sensitive information Version 0.8.3 [2020-12-18] -------------------------- @@ -250,7 +255,8 @@ Bugfixes - Increased minimum `openwisp-users version to ~=0.5.1 `_, - which fixes an `issue in the production setup `_ + which fixes an `issue in the production setup + `_ Version 0.8.2 [2020-12-11] -------------------------- @@ -258,15 +264,17 @@ Version 0.8.2 [2020-12-11] Bugfixes ~~~~~~~~ -- Fixed the `bug `_ - that prevented users from adding/editing access credentials. +- Fixed the `bug + `_ that + prevented users from adding/editing access credentials. Changes ~~~~~~~ -- Increased `django-x509 `_ - version to 0.9.2 -- Increased `django-flat-json-widget `_ +- Increased `django-x509 + `_ version to 0.9.2 +- Increased `django-flat-json-widget + `_ version to 0.1.2 - Changed the `preview` button colors for better readability - Added *help text* for *device name* field @@ -277,7 +285,8 @@ Version 0.8.1 [2020-12-02] Bugfixes ~~~~~~~~ -- Fixed tests that were dependent on specific settings of the Django project. +- Fixed tests that were dependent on specific settings of the Django + project. Version 0.8.0 [2020-11-23] -------------------------- @@ -290,58 +299,80 @@ Features - Added flat JSON widget for configuration variables - Added JSON Schema widget to credentials admin - Added ``device_registered`` signal -- Added `OpenWISP Notifications `_ - module as a dependency, which brings support for - web and email notifications for important events -- Allow using a different device model in update_config: - his allows `OpenWISP Monitoring `_ - to override the ``can_be_updated`` method to take into account the monitoring status, - so that push updates won't be attempted +- Added `OpenWISP Notifications + `_ + module as a dependency, which brings support for web and email + notifications for important events +- Allow using a different device model in update_config: his allows + `OpenWISP Monitoring + `_ + to override the ``can_be_updated`` method to take into account the + monitoring status, so that push updates won't be attempted - Added notifications for changes of ``is_working`` status of credentials - UX, automatically add/remove default values to device context: - automatically add or remove default values of templates to the configuration context - (a.k.a. configuration variables) when templates are added or removed from devices + automatically add or remove default values of templates to the + configuration context (a.k.a. configuration variables) when templates + are added or removed from devices - UX: added `system defined variables - `_ section + `_ + section Changes ~~~~~~~ -- **Backward incompatible**: the code of `django-netjsonconfig `_ - was merged in openwisp-controller to simplify maintenance -- Changed API of ``device_location`` view for consistency: ``/api/device-location/{id}/`` - becomes ``/api/v1/device/{id}/location/``, the old URL is kept for backward compatibility - but will be removed in the future -- **Backward incompatible change**: schema url endpoint changed to ``/config/schema.json`` - and it's now in config namespace instead of admin namespace -- Changed VPN DH length to 2048 and move its generation to the background because it's a lot slower +- **Backward incompatible**: the code of `django-netjsonconfig + `_ was merged in + openwisp-controller to simplify maintenance +- Changed API of ``device_location`` view for consistency: + ``/api/device-location/{id}/`` becomes + ``/api/v1/device/{id}/location/``, the old URL is kept for backward + compatibility but will be removed in the future +- **Backward incompatible change**: schema url endpoint changed to + ``/config/schema.json`` and it's now in config namespace + instead of admin namespace +- Changed VPN DH length to 2048 and move its generation to the background + because it's a lot slower - Admin: Order Device, Template and VPN alphabetically by default -- Admin: Added ``mac_address`` field to the device list page (``DeviceAdmin.list_display``) +- Admin: Added ``mac_address`` field to the device list page + (``DeviceAdmin.list_display``) - Increased ``max_length`` of common name to ``64`` - Changed the config apply logic to avoid restarting the openwisp-config deamon if the configuration apply procedure is already being run - Made template ``config`` field required in most cases -- Changed ``DeviceConnection.failure_reason`` field to ``TextField``, - this avoids possible exception if ``failed_reason`` is very long, - which may happen in some corner cases -- Made Device ``verbose_name`` configurable, see ``OPENWISP_CONTROLLER_DEVICE_VERBOSE_NAME`` -- Increased `netjsonconfig `__ version to 0.9.x - (which brings support for new interface types, - `see the change log of netjsonconfig `_ +- Changed ``DeviceConnection.failure_reason`` field to ``TextField``, this + avoids possible exception if ``failed_reason`` is very long, which may + happen in some corner cases +- Made Device ``verbose_name`` configurable, see + ``OPENWISP_CONTROLLER_DEVICE_VERBOSE_NAME`` +- Increased `netjsonconfig + `__ version to + 0.9.x (which brings support for new interface types, `see the change log + of netjsonconfig + `_ for more information) -- Increased `django-x509 `_ version to 0.9.x -- Increased `django-loci `_ version to 0.4.x - (which brings many bug fixes to the mapping feature, as long as support for - geo-coding and reverse geo-coding, - `see the change log of django-loci `_ +- Increased `django-x509 + `_ version to 0.9.x +- Increased `django-loci + `_ version to 0.4.x + (which brings many bug fixes to the mapping feature, as long as support + for geo-coding and reverse geo-coding, `see the change log of + django-loci + `_ for more information) -- Increased `openwisp-users `__ version from 0.2.x to 0.5.x - (which brings many interesting improvements to multi-tenancy, - `see the change log of openwisp-users `_ +- Increased `openwisp-users + `__ version + from 0.2.x to 0.5.x (which brings many interesting improvements to + multi-tenancy, `see the change log of openwisp-users + `_ for more information) -- Increased `django-taggit `_ version to 1.3.x -- Increased `openwisp-utils `__ version to 0.7.x -- Increased `django-rest-framework-gis `_ version to 0.16.x +- Increased `django-taggit `_ + version to 1.3.x +- Increased `openwisp-utils + `__ version + to 0.7.x +- Increased `django-rest-framework-gis + `_ version to + 0.16.x - Added support for django 3.1 Bugfixes @@ -356,31 +387,33 @@ Bugfixes - Avoid triggering ``config_modified`` signal during registration - UI: Fixed whitespace after overview tab in in device page - Validate ``Config.context`` and ``Template.default_values``: - ``Config.context`` and ``Template.default_values`` must always be a dictionary, - falsy values will be converted to empty dictionary automatically -- Fixed failures in ``update_config`` operation: - the ``update_config`` operation will be executed only when the transaction - is committed to the database; also handled rare but possible error conditions + ``Config.context`` and ``Template.default_values`` must always be a + dictionary, falsy values will be converted to empty dictionary + automatically +- Fixed failures in ``update_config`` operation: the ``update_config`` + operation will be executed only when the transaction is committed to the + database; also handled rare but possible error conditions - Handled device not existing case in ``update_config`` task - Fixed auto cert feature failure when device name is too long - UI: avoid showing main scrollbar in preview mode - Fixed ``OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST = False`` -- UI fixed advanced mode bugs: positioning is done using css instead of js. - Removed body scrollbar when in advanced mode. - Back to normal mode with ESC key. - Hidden netjsonconfig docs hint on narrow screens. -- Avoid simultaneous ``update_config`` tasks: - since now the launch of the task is executed when the - transaction is committed to the database, also the - check for other updates in progress must be moved there -- Fixed ``OPENWISP_CONTROLLER_CONTEXT`` setting getting modified at run time -- Fixed z-index of preview overlay: the z-index is increased so it's higher - than the main navigation menu to avoid the possibility of triggering the - main menu inadvertently +- UI fixed advanced mode bugs: positioning is done using css instead of + js. Removed body scrollbar when in advanced mode. Back to normal mode + with ESC key. Hidden netjsonconfig docs hint on narrow screens. +- Avoid simultaneous ``update_config`` tasks: since now the launch of the + task is executed when the transaction is committed to the database, also + the check for other updates in progress must be moved there +- Fixed ``OPENWISP_CONTROLLER_CONTEXT`` setting getting modified at run + time +- Fixed z-index of preview overlay: the z-index is increased so it's + higher than the main navigation menu to avoid the possibility of + triggering the main menu inadvertently - Prevent sending ``config_modified`` signal multiple times -- Fix timeout when changing template: slow operations are moved to the background -- Fixed variablle validation: now all the available context - (device variables, system variables) are taken into account when performing validation +- Fix timeout when changing template: slow operations are moved to the + background +- Fixed variablle validation: now all the available context (device + variables, system variables) are taken into account when performing + validation - Removed unnecessary ``static()`` call from media assets Version 0.7.0.post1 [2020-07-01] @@ -391,30 +424,39 @@ Version 0.7.0.post1 [2020-07-01] Version 0.7.0 [2020-07-01] -------------------------- -- [feature] Added signals: ``config_status_changed``, ``checksum_requested``, ``config_download_requested`` -- [feature] Added the possibility of specifying default values for variables used in templates +- [feature] Added signals: ``config_status_changed``, + ``checksum_requested``, ``config_download_requested`` +- [feature] Added the possibility of specifying default values for + variables used in templates - [feature] Added ``banner_timeout`` - [feature] Emit signal when ``DeviceConnection.is_working`` changes - [change] **Backward incompatible change**: the ``config_modified`` signal is not emitted anymore when the device is created - [change] VPN files now have 0600 permissions by default -- [change] Increased minimum `netjsonconfig `_ version to 0.8.0 -- [change] Increased minimum `paramiko `_ version to 2.7.1 -- [change] Increased minimum `celery `_ version to 4.4.3 +- [change] Increased minimum `netjsonconfig + `_ version to 0.8.0 +- [change] Increased minimum `paramiko + `_ version to 2.7.1 +- [change] Increased minimum `celery `_ + version to 4.4.3 - [fix] Avoid errors being hidden by tabs - [fix] Fixed clashes between javascript schema validation and variables - [fix] Fixed exception when adding device credential without type -- [fix] Fixed exception when auto adding device credentials to devices which don't have a configuration -- [fix] Avoid multiple devices having the same management IP address (multiple devices - having the same last IP is allowed because last IP is almost always a public address) +- [fix] Fixed exception when auto adding device credentials to devices + which don't have a configuration +- [fix] Avoid multiple devices having the same management IP address + (multiple devices having the same last IP is allowed because last IP is + almost always a public address) - [docs] Documented SSH timeouts - [docs] Update outdated steps in README instructions Version 0.6.0 [2020-04-02] -------------------------- -- Added controller view that allows to update the device information (firmware version used) -- Recover deleted object views in recoverable objects now show latest objects first +- Added controller view that allows to update the device information + (firmware version used) +- Recover deleted object views in recoverable objects now show latest + objects first - Added ``NETJSONCONFIG_HARDWARE_ID_AS_NAME`` setting Version 0.5.2 [2020-03-18] @@ -422,21 +464,23 @@ Version 0.5.2 [2020-03-18] - [controller] Added ``NETJSONCONFIG_REGISTRATION_SELF_CREATION`` - [models] Handled accidental duplication of files across templates -- [controller] Update hardware device info during registration - (if the device already exists, the registration will update its info) +- [controller] Update hardware device info during registration (if the + device already exists, the registration will update its info) - [admin] Moved ``hardware_id`` field in device list admin - [bugfix] Fixed broken preview when using ``hardware_id`` context var -- [models] Flagged ``hardware_id`` as not unique (it's ``unique_together`` with ``organization``) +- [models] Flagged ``hardware_id`` as not unique (it's ``unique_together`` + with ``organization``) - [admin] Hidden device configuration context field into advanced options - [models] Removed LEDE from the OpenWRT backend label -- [docker] Added ``REDIS_URL`` to docker-compose.yml and settings.py (for dev and test env) +- [docker] Added ``REDIS_URL`` to docker-compose.yml and settings.py (for + dev and test env) Version 0.5.1 [2020-02-28] -------------------------- -- [models] Improved consistent key generation, now a consisten key is generated - also when creating devices from the admin interface (or via model API), - before it was only done during registration +- [models] Improved consistent key generation, now a consisten key is + generated also when creating devices from the admin interface (or via + model API), before it was only done during registration - [admin] Fixed unsaved changes JS bug that was triggered in certain cases - [deps] Switched back to jsonfield @@ -446,8 +490,8 @@ Version 0.5.0 [2020-02-05] - [deps] Upgraded to django 3, upgraded dependencies - [deps] Dropped support for python 2 - [x509] Fixed serial number max length (imported from django-x509) -- [admin] Fixed bug that caused organization field to be missing - when importing a CA or certificate +- [admin] Fixed bug that caused organization field to be missing when + importing a CA or certificate Version 0.4.0 [2020-01-09] -------------------------- @@ -455,11 +499,13 @@ Version 0.4.0 [2020-01-09] - [feature] Added connection module (possibility to SSH into devices) - [feature] Added default operator group - [feature] Added management IP feature -- [change] Changed configuration status: ``running`` has been renamed to ``applied`` +- [change] Changed configuration status: ``running`` has been renamed to + ``applied`` - [admin] Added ``NETJSONCONFIG_MANAGEMENT_IP_DEVICE_LIST`` setting - [admin] Added ``NETJSONCONFIG_BACKEND_DEVICE_LIST`` setting - [x509] Fixed common_name redundancy -- [admin] Hidden "Download Configuration" button when no config is available +- [admin] Hidden "Download Configuration" button when no config is + available - [controller] Register view now updates device details - [deps] Added support for Django 2.1 and Django 2.2 - [models] Added support for hardware ID / serial number @@ -472,7 +518,8 @@ Version 0.4.0 [2020-01-09] - [change] Moved urls to admin namespace - [feature] Implement copy/clone templates - [feature] Added API to get context of device -- [bugfix] Ensure atomicity of transactions with database during auto-registration +- [bugfix] Ensure atomicity of transactions with database during + auto-registration Version 0.3.2 [2018-02-19] -------------------------- @@ -506,29 +553,36 @@ Version 0.2.4 [2017-11-07] Version 0.2.3 [2017-08-29] -------------------------- -- `934be13 `_: +- `934be13 + `_: [models] Updated sortedm2m __str__ definition -- `b76e4e2 `_: +- `b76e4e2 + `_: [requirements] django-netjsonconfig>=0.6.3,<0.7.0 Version 0.2.2 [2017-07-10] -------------------------- -- `f3dc784 `_: +- `f3dc784 + `_: [admin] Moved ``submit_line.html`` to `openwisp-utils `_ Version 0.2.1 [2017-07-05] -------------------------- -- `0064b98 `_: +- `0064b98 + `_: [device] Added ``system`` field -- `c7fe513 `_: +- `c7fe513 + `_: [docs] Added "Installing for development" section to README -- `c75fa68 `_: +- `c75fa68 + `_: [openwisp-utils] Moved shared logic to `openwisp-utils `_ -- `819cb21 `_: +- `819cb21 + `_: [requirements] django-netjsonconfig>=0.6.2,<0.7.0 Version 0.2.0 [2017-05-24] @@ -540,13 +594,17 @@ Version 0.2.0 [2017-05-24] [feature] Added ``Device`` model - `#9 `_: [admin] Load default templates JS logic only when required -- `298b2a2 `_: +- `298b2a2 + `_: [admin] Avoid setting ``extra_content`` to mutable object -- `d173c24 `_: +- `d173c24 + `_: [migrations] Squashed ``0001`` and ``0002`` to avoid postgres error -- `f5fb628 `_: +- `f5fb628 + `_: [migrations] Updated indexes -- `6200b7a `_: +- `6200b7a + `_: [Template] Fixed ``auto_client`` bug Version 0.1.4 [2017-04-21] @@ -558,25 +616,32 @@ Version 0.1.4 [2017-04-21] Version 0.1.3 [2017-03-11] -------------------------- -- `db77ae7 `_: +- `db77ae7 + `_: [controller] Added "error: " prefix in error responses Version 0.1.2 [2017-03-15] -------------------------- -- `3c61053 `_: +- `3c61053 + `_: [admin] Ensure preview button is present -- `0087483 `_: +- `0087483 + `_: [models] Converted ``OrganizationConfigSettings`` to UUID primary key Version 0.1.1 [2017-03-10] -------------------------- -- `cbca4e1 `_: - [users] Fixed integration with `openwisp-users `_ +- `cbca4e1 + `_: + [users] Fixed integration with `openwisp-users + `_ Version 0.1.0 [2017-03-08] -------------------------- -- added multi-tenancy (separation of organizations) to `openwisp2 `_ -- added email confirmation of new users (via `django-allauth `_) +- added multi-tenancy (separation of organizations) to `openwisp2 + `_ +- added email confirmation of new users (via `django-allauth + `_) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 820496092..e1b58e460 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1 +1,2 @@ -Please refer to the `OpenWISP Contribution Guidelines `_. +Please refer to the `OpenWISP Contribution Guidelines +`_. diff --git a/README.rst b/README.rst index 3c15dfa4a..3fd73b9a3 100644 --- a/README.rst +++ b/README.rst @@ -2,141 +2,158 @@ openwisp-controller =================== .. image:: https://github.com/openwisp/openwisp-controller/workflows/OpenWISP%20Controller%20CI%20Build/badge.svg?branch=master - :target: https://github.com/openwisp/openwisp-controller/actions?query=workflow%3A%22OpenWISP+Controller+CI+Build%22 - :alt: CI build status + :target: https://github.com/openwisp/openwisp-controller/actions?query=workflow%3A%22OpenWISP+Controller+CI+Build%22 + :alt: CI build status .. image:: https://coveralls.io/repos/openwisp/openwisp-controller/badge.svg - :target: https://coveralls.io/r/openwisp/openwisp-controller - :alt: Test Coverage + :target: https://coveralls.io/r/openwisp/openwisp-controller + :alt: Test Coverage .. image:: https://img.shields.io/librariesio/release/github/openwisp/openwisp-controller - :target: https://libraries.io/github/openwisp/openwisp-controller#repository_dependencies - :alt: Dependency monitoring + :target: https://libraries.io/github/openwisp/openwisp-controller#repository_dependencies + :alt: Dependency monitoring .. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg - :target: https://gitter.im/openwisp/general - :alt: Chat + :target: https://gitter.im/openwisp/general + :alt: Chat .. image:: https://badge.fury.io/py/openwisp-controller.svg - :target: http://badge.fury.io/py/openwisp-controller - :alt: Pypi Version + :target: http://badge.fury.io/py/openwisp-controller + :alt: Pypi Version .. image:: https://pepy.tech/badge/openwisp-controller - :target: https://pepy.tech/project/openwisp-controller - :alt: Downloads + :target: https://pepy.tech/project/openwisp-controller + :alt: Downloads .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://pypi.org/project/black/ - :alt: code style: black + :target: https://pypi.org/project/black/ + :alt: code style: black .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/controller_demo.gif - :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/controller_demo.gif - :alt: Feature Highlights + :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/controller_demo.gif + :alt: Feature Highlights ------------- +---- -**Need a quick overview?** `Try the OpenWISP Demo `_. +**Need a quick overview?** `Try the OpenWISP Demo +`_. -OpenWISP Controller is a configuration manager that allows to automate several -networking tasks like adoption, provisioning, management VPN configuration, -X509 certificates automatic generation, revocation of x509 certificates and -a lot more features. +OpenWISP Controller is a configuration manager that allows to automate +several networking tasks like adoption, provisioning, management VPN +configuration, X509 certificates automatic generation, revocation of x509 +certificates and a lot more features. -OpenWISP is not only an application designed for end users, but can also be -used as a framework on which custom network automation solutions can be built -on top of its building blocks. +OpenWISP is not only an application designed for end users, but can also +be used as a framework on which custom network automation solutions can be +built on top of its building blocks. Other popular building blocks that are part of the OpenWISP ecosystem are: -- `openwisp-monitoring `_: - provides device status monitoring, collection of metrics, charts, alerts, - possibility to define custom checks -- `openwisp-firmware-upgrader `_: - automated firmware upgrades (single devices or mass network upgrades) -- `openwisp-radius `_: - based on FreeRADIUS, allows to implement network access authentication systems like - 802.1x WPA2 Enterprise, captive portal authentication, Hotspot 2.0 (802.11u) -- `openwisp-network-topology `_: - provides way to collect and visualize network topology data from - dynamic mesh routing daemons or other network software (eg: OpenVPN); - it can be used in conjunction with openwisp-monitoring to get a better idea - of the state of the network -- `openwisp-ipam `_: - allows to manage the assignment of IP addresses used in the network -- `openwisp-notifications `_: - allows users to be aware of important events happening in the network. +- `openwisp-monitoring + `_: provides device + status monitoring, collection of metrics, charts, alerts, possibility to + define custom checks +- `openwisp-firmware-upgrader + `_: automated + firmware upgrades (single devices or mass network upgrades) +- `openwisp-radius `_: based + on FreeRADIUS, allows to implement network access authentication systems + like 802.1x WPA2 Enterprise, captive portal authentication, Hotspot 2.0 + (802.11u) +- `openwisp-network-topology + `_: provides way + to collect and visualize network topology data from dynamic mesh routing + daemons or other network software (eg: OpenVPN); it can be used in + conjunction with openwisp-monitoring to get a better idea of the state + of the network +- `openwisp-ipam `_: allows to + manage the assignment of IP addresses used in the network +- `openwisp-notifications + `_: allows users to + be aware of important events happening in the network. **For a more complete overview of the OpenWISP modules and architecture**, -see the -`OpenWISP Architecture Overview +see the `OpenWISP Architecture Overview `_. .. image:: https://raw.githubusercontent.com/openwisp/openwisp2-docs/master/assets/design/openwisp-logo-black.svg - :target: http://openwisp.org - :alt: OpenWISP + :target: http://openwisp.org + :alt: OpenWISP **Want to help OpenWISP?** `Find out how to help us grow here `_. ------------- +---- .. contents:: **Table of Contents**: - :backlinks: none - :depth: 3 + :backlinks: none + :depth: 3 ------------- +---- Project Structure & main features ----------------------------------- +--------------------------------- OpenWISP Controller is a python package consisting of four django apps: Config App ~~~~~~~~~~ -* **configuration management** for embedded devices supporting different firmwares: - - `OpenWRT `_ - - `OpenWISP Firmware `_ - - support for additional firmware can be added by `specifying custom backends <#netjsonconfig-backends>`_ -* **configuration editor** based on `JSON-Schema editor `_ -* **advanced edit mode**: edit `NetJSON `_ *DeviceConfiguration* objects for maximum flexibility -* `configuration templates `_: - reduce repetition to the minimum, configure default and required templates -* `configuration variables <#how-to-use-configuration-variables>`_: +- **configuration management** for embedded devices supporting different firmwares: + - `OpenWRT `_ + - `OpenWISP Firmware + `_ + - support for additional firmware can be added by `specifying custom + backends <#netjsonconfig-backends>`_ +- **configuration editor** based on `JSON-Schema editor + `_ +- **advanced edit mode**: edit `NetJSON `_ + *DeviceConfiguration* objects for maximum flexibility +- `configuration templates + `_: reduce repetition to + the minimum, configure default and required templates +- `configuration variables <#how-to-use-configuration-variables>`_: reference ansible-like variables in the configuration and templates -* **template tags**: tag templates to automate different types of auto-configurations (eg: mesh, WDS, 4G) -* **device groups**: add `devices to dedicated groups <#device-groups>`_ to - ease management of group of devices -* **simple HTTP resources**: allow devices to automatically download configuration updates -* **VPN management**: `automatically provision VPN tunnels <#openwisp-controller-default-auto-cert>`_, - including cryptographic keys, IP addresses -* `REST API <#rest-api-reference>`_ -* `Export/Import devices <#exportimport-device-data>`_ +- **template tags**: tag templates to automate different types of + auto-configurations (eg: mesh, WDS, 4G) +- **device groups**: add `devices to dedicated groups <#device-groups>`_ + to ease management of group of devices +- **simple HTTP resources**: allow devices to automatically download + configuration updates +- **VPN management**: `automatically provision VPN tunnels + <#openwisp-controller-default-auto-cert>`_, including cryptographic + keys, IP addresses +- `REST API <#rest-api-reference>`_ +- `Export/Import devices <#exportimport-device-data>`_ PKI App ~~~~~~~ -The PKI app is based on `django-x509 `_, -it allows to create, import and view x509 CAs and certificates directly from -the administration dashboard, it also adds different endpoints to the -`REST API <#rest-api-reference>`_. +The PKI app is based on `django-x509 +`_, it allows to create, import +and view x509 CAs and certificates directly from the administration +dashboard, it also adds different endpoints to the `REST API +<#rest-api-reference>`_. Connection App ~~~~~~~~~~~~~~ -This app allows OpenWISP Controller to use different protocols to reach network devices. -Currently, the default connnection protocols are SSH and SNMP, but the protocol -mechanism is extensible and more protocols can be implemented if needed. +This app allows OpenWISP Controller to use different protocols to reach +network devices. Currently, the default connnection protocols are SSH and +SNMP, but the protocol mechanism is extensible and more protocols can be +implemented if needed. SSH -### ++++ -The SSH connector allows the controller to initialize connections to the devices -in order perform `push operations <#how-to-configure-push-updates>`__: +The SSH connector allows the controller to initialize connections to the +devices in order perform `push operations +<#how-to-configure-push-updates>`__: - Sending configuration updates. - `Executing shell commands <#sending-commands-to-devices>`_. -- Perform `firmware upgrades via the additional firmware upgrade module `_. +- Perform `firmware upgrades via the additional firmware upgrade module + `_. - `REST API <#rest-api-reference>`_ The default connection protocol implemented is SSH, but other protocol @@ -148,34 +165,38 @@ Access via SSH key is recommended, the SSH key algorithms supported are: - Ed25519 SNMP -#### +++++ -The SNMP connector is useful to collect monitoring information and it's used in -`openwisp-monitoring`_ for performing checks to collect monitoring information. -`Read more `_ on how to use it. +The SNMP connector is useful to collect monitoring information and it's +used in openwisp-monitoring_ for performing checks to collect monitoring +information. `Read more +`_ +on how to use it. Geo App ~~~~~~~ -The geographic app is based on `django-loci `_ -and allows to define the geographic coordinates of the devices, -as well as their indoor coordinates on floorplan images. +The geographic app is based on `django-loci +`_ and allows to define the +geographic coordinates of the devices, as well as their indoor coordinates +on floorplan images. It also adds different endpoints to the `REST API <#rest-api-reference>`_. Subnet Division App ~~~~~~~~~~~~~~~~~~~ -This app allows to automatically provision subnets and IP addresses which will be -available as `system defined configuration variables <#system-defined-variables>`_ -that can be used in templates. The purpose of this app is to allow users to automatically -provision and configure specific -subnets and IP addresses to the devices without the need of manual intervention. +This app allows to automatically provision subnets and IP addresses which +will be available as `system defined configuration variables +<#system-defined-variables>`_ that can be used in templates. The purpose +of this app is to allow users to automatically provision and configure +specific subnets and IP addresses to the devices without the need of +manual intervention. Refer to `"How to configure automatic provisioning of subnets and IPs" section of this documentation -<#how-to-configure-automatic-provisioning-of-subnets-and-ips>`_ -to learn about features provided by this app. +<#how-to-configure-automatic-provisioning-of-subnets-and-ips>`_ to learn +about features provided by this app. This app is optional, if you don't need it you can avoid adding it to ``settings.INSTALLED_APPS``. @@ -194,8 +215,8 @@ See: Dependencies ~~~~~~~~~~~~ -* Python >= 3.7 -* OpenSSL +- Python >= 3.7 +- OpenSSL Install stable version from pypi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -221,8 +242,8 @@ Alternatively you can install via pip using git: pip install -e git+git://github.com/openwisp/openwisp-controller#egg=openwisp_controller -If you want to contribute, follow the instructions in -`Installing for development <#installing-for-development>`_. +If you want to contribute, follow the instructions in `Installing for +development <#installing-for-development>`_. Installing for development ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -254,14 +275,16 @@ Launch Redis and PostgreSQL: docker-compose up -d redis postgres -Setup and activate a virtual-environment. (we'll be using `virtualenv `_) +Setup and activate a virtual-environment. (we'll be using `virtualenv +`_) .. code-block:: shell python -m virtualenv env source env/bin/activate -Make sure that you are using pip version 20.2.4 before moving to the next step: +Make sure that you are using pip version 20.2.4 before moving to the next +step: .. code-block:: shell @@ -275,8 +298,9 @@ Install development dependencies: pip install -r requirements-test.txt npm install -g jshint stylelint -Install WebDriver for Chromium for your browser version from ``_ -and Extract ``chromedriver`` to one of directories from your ``$PATH`` (example: ``~/.local/bin/``). +Install WebDriver for Chromium for your browser version from +https://chromedriver.chromium.org/home and Extract ``chromedriver`` to one +of directories from your ``$PATH`` (example: ``~/.local/bin/``). Create database: @@ -317,8 +341,8 @@ Run quality assurance tests with: Install and run on docker ~~~~~~~~~~~~~~~~~~~~~~~~~ -NOTE: This Docker image is for development purposes only. -For the official OpenWISP Docker images, see: `docker-openwisp +NOTE: This Docker image is for development purposes only. For the official +OpenWISP Docker images, see: `docker-openwisp `_. Build from the Dockerfile: @@ -339,21 +363,23 @@ Troubleshooting steps for common installation issues You may encounter some issues while installing GeoDjango. Unable to load SpatiaLite library extension? -############################################ +++++++++++++++++++++++++++++++++++++++++++++ + +If you are getting below exception: -If you are getting below exception:: +:: - django.core.exceptions.ImproperlyConfigured: Unable to load the SpatiaLite library extension + django.core.exceptions.ImproperlyConfigured: Unable to load the SpatiaLite library extension -then, You need to specify ``SPATIALITE_LIBRARY_PATH`` in your ``settings.py`` as explained in -`django documentation regarding how to install and configure spatialte +then, You need to specify ``SPATIALITE_LIBRARY_PATH`` in your +``settings.py`` as explained in `django documentation regarding how to +install and configure spatialte `_. Having Issues with other geospatial libraries? -############################################## +++++++++++++++++++++++++++++++++++++++++++++++ -Please refer -`troubleshooting issues related to geospatial libraries +Please refer `troubleshooting issues related to geospatial libraries `_. Setup (integrate in an existing django project) @@ -386,48 +412,50 @@ Add ``openwisp_controller`` applications to ``INSTALLED_APPS``: ] EXTENDED_APPS = ('django_x509', 'django_loci') -**Note**: The order of applications in ``INSTALLED_APPS`` should be maintained, -otherwise it might not work properly. +**Note**: The order of applications in ``INSTALLED_APPS`` should be +maintained, otherwise it might not work properly. Other settings needed in ``settings.py``: .. code-block:: python STATICFILES_FINDERS = [ - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'openwisp_utils.staticfiles.DependencyFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "openwisp_utils.staticfiles.DependencyFinder", ] - ASGI_APPLICATION = 'openwisp_controller.geo.channels.routing.channel_routing' + ASGI_APPLICATION = ( + "openwisp_controller.geo.channels.routing.channel_routing" + ) CHANNEL_LAYERS = { # in production you should use another channel layer backend - 'default': {'BACKEND': 'channels.layers.InMemoryChannelLayer'}, + "default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}, } TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'OPTIONS': { - 'loaders': [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'openwisp_utils.loaders.DependencyLoader', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "OPTIONS": { + "loaders": [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "openwisp_utils.loaders.DependencyLoader", ], - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'openwisp_utils.admin_theme.context_processor.menu_items', - 'openwisp_notifications.context_processors.notification_api_settings', + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "openwisp_utils.admin_theme.context_processor.menu_items", + "openwisp_notifications.context_processors.notification_api_settings", ], }, } ] - FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' + FORM_RENDERER = "django.forms.renderers.TemplatesSetting" Add the URLs to your main ``urls.py``: @@ -436,8 +464,8 @@ Add the URLs to your main ``urls.py``: urlpatterns = [ # ... other urls in your project ... # openwisp-controller urls - url(r'^admin/', admin.site.urls), - url(r'', include('openwisp_controller.urls')), + url(r"^admin/", admin.site.urls), + url(r"", include("openwisp_controller.urls")), ] Configure caching (you may use a different cache storage if you want): @@ -445,17 +473,17 @@ Configure caching (you may use a different cache storage if you want): .. code-block:: python CACHES = { - 'default': { - 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': 'redis://localhost/0', - 'OPTIONS': { - 'CLIENT_CLASS': 'django_redis.client.DefaultClient', - } + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://localhost/0", + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, } } - SESSION_ENGINE = 'django.contrib.sessions.backends.cache' - SESSION_CACHE_ALIAS = 'default' + SESSION_ENGINE = "django.contrib.sessions.backends.cache" + SESSION_CACHE_ALIAS = "default" Configure celery (you may use a different broker if you want): @@ -463,13 +491,15 @@ Configure celery (you may use a different broker if you want): # here we show how to configure celery with redis but you can # use other brokers if you want, consult the celery docs - CELERY_BROKER_URL = 'redis://localhost/1' + CELERY_BROKER_URL = "redis://localhost/1" - INSTALLED_APPS.append('djcelery_email') - EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' + INSTALLED_APPS.append("djcelery_email") + EMAIL_BACKEND = "djcelery_email.backends.CeleryEmailBackend" -If you decide to use redis (as shown in these examples), -install the required python packages:: +If you decide to use redis (as shown in these examples), install the +required python packages: + +:: pip install redis django-redis @@ -485,10 +515,12 @@ Usage reference Default Templates ~~~~~~~~~~~~~~~~~ -When templates are flagged as default, they will be automatically assigned to new devices. +When templates are flagged as default, they will be automatically assigned +to new devices. -If there are multiple default templates, these are assigned to the device in alphabetical -order based on their names, for example, given the following default templates: +If there are multiple default templates, these are assigned to the device +in alphabetical order based on their names, for example, given the +following default templates: - Access - Interfaces @@ -496,9 +528,10 @@ order based on their names, for example, given the following default templates: They will be assigned to devices in exactly that order. -If for some technical reason (eg: one default template depends on the presence of another -default template which must be assigned earlier) you need to change the ordering, you can -simply rename the templates by prefixing them with numbers, eg: +If for some technical reason (eg: one default template depends on the +presence of another default template which must be assigned earlier) you +need to change the ordering, you can simply rename the templates by +prefixing them with numbers, eg: - 1 Interfaces - 2. SSH Keys @@ -508,28 +541,29 @@ Required Templates ~~~~~~~~~~~~~~~~~~ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/required-templates.png - :alt: Required template example + :alt: Required template example -Required templates are similar to `Default templates <#default-templates>`__ -but cannot be unassigned from a device configuration, they can only be overridden. +Required templates are similar to `Default templates +<#default-templates>`__ but cannot be unassigned from a device +configuration, they can only be overridden. -They will be always assigned earlier than default templates, -so they can be overridden if needed. +They will be always assigned earlier than default templates, so they can +be overridden if needed. -In the example above, the "SSID" template is flagged as "(required)" -and its checkbox is always checked and disabled. +In the example above, the "SSID" template is flagged as "(required)" and +its checkbox is always checked and disabled. How to use configuration variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Sometimes the configuration is not exactly equal on all the devices, -some parameters are unique to each device or need to be changed -by the user. +Sometimes the configuration is not exactly equal on all the devices, some +parameters are unique to each device or need to be changed by the user. -In these cases it is possible to use configuration variables in conjunction -with templates, this feature is also known as *configuration context*, think of -it like a dictionary which is passed to the function which renders the -configuration, so that it can fill variables according to the passed context. +In these cases it is possible to use configuration variables in +conjunction with templates, this feature is also known as *configuration +context*, think of it like a dictionary which is passed to the function +which renders the configuration, so that it can fill variables according +to the passed context. The different ways in which variables are defined are described below in the order (high to low) of their precedence: @@ -549,17 +583,18 @@ In the device configuration section you can find a section named variables and their values, as shown in the example below: .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/device-context.png - :alt: context + :alt: context Predefined device variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Each device gets the following attributes passed as configuration variables: +Each device gets the following attributes passed as configuration +variables: -* ``id`` -* ``key`` -* ``name`` -* ``mac_address`` +- ``id`` +- ``key`` +- ``name`` +- ``mac_address`` Group variables ~~~~~~~~~~~~~~~ @@ -575,11 +610,11 @@ Organization variables Variables can also be defined at the organization level. You can set the *organization variables* from the organization change page -``/admin/openwisp_users/organization//change/``, under the -**Configuration Management Settings**. +``/admin/openwisp_users/organization//change/``, under +the **Configuration Management Settings**. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/organization-variables.png - :alt: organization variables + :alt: organization variables Global variables ~~~~~~~~~~~~~~~~ @@ -590,46 +625,48 @@ Variables can also be defined globally using the Template default values ~~~~~~~~~~~~~~~~~~~~~~~ -It's possible to specify the default values of variables defined in a template. +It's possible to specify the default values of variables defined in a +template. This allows to achieve 2 goals: -1. pass schema validation without errors (otherwise it would not be possible - to save the template in the first place) +1. pass schema validation without errors (otherwise it would not be + possible to save the template in the first place) 2. provide good default values that are valid in most cases but can be overridden in the device if needed -These default values will be overridden by the -`User defined device variables <#user-defined-device-variables>`_. +These default values will be overridden by the `User defined device +variables <#user-defined-device-variables>`_. The default values of variables can be manipulated from the section "configuration variables" in the edit template page: .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/template-default-values.png - :alt: default values + :alt: default values System defined variables ~~~~~~~~~~~~~~~~~~~~~~~~ -Predefined device variables, global variables and other variables that -are automatically managed by the system (eg: when using templates of -type VPN-client) are displayed in the admin UI as *System Defined Variables* -in read-only mode. +Predefined device variables, global variables and other variables that are +automatically managed by the system (eg: when using templates of type +VPN-client) are displayed in the admin UI as *System Defined Variables* in +read-only mode. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/system-defined-variables.png - :alt: system defined variables + :alt: system defined variables -**Note:** `Group configuration variables <#group-configuration-variables>`__ -are also added to the **System Defined Variables** of the device. +**Note:** `Group configuration variables +<#group-configuration-variables>`__ are also added to the **System Defined +Variables** of the device. Example usage of variables ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Here's a typical use case, the WiFi SSID and WiFi password. -You don't want to define this for every device, but you may want to -allow operators to easily change the SSID or WiFi password for a -specific device without having to re-define the whole wifi interface -to avoid duplicating information. +Here's a typical use case, the WiFi SSID and WiFi password. You don't want +to define this for every device, but you may want to allow operators to +easily change the SSID or WiFi password for a specific device without +having to re-define the whole wifi interface to avoid duplicating +information. This would be the template: @@ -663,8 +700,8 @@ These would be the default values in the template: "wlan0_password": "Snakeoil_pwd!321654" } -The default values can then be overridden at -`device level <#user-defined-device-variables>`_ if needed, eg: +The default values can then be overridden at `device level +<#user-defined-device-variables>`_ if needed, eg: .. code-block:: json @@ -676,95 +713,107 @@ The default values can then be overridden at How to configure push updates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Follow the procedure described below to enable secure SSH access from OpenWISP to your -devices, this is required to enable push updates (whenever the configuration is changed, -OpenWISP will trigger the update in the background) and/or -`firmware upgrades (via the additional module openwisp-firmware-upgrader) +Follow the procedure described below to enable secure SSH access from +OpenWISP to your devices, this is required to enable push updates +(whenever the configuration is changed, OpenWISP will trigger the update +in the background) and/or `firmware upgrades (via the additional module +openwisp-firmware-upgrader) `_. -**Note**: If you have installed OpenWISP with `openwisp2 Ansbile role `_ -then you can skip the following steps. The Ansible role automatically creates a -default template to update ``authorized_keys`` on networking devices using the -default access credentials. +**Note**: If you have installed OpenWISP with `openwisp2 Ansbile role +`_ then you can skip the +following steps. The Ansible role automatically creates a default template +to update ``authorized_keys`` on networking devices using the default +access credentials. 1. Generate SSH key -################### ++++++++++++++++++++ -First of all, we need to generate the SSH key which will be -used by OpenWISP to access the devices, to do so, you can use the following command: +First of all, we need to generate the SSH key which will be used by +OpenWISP to access the devices, to do so, you can use the following +command: .. code-block:: shell echo './sshkey' | ssh-keygen -t ed25519 -C "openwisp" -This will create two files in the current directory, one called ``sshkey`` (the private key) and one called -``sshkey.pub`` (the public key). +This will create two files in the current directory, one called ``sshkey`` +(the private key) and one called ``sshkey.pub`` (the public key). Store the content of these files in a secure location. -**Note:** Support for **ED25519** was added in OpenWrt 21.02 (requires Dropbear > 2020.79). -If you are managing devices with OpenWrt < 21, then you will need to use RSA keys: +**Note:** Support for **ED25519** was added in OpenWrt 21.02 (requires +Dropbear > 2020.79). If you are managing devices with OpenWrt < 21, then +you will need to use RSA keys: .. code-block:: shell echo './sshkey' | ssh-keygen -t rsa -b 4096 -C "openwisp" 2. Save SSH private key in OpenWISP (access credentials) -######################################################## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/add-ssh-credentials-private-key.png - :alt: add SSH private key as access credential in OpenWISP + :alt: add SSH private key as access credential in OpenWISP From the first page of OpenWISP click on "Access credentials", then click on the **"ADD ACCESS CREDENTIALS"** button in the upper right corner -(alternatively, go to the following URL: ``/admin/connection/credentials/add/``). +(alternatively, go to the following URL: +``/admin/connection/credentials/add/``). -Select SSH as ``type``, enable the **Auto add** checkbox, then at the field -"Credentials type" select "SSH (private key)", now type "root" in the ``username`` field, -while in the ``key`` field you have to paste the contents of the private key just created. +Select SSH as ``type``, enable the **Auto add** checkbox, then at the +field "Credentials type" select "SSH (private key)", now type "root" in +the ``username`` field, while in the ``key`` field you have to paste the +contents of the private key just created. Now hit save. -The credentials just created will be automatically enabled for all the devices in the system -(both existing devices and devices which will be added in the future). +The credentials just created will be automatically enabled for all the +devices in the system (both existing devices and devices which will be +added in the future). 3. Add the public key to your devices -##################################### ++++++++++++++++++++++++++++++++++++++ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/add-authorized-ssh-keys-template.png - :alt: Add authorized SSH public keys template to OpenWISP (OpenWRT) + :alt: Add authorized SSH public keys template to OpenWISP (OpenWRT) Now we need to instruct your devices to allow OpenWISP accessing via SSH, -in order to do this we need to add the contents of the public key file created in step 1 -(``sshkey.pub``) in the file ``/etc/dropbear/authorized_keys`` on the devices, the -recommended way to do this is to create a configuration template in OpenWISP: -from the first page of OpenWISP, click on "Templates", then and click on the -**"ADD TEMPLATE"** button in the upper right corner (alternatively, go to the following URL: -``/admin/config/template/add/``). +in order to do this we need to add the contents of the public key file +created in step 1 (``sshkey.pub``) in the file +``/etc/dropbear/authorized_keys`` on the devices, the recommended way to +do this is to create a configuration template in OpenWISP: from the first +page of OpenWISP, click on "Templates", then and click on the **"ADD +TEMPLATE"** button in the upper right corner (alternatively, go to the +following URL: ``/admin/config/template/add/``). Check **enabled by default**, then scroll down the configuration section, -click on "Configuration Menu", scroll down, click on "Files" then close the menu -by clicking again on "Configuration Menu". Now type ``/etc/dropbear/authorized_keys`` -in the ``path`` field of the file, then paste the contents of ``sshkey.pub`` in ``contents``. +click on "Configuration Menu", scroll down, click on "Files" then close +the menu by clicking again on "Configuration Menu". Now type +``/etc/dropbear/authorized_keys`` in the ``path`` field of the file, then +paste the contents of ``sshkey.pub`` in ``contents``. Now hit save. -**There's a catch**: you will need to assign the template to any existing device. +**There's a catch**: you will need to assign the template to any existing +device. 4. Test it -########## +++++++++++ Once you have performed the 3 steps above, you can test it as follows: -1. Ensure there's at least one device turned on and connected to OpenWISP, ensure - this device has the "SSH Authorized Keys" assigned to it. -2. Ensure the celery worker of OpenWISP Controller is running (eg: ``ps aux | grep celery``) -3. SSH into the device and wait (maximum 2 minutes) until ``/etc/dropbear/authorized_keys`` - appears as specified in the template. -4. While connected via SSH to the device run the following command in the console: - ``logread -f``, now try changing the device name in OpenWISP -5. Shortly after you change the name in OpenWISP, you should see some output in the - SSH console indicating another SSH access and the configuration update being performed. +1. Ensure there's at least one device turned on and connected to OpenWISP, + ensure this device has the "SSH Authorized Keys" assigned to it. +2. Ensure the celery worker of OpenWISP Controller is running (eg: ``ps + aux | grep celery``) +3. SSH into the device and wait (maximum 2 minutes) until + ``/etc/dropbear/authorized_keys`` appears as specified in the template. +4. While connected via SSH to the device run the following command in the + console: ``logread -f``, now try changing the device name in OpenWISP +5. Shortly after you change the name in OpenWISP, you should see some + output in the SSH console indicating another SSH access and the + configuration update being performed. Sending Commands to Devices ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -775,35 +824,39 @@ By default, there are three options in the **Send Command** dropdown: 2. Change Password 3. Custom Command -While the first two options are self-explanatory, the **custom command** option -allows you to execute any command on the device as shown in the example below. +While the first two options are self-explanatory, the **custom command** +option allows you to execute any command on the device as shown in the +example below. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/commands_demo.gif - :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/commands_demo.gif - :alt: Executing commands on device example + :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/commands_demo.gif + :alt: Executing commands on device example -**Note**: in order for this feature to work, a device needs to have at least -one **Access Credential** (see `How to configure push updates <#how-to-configure-push-updates>`__). +**Note**: in order for this feature to work, a device needs to have at +least one **Access Credential** (see `How to configure push updates +<#how-to-configure-push-updates>`__). -The **Send Command** button will be hidden until the device -has at least one **Access Credential**. +The **Send Command** button will be hidden until the device has at least +one **Access Credential**. -If you need to allow your users to quickly send specific commands that are used often in your -network regardless of your users' knowledge of Linux shell commands, you can add new commands -by following instructions in the `"How to define new options in the commands menu" +If you need to allow your users to quickly send specific commands that are +used often in your network regardless of your users' knowledge of Linux +shell commands, you can add new commands by following instructions in the +`"How to define new options in the commands menu" <#how-to-define-new-options-in-the-commands-menu>`_ section below. -If you are an advanced user and want to register commands programatically, then refer to -`"Register / Unregistering commands" <#registering--unregistering-commands>`_ section. +If you are an advanced user and want to register commands programatically, +then refer to `"Register / Unregistering commands" +<#registering--unregistering-commands>`_ section. How to define new options in the commands menu -############################################## +++++++++++++++++++++++++++++++++++++++++++++++ -Let's explore to define new custom commands -to help users perform additional management actions -without having to be Linux/Unix experts. +Let's explore to define new custom commands to help users perform +additional management actions without having to be Linux/Unix experts. -We can do so by using the ``OPENWISP_CONTROLLER_USER_COMMANDS`` django setting. +We can do so by using the ``OPENWISP_CONTROLLER_USER_COMMANDS`` django +setting. The following example defines a simple command that can ``ping`` an input ``destination_address`` through a network interface, ``interface_name``. @@ -812,36 +865,38 @@ The following example defines a simple command that can ``ping`` an input # In yourproject/settings.py + def ping_command_callable(destination_address, interface_name=None): - command = f'ping -c 4 {destination_address}' + command = f"ping -c 4 {destination_address}" if interface_name: - command += f' -I {interface_name}' + command += f" -I {interface_name}" return command + OPENWISP_CONTROLLER_USER_COMMANDS = [ ( - 'ping', + "ping", { - 'label': 'Ping', - 'schema': { - 'title': 'Ping', - 'type': 'object', - 'required': ['destination_address'], - 'properties': { - 'destination_address': { - 'type': 'string', - 'title': 'Destination Address', + "label": "Ping", + "schema": { + "title": "Ping", + "type": "object", + "required": ["destination_address"], + "properties": { + "destination_address": { + "type": "string", + "title": "Destination Address", }, - 'interface_name': { - 'type': 'string', - 'title': 'Interface Name', + "interface_name": { + "type": "string", + "title": "Interface Name", }, }, - 'message': 'Destination Address cannot be empty', - 'additionalProperties': False, + "message": "Destination Address cannot be empty", + "additionalProperties": False, }, - 'callable': ping_command_callable, - } + "callable": ping_command_callable, + }, ) ] @@ -849,30 +904,31 @@ The above code will add the "Ping" command in the user interface as show in the GIF below: .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/ping_command_example.gif - :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/ping_command_example.gif - :alt: Adding a "ping" command + :target: https://github.com/openwisp/openwisp-controller/tree/docs/docs/ping_command_example.gif + :alt: Adding a "ping" command -The ``OPENWISP_CONTROLLER_USER_COMMANDS`` setting takes a ``list`` of ``tuple`` -each containing two elements. The first element of the tuple should contain an -identifier for the command and the second element should contain a ``dict`` -defining configuration of the command. +The ``OPENWISP_CONTROLLER_USER_COMMANDS`` setting takes a ``list`` of +``tuple`` each containing two elements. The first element of the tuple +should contain an identifier for the command and the second element should +contain a ``dict`` defining configuration of the command. Command Configuration -^^^^^^^^^^^^^^^^^^^^^ +..................... -The ``dict`` defining configuration for command should contain following keys: +The ``dict`` defining configuration for command should contain following +keys: 1. ``label`` -"""""""""""" +'''''''''''' A ``str`` defining label for the command used internally by Django. 2. ``schema`` -""""""""""""" +''''''''''''' -A ``dict`` defining `JSONSchema `_ for inputs of command. -You can specify the inputs for your command, add rules for performing validation -and make inputs required or optional. +A ``dict`` defining `JSONSchema `_ for inputs of +command. You can specify the inputs for your command, add rules for +performing validation and make inputs required or optional. Here is a detailed explanation of the schema used in above example: @@ -905,59 +961,59 @@ Here is a detailed explanation of the schema used in above example: 'additionalProperties': False, } -This example uses only handful of properties available in JSONSchema. You can -experiment with other properties of JSONSchema for schema of your command. +This example uses only handful of properties available in JSONSchema. You +can experiment with other properties of JSONSchema for schema of your +command. 3. ``callable`` -""""""""""""""" +''''''''''''''' -A ``callable`` or ``str`` defining dotted path to a callable. It should return -the command (``str``) to be executed on the device. Inputs of the command are -passed as arguments to this callable. +A ``callable`` or ``str`` defining dotted path to a callable. It should +return the command (``str``) to be executed on the device. Inputs of the +command are passed as arguments to this callable. The example above includes a callable(``ping_command_callable``) for ``ping`` command. Registering / Unregistering Commands -#################################### +++++++++++++++++++++++++++++++++++++ OpenWISP Controller provides registering and unregistering commands -through utility functions ``openwisp_controller.connection.commands.register_command`` -and ``openwisp_notifications.types.unregister_notification_type``. -You can use these functions to register or unregister commands -from your code. +through utility functions +``openwisp_controller.connection.commands.register_command`` and +``openwisp_notifications.types.unregister_notification_type``. You can use +these functions to register or unregister commands from your code. **Note**: These functions are to be used as an alternative to the -`"OPENWISP_CONTROLLER_USER_COMMANDS" <#openwisp-controller-user-commands>`_ -when `developing custom modules based on openwisp-controller -<#extending-openwisp-controller>`_ or when developing custom third party -apps. +`"OPENWISP_CONTROLLER_USER_COMMANDS" +<#openwisp-controller-user-commands>`_ when `developing custom modules +based on openwisp-controller <#extending-openwisp-controller>`_ or when +developing custom third party apps. ``register_command`` -^^^^^^^^^^^^^^^^^^^^ +.................... -+--------------------+------------------------------------------------------------------+ -| Parameter | Description | -+--------------------+------------------------------------------------------------------+ -| ``command_name`` | A ``str`` defining identifier for the command. | -+--------------------+------------------------------------------------------------------+ -| ``command_config`` | A ``dict`` defining configuration of the command | -| | as shown in `"Command Configuration" <#command-configuration>`_. | -+--------------------+------------------------------------------------------------------+ +================== =================================================== +Parameter Description +``command_name`` A ``str`` defining identifier for the command. +``command_config`` A ``dict`` defining configuration of the command as + shown in `"Command Configuration" + <#command-configuration>`_. +================== =================================================== -**Note:** It will raise ``ImproperlyConfigured`` exception if a command is already -registered with the same name. +**Note:** It will raise ``ImproperlyConfigured`` exception if a command is +already registered with the same name. ``unregister_command`` -^^^^^^^^^^^^^^^^^^^^^^ +...................... -+--------------------+-----------------------------------------+ -| Parameter | Description | -+--------------------+-----------------------------------------+ -| ``command_name`` | A ``str`` defining name of the command. | -+--------------------+-----------------------------------------+ +================ ======================================= +Parameter Description +``command_name`` A ``str`` defining name of the command. +================ ======================================= -**Note:** It will raise ``ImproperlyConfigured`` exception if such command does not exists. +**Note:** It will raise ``ImproperlyConfigured`` exception if such command +does not exists. Device Groups ~~~~~~~~~~~~~ @@ -965,25 +1021,26 @@ Device Groups Device Groups provide features aimed at adding specific management rules for the devices of an organization: -- Group similar devices by having dedicated groups for access points, routers, etc. +- Group similar devices by having dedicated groups for access points, + routers, etc. - Define `group metadata <#group-metadata>`_. - Define `group configuration templates <#group-templates>`_. -- Define `group configuration variables <#group-configuration-variables>`__. +- Define `group configuration variables + <#group-configuration-variables>`__. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/1.1/device-groups.png - :alt: Device Group example + :alt: Device Group example Group Templates -############### ++++++++++++++++ -Groups allow to define templates which are automatically assigned to devices -belonging to the group. When using this feature, keep in mind the following -important points: +Groups allow to define templates which are automatically assigned to +devices belonging to the group. When using this feature, keep in mind the +following important points: -- Templates of any configuration backend can be selected, - when a device is assigned to a group, - only the templates which matches the device configuration backend are - applied to the device. +- Templates of any configuration backend can be selected, when a device is + assigned to a group, only the templates which matches the device + configuration backend are applied to the device. - The system will not force group templates onto devices, this means that users can remove the applied group templates from a specific device if needed. @@ -991,77 +1048,82 @@ important points: group templates of the old group and apply the new templates of the new group (this operation is implemented by leveraging the `group_templates_changed <#group_templates_changed>`_ signal). -- If the group templates are changed, the devices which belong to the group - will be automatically updated to reflect the changes - (this operation is executed in a background task). -- In case the configuration backend of a device is changed, - the system will handle this automatically too and update the group - templates accordingly (this operation is implemented by leveraging the +- If the group templates are changed, the devices which belong to the + group will be automatically updated to reflect the changes (this + operation is executed in a background task). +- In case the configuration backend of a device is changed, the system + will handle this automatically too and update the group templates + accordingly (this operation is implemented by leveraging the `config_backend_changed <#config_backend_changed>`_ signal). -- If a device does not have a configuration defined yet, but it is assigned - to a group which has templates defined, the system will automatically - create a configuration for it using the default backend specified in - `OPENWISP_CONTROLLER_DEFAULT_BACKEND <#OPENWISP_CONTROLLER_DEFAULT_BACKEND>`_ setting. +- If a device does not have a configuration defined yet, but it is + assigned to a group which has templates defined, the system will + automatically create a configuration for it using the default backend + specified in `OPENWISP_CONTROLLER_DEFAULT_BACKEND + <#OPENWISP_CONTROLLER_DEFAULT_BACKEND>`_ setting. **Note:** the list of templates shown in the edit group page do not contain templates flagged as "default" or "required" to avoid redundancy -because those templates are automatically assigned by the system -to new devices. +because those templates are automatically assigned by the system to new +devices. This feature works also when editing group templates or the group assigned to a device via the `REST API <#change-device-group-detail>`__. Group Configuration Variables -############################# ++++++++++++++++++++++++++++++ Groups allow to define configuration variables which are automatically -added to the device's context in the **System Defined Variables**. -Check the `"How to use configuration variables" section <#how-to-use-configuration-variables>`_ -to learn about precedence of different configuration variables. +added to the device's context in the **System Defined Variables**. Check +the `"How to use configuration variables" section +<#how-to-use-configuration-variables>`_ to learn about precedence of +different configuration variables. This feature works also when editing group templates or the group assigned to a device via the `REST API <#change-device-group-detail>`__. Group Metadata -############## +++++++++++++++ Groups allow to store additional information regarding a group in the structured metadata field (which can be accessed via the REST API). The metadata field allows custom structure and validation to standardize information across all groups using the -`"OPENWISP_CONTROLLER_DEVICE_GROUP_SCHEMA" <#openwisp-controller-device-group-schema>`_ -setting. +`"OPENWISP_CONTROLLER_DEVICE_GROUP_SCHEMA" +<#openwisp-controller-device-group-schema>`_ setting. -**Note:** *Group configuration variables* and *Group metadata* serves different purposes. -The group configuration variables should be used when the device configuration is required -to be changed for particular group of devices. Group metadata should be used to store -additional data for the devices. Group metadata is not used for configuration generation. +**Note:** *Group configuration variables* and *Group metadata* serves +different purposes. The group configuration variables should be used when +the device configuration is required to be changed for particular group of +devices. Group metadata should be used to store additional data for the +devices. Group metadata is not used for configuration generation. Export/Import Device data ~~~~~~~~~~~~~~~~~~~~~~~~~ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/1.1/import-export/device-list.png - :alt: Import / Export + :alt: Import / Export -The device list page offers two buttons to export and import device data in -different formats. +The device list page offers two buttons to export and import device data +in different formats. The export feature respects any filters selected in the device list. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/1.1/import-export/export-page.png - :alt: Export + :alt: Export -For importing devices into the system, only the required fields are needed, -for example, the following CSV file will import a device named -``TestImport`` with mac address ``00:11:22:09:44:55`` in the organization with -UUID ``3cb5e18c-0312-48ab-8dbd-038b8415bd6f``:: +For importing devices into the system, only the required fields are +needed, for example, the following CSV file will import a device named +``TestImport`` with mac address ``00:11:22:09:44:55`` in the organization +with UUID ``3cb5e18c-0312-48ab-8dbd-038b8415bd6f``: + +:: organization_id,name,mac_address 3cb5e18c-0312-48ab-8dbd-038b8415bd6f,TestImport,00:11:22:09:44:55 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/1.1/import-export/import-page.png - :alt: Import / Export + :alt: Import / Export Organization Limits ~~~~~~~~~~~~~~~~~~~ @@ -1073,20 +1135,21 @@ Allows configuring following limits for each organization: You can change the limits from the organization's admin page: .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/1.1/organization-limits.png - :alt: Organization limits + :alt: Organization limits How to setup WireGuard tunnels ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Follow the procedure described below to setup WireGuard tunnels on your devices. +Follow the procedure described below to setup WireGuard tunnels on your +devices. -**Note:** This example uses **Shared systemwide (no organization)** option as -the organization for VPN server and VPN client template. You can use any -organization as long as VPN server, VPN client template and Device has same -organization. +**Note:** This example uses **Shared systemwide (no organization)** option +as the organization for VPN server and VPN client template. You can use +any organization as long as VPN server, VPN client template and Device has +same organization. 1. Create VPN server configuration for WireGuard -################################################ +++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/vpn/add/`` to add a new VPN server. 2. We will set **Name** of this VPN server ``Wireguard`` and **Host** as @@ -1094,85 +1157,88 @@ organization. WireGuard VPN server). 3. Select ``WireGuard`` from the dropdown as **VPN Backend**. 4. When using WireGuard, OpenWISP takes care of managing IP addresses - (assigning an IP address to each VPN peer). You can create a new subnet or - select an existing one from the dropdown menu. You can also assign an - **Internal IP** to the WireGuard Server or leave it empty for OpenWISP to - configure. This IP address will be used by the WireGuard interface on - server. -5. We have set the **Webhook Endpoint** as ``https://wireguard-server.mydomain.com:8081/trigger-update`` - for this example. You will need to update this according to you VPN upgrader - endpoint. Set **Webhook AuthToken** to any strong passphrase, this will be - used to ensure that configuration upgrades are requested from trusted - sources. - - **Note**: If you are following this tutorial for also setting up WireGuard - VPN server, just substitute ``wireguard-server.mydomain.com`` with hostname - of your VPN server and follow the steps in next section. - -6. Under the configuration section, set the name of WireGuard tunnel 1 interface. - We have used ``wg0`` in this example. + (assigning an IP address to each VPN peer). You can create a new subnet + or select an existing one from the dropdown menu. You can also assign + an **Internal IP** to the WireGuard Server or leave it empty for + OpenWISP to configure. This IP address will be used by the WireGuard + interface on server. +5. We have set the **Webhook Endpoint** as + ``https://wireguard-server.mydomain.com:8081/trigger-update`` for this + example. You will need to update this according to you VPN upgrader + endpoint. Set **Webhook AuthToken** to any strong passphrase, this will + be used to ensure that configuration upgrades are requested from + trusted sources. + + **Note**: If you are following this tutorial for also setting up + WireGuard VPN server, just substitute ``wireguard-server.mydomain.com`` + with hostname of your VPN server and follow the steps in next section. + +6. Under the configuration section, set the name of WireGuard tunnel 1 + interface. We have used ``wg0`` in this example. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-tutorial/vpn-server-1.png - :alt: WireGuard VPN server configuration example 1 + :alt: WireGuard VPN server configuration example 1 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-tutorial/vpn-server-2.png - :alt: WireGuard VPN server configuration example 2 + :alt: WireGuard VPN server configuration example 2 -7. After clicking on **Save and continue editing**, you will see that OpenWISP - has automatically created public and private key for WireGuard server in - **System Defined Variables** along with internal IP address information. +7. After clicking on **Save and continue editing**, you will see that + OpenWISP has automatically created public and private key for WireGuard + server in **System Defined Variables** along with internal IP address + information. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-tutorial/vpn-server-3.png - :alt: WireGuard VPN server configuration example 3 + :alt: WireGuard VPN server configuration example 3 2. Deploy Wireguard VPN Server -############################## +++++++++++++++++++++++++++++++ -If you haven't already setup WireGuard on your VPN server, this will be a good -time do so. We recommend using the `ansible-wireguard-openwisp `_ -role for installing WireGuard since it also installs scripts that allows -OpenWISP to manage WireGuard VPN server. +If you haven't already setup WireGuard on your VPN server, this will be a +good time do so. We recommend using the `ansible-wireguard-openwisp +`_ role for +installing WireGuard since it also installs scripts that allows OpenWISP +to manage WireGuard VPN server. -Pay attention to the VPN server attributes used in your playbook. It should be same as -VPN server configuration in OpenWISP. +Pay attention to the VPN server attributes used in your playbook. It +should be same as VPN server configuration in OpenWISP. 3. Create VPN client template for WireGuard VPN Server -###################################################### +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/template/add/`` to add a new template. -2. Set ``Wireguard Client`` as **Name** (you can set whatever you want) and - select ``VPN-client`` as **type** from the dropdown list. -3. The **Backend** field refers to the backend of the device this template can - be applied to. For this example, we will leave it to ``OpenWRT``. -4. Select the correct VPN server from the dropdown for the **VPN** field. Here - it is ``Wireguard``. -5. Ensure that **Automatic tunnel provisioning** is checked. This will make - OpenWISP to automatically generate public and private keys and provision IP - address for each WireGuard VPN client. -6. After clicking on **Save and continue editing** button, you will see details - of *Wireguard* VPN server in **System Defined Variables**. The template - configuration will be automatically generated which you can tweak - accordingly. We will use the automatically generated VPN client configuration - for this example. +2. Set ``Wireguard Client`` as **Name** (you can set whatever you want) + and select ``VPN-client`` as **type** from the dropdown list. +3. The **Backend** field refers to the backend of the device this template + can be applied to. For this example, we will leave it to ``OpenWRT``. +4. Select the correct VPN server from the dropdown for the **VPN** field. + Here it is ``Wireguard``. +5. Ensure that **Automatic tunnel provisioning** is checked. This will + make OpenWISP to automatically generate public and private keys and + provision IP address for each WireGuard VPN client. +6. After clicking on **Save and continue editing** button, you will see + details of *Wireguard* VPN server in **System Defined Variables**. The + template configuration will be automatically generated which you can + tweak accordingly. We will use the automatically generated VPN client + configuration for this example. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-tutorial/template.png :alt: WireGuard VPN client template example 4. Apply Wireguard VPN template to devices -########################################## +++++++++++++++++++++++++++++++++++++++++++ **Note**: This step assumes that you already have a device registered on OpenWISP. Register or create a device before proceeding. 1. Open the **Configuration** tab of the concerned device. 2. Select the *WireGuard Client* template. -3. Upon clicking on **Save and continue editing** button, you will see some - entries in **System Defined Variables**. It will contain internal IP address, - private and public key for the WireGuard client on the device along with - details of WireGuard VPN server. +3. Upon clicking on **Save and continue editing** button, you will see + some entries in **System Defined Variables**. It will contain internal + IP address, private and public key for the WireGuard client on the + device along with details of WireGuard VPN server. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-tutorial/device-configuration.png - :alt: WireGuard VPN device configuration example + :alt: WireGuard VPN device configuration example **Voila!** You have successfully configured OpenWISP to manage WireGuard tunnels for your devices. @@ -1183,99 +1249,104 @@ How to setup VXLAN over WireGuard tunnels By following these steps, you will be able to setup layer 2 VXLAN tunnels encapsulated in WireGuard tunnels which work on layer 3. -**Note:** This example uses **Shared systemwide (no organization)** option as -the organization for VPN server and VPN client template. You can use any -organization as long as VPN server, VPN client template and Device has same -organization. +**Note:** This example uses **Shared systemwide (no organization)** option +as the organization for VPN server and VPN client template. You can use +any organization as long as VPN server, VPN client template and Device has +same organization. 1. Create VPN server configuration for VXLAN over WireGuard -########################################################### ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/vpn/add/`` to add a new VPN server. -2. We will set **Name** of this VPN server ``Wireguard VXLAN`` and **Host** as - ``wireguard-vxlan-server.mydomain.com`` (update this to point to your - WireGuard VXLAN VPN server). +2. We will set **Name** of this VPN server ``Wireguard VXLAN`` and + **Host** as ``wireguard-vxlan-server.mydomain.com`` (update this to + point to your WireGuard VXLAN VPN server). 3. Select ``VXLAN over WireGuard`` from the dropdown as **VPN Backend**. -4. When using VXLAN over WireGuard, OpenWISP takes care of managing IP addresses - (assigning an IP address to each VPN peer). You can create a new subnet or - select an existing one from the dropdown menu. You can also assign an - **Internal IP** to the WireGuard Server or leave it empty for OpenWISP to - configure. This IP address will be used by the WireGuard interface on - server. -5. We have set the **Webhook Endpoint** as ``https://wireguard-vxlan-server.mydomain.com:8081/trigger-update`` - for this example. You will need to update this according to you VPN upgrader - endpoint. Set **Webhook AuthToken** to any strong passphrase, this will be - used to ensure that configuration upgrades are requested from trusted - sources. - - **Note**: If you are following this tutorial for also setting up WireGuard - VPN server, just substitute ``wireguard-server.mydomain.com`` with hostname - of your VPN server and follow the steps in next section. - -6. Under the configuration section, set the name of WireGuard tunnel 1 interface. - We have used ``wg0`` in this example. +4. When using VXLAN over WireGuard, OpenWISP takes care of managing IP + addresses (assigning an IP address to each VPN peer). You can create a + new subnet or select an existing one from the dropdown menu. You can + also assign an **Internal IP** to the WireGuard Server or leave it + empty for OpenWISP to configure. This IP address will be used by the + WireGuard interface on server. +5. We have set the **Webhook Endpoint** as + ``https://wireguard-vxlan-server.mydomain.com:8081/trigger-update`` for + this example. You will need to update this according to you VPN + upgrader endpoint. Set **Webhook AuthToken** to any strong passphrase, + this will be used to ensure that configuration upgrades are requested + from trusted sources. + + **Note**: If you are following this tutorial for also setting up + WireGuard VPN server, just substitute ``wireguard-server.mydomain.com`` + with hostname of your VPN server and follow the steps in next section. + +6. Under the configuration section, set the name of WireGuard tunnel 1 + interface. We have used ``wg0`` in this example. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-vxlan-tutorial/vpn-server-1.png - :alt: WireGuard VPN VXLAN server configuration example 1 + :alt: WireGuard VPN VXLAN server configuration example 1 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-vxlan-tutorial/vpn-server-2.png - :alt: WireGuard VPN VXLAN server configuration example 2 + :alt: WireGuard VPN VXLAN server configuration example 2 -7. After clicking on **Save and continue editing**, you will see that OpenWISP - has automatically created public and private key for WireGuard server in - **System Defined Variables** along with internal IP address information. +7. After clicking on **Save and continue editing**, you will see that + OpenWISP has automatically created public and private key for WireGuard + server in **System Defined Variables** along with internal IP address + information. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-vxlan-tutorial/vpn-server-3.png - :alt: WireGuard VXLAN VPN server configuration example 3 + :alt: WireGuard VXLAN VPN server configuration example 3 2. Deploy Wireguard VXLAN VPN Server -#################################### +++++++++++++++++++++++++++++++++++++ -If you haven't already setup WireGuard on your VPN server, this will be a good -time do so. We recommend using the `ansible-wireguard-openwisp `_ -role for installing WireGuard since it also installs scripts that allows -OpenWISP to manage WireGuard VPN server along with VXLAN tunnels. +If you haven't already setup WireGuard on your VPN server, this will be a +good time do so. We recommend using the `ansible-wireguard-openwisp +`_ role for +installing WireGuard since it also installs scripts that allows OpenWISP +to manage WireGuard VPN server along with VXLAN tunnels. -Pay attention to the VPN server attributes used in your playbook. It should be same as -VPN server configuration in OpenWISP. +Pay attention to the VPN server attributes used in your playbook. It +should be same as VPN server configuration in OpenWISP. 3. Create VPN client template for WireGuard VXLAN VPN Server -############################################################ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/template/add/`` to add a new template. -2. Set ``Wireguard VXLAN Client`` as **Name** (you can set whatever you want) and - select ``VPN-client`` as **type** from the dropdown list. -3. The **Backend** field refers to the backend of the device this template can - be applied to. For this example, we will leave it to ``OpenWRT``. -4. Select the correct VPN server from the dropdown for the **VPN** field. Here - it is ``Wireguard VXLAN``. -5. Ensure that **Automatic tunnel provisioning** is checked. This will make - OpenWISP to automatically generate public and private keys and provision IP - address for each WireGuard VPN client along with VXLAN Network Indentifier(VNI). -6. After clicking on **Save and continue editing** button, you will see details - of *Wireguard VXLAN* VPN server in **System Defined Variables**. The template - configuration will be automatically generated which you can tweak - accordingly. We will use the automatically generated VPN client configuration - for this example. +2. Set ``Wireguard VXLAN Client`` as **Name** (you can set whatever you + want) and select ``VPN-client`` as **type** from the dropdown list. +3. The **Backend** field refers to the backend of the device this template + can be applied to. For this example, we will leave it to ``OpenWRT``. +4. Select the correct VPN server from the dropdown for the **VPN** field. + Here it is ``Wireguard VXLAN``. +5. Ensure that **Automatic tunnel provisioning** is checked. This will + make OpenWISP to automatically generate public and private keys and + provision IP address for each WireGuard VPN client along with VXLAN + Network Indentifier(VNI). +6. After clicking on **Save and continue editing** button, you will see + details of *Wireguard VXLAN* VPN server in **System Defined + Variables**. The template configuration will be automatically generated + which you can tweak accordingly. We will use the automatically + generated VPN client configuration for this example. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-vxlan-tutorial/template.png :alt: WireGuard VXLAN VPN client template example 4. Apply Wireguard VXLAN VPN template to devices -################################################ +++++++++++++++++++++++++++++++++++++++++++++++++ **Note**: This step assumes that you already have a device registered on OpenWISP. Register or create a device before proceeding. 1. Open the **Configuration** tab of the concerned device. 2. Select the *WireGuard VXLAN Client* template. -3. Upon clicking on **Save and continue editing** button, you will see some - entries in **System Defined Variables**. It will contain internal IP address, - private and public key for the WireGuard client on the device and details of - WireGuard VPN server along with VXLAN Network Identifier(VNI) of this device. +3. Upon clicking on **Save and continue editing** button, you will see + some entries in **System Defined Variables**. It will contain internal + IP address, private and public key for the WireGuard client on the + device and details of WireGuard VPN server along with VXLAN Network + Identifier(VNI) of this device. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/wireguard-vxlan-tutorial/device-configuration.png - :alt: WireGuard VXLAN VPN device configuration example + :alt: WireGuard VXLAN VPN device configuration example **Voila!** You have successfully configured OpenWISP to manage VXLAN over WireGuard tunnels for your devices. @@ -1283,264 +1354,292 @@ WireGuard tunnels for your devices. How to setup ZeroTier Tunnels ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Follow the procedure described below to setup ZeroTier tunnels on your devices. +Follow the procedure described below to setup ZeroTier tunnels on your +devices. -**Note:** This example uses **Shared systemwide (no organization)** option as -the organization for VPN server and VPN client template. You can use any -organization as long as VPN server, VPN client template and Device has same -organization. +**Note:** This example uses **Shared systemwide (no organization)** option +as the organization for VPN server and VPN client template. You can use +any organization as long as VPN server, VPN client template and Device has +same organization. 1. Configure Self-Hosted ZeroTier Network Controller -#################################################### +++++++++++++++++++++++++++++++++++++++++++++++++++++ -If you haven't already set up a self-hosted Zerotier network controller on your server, -now is a good time to do so. You can start by simply installing Zerotier on your server -from the `official website `_. +If you haven't already set up a self-hosted Zerotier network controller on +your server, now is a good time to do so. You can start by simply +installing Zerotier on your server from the `official website +`_. 2. Create VPN server configuration for ZeroTier -############################################### ++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/vpn/add/`` to add a new VPN server. 2. We will set **Name** of this VPN server ``ZeroTier`` and **Host** as - ``my-zerotier-server.mydomain.com:9993`` (update this to point to your ZeroTier VPN server). + ``my-zerotier-server.mydomain.com:9993`` (update this to point to your + ZeroTier VPN server). 3. Select ``ZeroTier`` from the dropdown as **VPN Backend**. 4. When using ZeroTier, OpenWISP takes care of managing IP addresses - (assigning an IP address to each VPN clients (Zerotier network members). - You can create a new subnet or select an existing one from the dropdown menu. - You can also assign an **Internal IP** to the Zerotier controller or - leave it empty for OpenWISP to configure. This IP address will be used - to assign it to the Zerotier controller running on the server. -5. Set the **Webhook AuthToken**, this will be ZeroTier authorization token which you - can obtain by running the following command on the ZeroTier controller: + (assigning an IP address to each VPN clients (Zerotier network + members). You can create a new subnet or select an existing one from + the dropdown menu. You can also assign an **Internal IP** to the + Zerotier controller or leave it empty for OpenWISP to configure. This + IP address will be used to assign it to the Zerotier controller running + on the server. +5. Set the **Webhook AuthToken**, this will be ZeroTier authorization + token which you can obtain by running the following command on the + ZeroTier controller: .. code-block:: shell - sudo cat /var/lib/zerotier-one/authtoken.secret + sudo cat /var/lib/zerotier-one/authtoken.secret .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/vpn-server-1.png - :alt: ZeroTier VPN server configuration example 1 + :alt: ZeroTier VPN server configuration example 1 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/vpn-server-2.png - :alt: ZeroTier VPN server configuration example 2 + :alt: ZeroTier VPN server configuration example 2 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/vpn-server-3.png - :alt: ZeroTier VPN server configuration example 3 + :alt: ZeroTier VPN server configuration example 3 .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/vpn-server-4.png - :alt: ZeroTier VPN server configuration example 4 + :alt: ZeroTier VPN server configuration example 4 -6. After clicking on **Save and continue editing**, OpenWISP automatically detects - the node address of the Zerotier controller and creates a Zerotier network. - The **network_id** of this network can be viewed in the **System Defined Variables** - section, where it also provides internal IP address information. +6. After clicking on **Save and continue editing**, OpenWISP automatically + detects the node address of the Zerotier controller and creates a + Zerotier network. The **network_id** of this network can be viewed in + the **System Defined Variables** section, where it also provides + internal IP address information. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/vpn-server-5.png - :alt: ZeroTier VPN server configuration example 5 + :alt: ZeroTier VPN server configuration example 5 3. Create VPN client template for ZeroTier VPN Server -##################################################### ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1. Visit ``/admin/config/template/add/`` to add a new template. 2. Set ``ZeroTier Client`` as **Name** (you can set whatever you want) and select ``VPN-client`` as **type** from the dropdown list. -3. The **Backend** field refers to the backend of the device this template can - be applied to. For this example, we will leave it to ``OpenWRT``. -4. Select the correct VPN server from the dropdown for the **VPN** field. Here - it is ``ZeroTier``. +3. The **Backend** field refers to the backend of the device this template + can be applied to. For this example, we will leave it to ``OpenWRT``. +4. Select the correct VPN server from the dropdown for the **VPN** field. + Here it is ``ZeroTier``. 5. Ensure that the **Automatic tunnel provisioning** option is checked. This will enable OpenWISP to automatically provision an IP address and - ZeroTier identity secrets (used for assigning member IDs) for each ZeroTier VPN client. -6. After clicking on **Save and continue editing** button, you will see details - of *ZeroTier* VPN server in **System Defined Variables**. The template - configuration will be automatically generated which you can tweak - accordingly. We will use the automatically generated VPN client configuration - for this example. + ZeroTier identity secrets (used for assigning member IDs) for each + ZeroTier VPN client. +6. After clicking on **Save and continue editing** button, you will see + details of *ZeroTier* VPN server in **System Defined Variables**. The + template configuration will be automatically generated which you can + tweak accordingly. We will use the automatically generated VPN client + configuration for this example. **Note:** OpenWISP uses `zerotier-idtool `_ to manage **ZeroTier identity secrets**. Please make sure that you have -`ZeroTier package installed `_ on the server. +`ZeroTier package installed `_ on the +server. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/template.png :alt: ZeroTier VPN client template example 4. Apply ZeroTier VPN template to devices -######################################### ++++++++++++++++++++++++++++++++++++++++++ **Note**: This step assumes that you already have a device registered on OpenWISP. Register or create a device before proceeding. 1. Open the **Configuration** tab of the concerned device. 2. Select the *ZeroTier Client* template. -3. Upon clicking the **Save and Continue Editing** button, you will see entries - in the **System Defined Variables** section. These entries will include **zerotier_member_id**, **identity_secret**, - and the internal **IP address** of the ZeroTier client (network member) on the device, along with details of the VPN server. +3. Upon clicking the **Save and Continue Editing** button, you will see + entries in the **System Defined Variables** section. These entries will + include **zerotier_member_id**, **identity_secret**, and the internal + **IP address** of the ZeroTier client (network member) on the device, + along with details of the VPN server. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/device-configuration-1.png - :alt: ZeroTier VPN device configuration example 1 + :alt: ZeroTier VPN device configuration example 1 -4. Once the configuration is successfully applied to the device, you will notice a new ZeroTier interface - that is up and running. This interface will have the name ``owzt89f498`` (where ``owzt`` is followed - by the last six hexadecimal characters of the ZeroTier **network ID**). +4. Once the configuration is successfully applied to the device, you will + notice a new ZeroTier interface that is up and running. This interface + will have the name ``owzt89f498`` (where ``owzt`` is followed by the + last six hexadecimal characters of the ZeroTier **network ID**). .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/zerotier-tutorial/device-configuration-2.png - :alt: ZeroTier VPN device configuration example 2 + :alt: ZeroTier VPN device configuration example 2 -**Voila!** You have successfully configured OpenWISP -to manage ZeroTier tunnels for your devices. +**Voila!** You have successfully configured OpenWISP to manage ZeroTier +tunnels for your devices. How to configure automatic provisioning of subnets and IPs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following steps will help you configure automatic provisioning of subnets and IPs -for devices. +The following steps will help you configure automatic provisioning of +subnets and IPs for devices. 1. Create a Subnet and a Subnet Division Rule -############################################# ++++++++++++++++++++++++++++++++++++++++++++++ -Create a master subnet under which automatically generated subnets will be provisioned. +Create a master subnet under which automatically generated subnets will be +provisioned. -**Note**: Choose the size of the subnet appropriately considering your use case. +**Note**: Choose the size of the subnet appropriately considering your use +case. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/subnet.png - :alt: Creating a master subnet example + :alt: Creating a master subnet example -On the same page, add a **subnet division rule** that will be used to provision subnets -under the master subnet. +On the same page, add a **subnet division rule** that will be used to +provision subnets under the master subnet. -The type of subnet division rule controls when subnets and IP addresses will be provisioned -for a device. The subnet division rule types currently implemented are described below. +The type of subnet division rule controls when subnets and IP addresses +will be provisioned for a device. The subnet division rule types currently +implemented are described below. Device Subnet Division Rule -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +........................... -This rule type is triggered whenever a device configuration (``config.Config`` model) -is created for the organization specified in the rule. +This rule type is triggered whenever a device configuration +(``config.Config`` model) is created for the organization specified in the +rule. -Creating a new rule of "Device" type will also provision subnets and -IP addresses for existing devices of the organization automatically. +Creating a new rule of "Device" type will also provision subnets and IP +addresses for existing devices of the organization automatically. **Note**: a device without a configuration will not trigger this rule. VPN Subnet Division Rule -^^^^^^^^^^^^^^^^^^^^^^^^ +........................ This rule is triggered when a VPN client template is assigned to a device, provided the VPN server to which the VPN client template relates to has the same subnet for which the subnet division rule is created. -**Note:** This rule will only work for **WireGuard** and **VXLAN over WireGuard** -VPN servers. +**Note:** This rule will only work for **WireGuard** and **VXLAN over +WireGuard** VPN servers. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/subnet-division-rule.png - :alt: Creating a subnet division rule example + :alt: Creating a subnet division rule example In this example, **VPN subnet division rule** is used. 2. Create a VPN Server -###################### +++++++++++++++++++++++ -Now create a VPN Server and choose the previously created **master subnet** as the subnet for -this VPN Server. +Now create a VPN Server and choose the previously created **master +subnet** as the subnet for this VPN Server. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/vpn-server.png - :alt: Creating a VPN Server example + :alt: Creating a VPN Server example 3. Create a VPN Client Template -############################### ++++++++++++++++++++++++++++++++ -Create a template, setting the **Type** field to **VPN Client** and **VPN** field to use the -previously created VPN Server. +Create a template, setting the **Type** field to **VPN Client** and +**VPN** field to use the previously created VPN Server. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/vpn-client.png - :alt: Creating a VPN Client template example + :alt: Creating a VPN Client template example -**Note**: You can also check the **Enable by default** field if you want to automatically -apply this template to devices that will register in future. +**Note**: You can also check the **Enable by default** field if you want +to automatically apply this template to devices that will register in +future. 4. Apply VPN Client Template to Devices -####################################### ++++++++++++++++++++++++++++++++++++++++ -With everything in place, you can now apply the VPN Client Template to devices. +With everything in place, you can now apply the VPN Client Template to +devices. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/apply-template-to-device.png - :alt: Adding template to device example + :alt: Adding template to device example -After saving the device, you should see all provisioned Subnets and IPs for this device -under `System Defined Variables <#system-defined-variables>`_. +After saving the device, you should see all provisioned Subnets and IPs +for this device under `System Defined Variables +<#system-defined-variables>`_. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/subnet-division-rule/system-defined-variables.png - :alt: Provisioned Subnets and IPs available as System Defined Variables example + :alt: Provisioned Subnets and IPs available as System Defined Variables example -Voila! You can now use these variables in configuration of the device. Refer to `How to use configuration variables <#how-to-use-configuration-variables>`_ -section of this documentation to learn how to use configuration variables. +Voila! You can now use these variables in configuration of the device. +Refer to `How to use configuration variables +<#how-to-use-configuration-variables>`_ section of this documentation to +learn how to use configuration variables. Important notes for using Subnet Division -######################################### - -- In the above example Subnet, VPN Server, and VPN Client Template belonged to the **default** organization. - You can use **Systemwide Shared** Subnet, VPN Server, or VPN Client Template too, but - Subnet Division Rule will be always related to an organization. The Subnet Division Rule will only be - triggered when such VPN Client Template will be applied to a Device having the same organization as Subnet Division Rule. - -- You can also use the configuration variables for provisioned subnets and IPs in the Template. - Each variable will be resolved differently for different devices. E.g. ``OW_subnet1_ip1`` will resolve to - ``10.0.0.1`` for one device and ``10.0.0.55`` for another. Every device gets its own set of subnets and IPs. - But don't forget to provide the default fall back values in the "default values" template field - (used mainly for validation). - -- The Subnet Division Rule will automatically create a reserved subnet, this subnet can be used - to provision any IP addresses that have to be created manually. The rest of the master subnet - address space **must not** be interfered with or the automation implemented in this module ++++++++++++++++++++++++++++++++++++++++++ + +- In the above example Subnet, VPN Server, and VPN Client Template + belonged to the **default** organization. You can use **Systemwide + Shared** Subnet, VPN Server, or VPN Client Template too, but Subnet + Division Rule will be always related to an organization. The Subnet + Division Rule will only be triggered when such VPN Client Template will + be applied to a Device having the same organization as Subnet Division + Rule. +- You can also use the configuration variables for provisioned subnets and + IPs in the Template. Each variable will be resolved differently for + different devices. E.g. ``OW_subnet1_ip1`` will resolve to ``10.0.0.1`` + for one device and ``10.0.0.55`` for another. Every device gets its own + set of subnets and IPs. But don't forget to provide the default fall + back values in the "default values" template field (used mainly for + validation). +- The Subnet Division Rule will automatically create a reserved subnet, + this subnet can be used to provision any IP addresses that have to be + created manually. The rest of the master subnet address space **must + not** be interfered with or the automation implemented in this module will not work. - -- The above example used `VPN subnet division rule <#vpn-subnet-division-rule>`_. Similarly, - `device subnet division rule <#device-subnet-division-rule>`_ can be used, which only requires - `creating a subnet and a subnet division rule <#1-create-a-subnet-and-a-subnet-division-rule>`_. +- The above example used `VPN subnet division rule + <#vpn-subnet-division-rule>`_. Similarly, `device subnet division rule + <#device-subnet-division-rule>`_ can be used, which only requires + `creating a subnet and a subnet division rule + <#1-create-a-subnet-and-a-subnet-division-rule>`_. Limitations of Subnet Division -############################## +++++++++++++++++++++++++++++++ -In the current implementation, it is not possible to change "Size", "Number of Subnets" and -"Number of IPs" fields of an existing subnet division rule due to following reasons: +In the current implementation, it is not possible to change "Size", +"Number of Subnets" and "Number of IPs" fields of an existing subnet +division rule due to following reasons: Size -^^^^ +.... -Allowing to change size of provisioned subnets of an existing subnet division rule -will require rebuilding of Subnets and IP addresses which has possibility of breaking -existing configurations. +Allowing to change size of provisioned subnets of an existing subnet +division rule will require rebuilding of Subnets and IP addresses which +has possibility of breaking existing configurations. Number of Subnets -^^^^^^^^^^^^^^^^^ +................. -Allowing to decrease number of subnets of an existing subnet division -rule can create patches of unused subnets dispersed everywhere in the master subnet. -Allowing to increase number of subnets will break the continuous allocation of subnets for -every device. It can also break configuration of devices. +Allowing to decrease number of subnets of an existing subnet division rule +can create patches of unused subnets dispersed everywhere in the master +subnet. Allowing to increase number of subnets will break the continuous +allocation of subnets for every device. It can also break configuration of +devices. Number of IPs -^^^^^^^^^^^^^ +............. Allowing to decrease number of IPs of an existing subnet division rule -will lead to deletion of IP Addresses which can break configuration of devices being used. -It **is allowed** to increase number of IPs. +will lead to deletion of IP Addresses which can break configuration of +devices being used. It **is allowed** to increase number of IPs. -If you want to make changes to any of above fields, delete the existing rule and create a -new one. The automation will provision for all existing devices that meets the criteria -for provisioning. **WARNING**: It is possible that devices get different subnets and IPs -from previous provisioning. +If you want to make changes to any of above fields, delete the existing +rule and create a new one. The automation will provision for all existing +devices that meets the criteria for provisioning. **WARNING**: It is +possible that devices get different subnets and IPs from previous +provisioning. Default Alerts / Notifications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+-----------------------+---------------------------------------------------------------------+ -| Notification Type | Use | -+-----------------------+---------------------------------------------------------------------+ -| ``config_error`` | Fires when status of a device configuration changes to ``error``. | -+-----------------------+---------------------------------------------------------------------+ -| ``device_registered`` | Fires when a new device is registered automatically on the network. | -+-----------------------+---------------------------------------------------------------------+ +===================== =================================================== +Notification Type Use +``config_error`` Fires when status of a device configuration changes + to ``error``. +``device_registered`` Fires when a new device is registered automatically + on the network. +===================== =================================================== REST API Reference ------------------ @@ -1550,17 +1649,19 @@ Live documentation .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/live-docu-api.png -A general live API documentation (following the OpenAPI specification) at ``/api/v1/docs/``. +A general live API documentation (following the OpenAPI specification) at +``/api/v1/docs/``. Browsable web interface ~~~~~~~~~~~~~~~~~~~~~~~ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/browsable-api-ui.png -Additionally, opening any of the endpoints `listed below <#list-of-endpoints>`_ -directly in the browser will show the `browsable API interface of Django-REST-Framework -`_, -which makes it even easier to find out the details of each endpoint. +Additionally, opening any of the endpoints `listed below +<#list-of-endpoints>`_ directly in the browser will show the `browsable +API interface of Django-REST-Framework +`_, which +makes it even easier to find out the details of each endpoint. Authentication ~~~~~~~~~~~~~~ @@ -1575,8 +1676,8 @@ the session authentication by logging in the django admin. Pagination ~~~~~~~~~~ -All *list* endpoints support the ``page_size`` parameter that allows paginating -the results in conjunction with the ``page`` parameter. +All *list* endpoints support the ``page_size`` parameter that allows +paginating the results in conjunction with the ``page`` parameter. .. code-block:: text @@ -1586,13 +1687,14 @@ the results in conjunction with the ``page`` parameter. List of endpoints ~~~~~~~~~~~~~~~~~ -Since the detailed explanation is contained in the `Live documentation <#live-documentation>`_ -and in the `Browsable web page <#browsable-web-interface>`_ of each point, -here we'll provide just a list of the available endpoints, -for further information please open the URL of the endpoint in your browser. +Since the detailed explanation is contained in the `Live documentation +<#live-documentation>`_ and in the `Browsable web page +<#browsable-web-interface>`_ of each point, here we'll provide just a list +of the available endpoints, for further information please open the URL of +the endpoint in your browser. List devices -############ +++++++++++++ .. code-block:: text @@ -1600,111 +1702,116 @@ List devices **Available filters** -You can filter a list of devices based on their configuration -status using the ``status`` (e.g modified, applied, or error). +You can filter a list of devices based on their configuration status using +the ``status`` (e.g modified, applied, or error). .. code-block:: text - GET /api/v1/controller/device/?config__status={status} + GET /api/v1/controller/device/?config__status={status} You can filter a list of devices based on their configuration backend -using the ``backend`` (e.g netjsonconfig.OpenWrt or netjsonconfig.OpenWisp). +using the ``backend`` (e.g netjsonconfig.OpenWrt or +netjsonconfig.OpenWisp). .. code-block:: text - GET /api/v1/controller/device/?config__backend={backend} + GET /api/v1/controller/device/?config__backend={backend} -You can filter a list of devices based on their -organization using the ``organization_id`` or ``organization_slug``. +You can filter a list of devices based on their organization using the +``organization_id`` or ``organization_slug``. .. code-block:: text - GET /api/v1/controller/device/?organization={organization_id} + GET /api/v1/controller/device/?organization={organization_id} .. code-block:: text - GET /api/v1/controller/device/?organization_slug={organization_slug} + GET /api/v1/controller/device/?organization_slug={organization_slug} -You can filter a list of devices based on their -configuration templates using the ``template_id``. +You can filter a list of devices based on their configuration templates +using the ``template_id``. .. code-block:: text - GET /api/v1/controller/device/?config__templates={template_id} + GET /api/v1/controller/device/?config__templates={template_id} -You can filter a list of devices based on -their device group using the ``group_id``. +You can filter a list of devices based on their device group using the +``group_id``. .. code-block:: text - GET /api/v1/controller/device/?group={group_id} + GET /api/v1/controller/device/?group={group_id} -You can filter a list of devices that have a device -location object using the ``with_geo`` (eg. true or false). +You can filter a list of devices that have a device location object using +the ``with_geo`` (eg. true or false). .. code-block:: text - GET /api/v1/controller/device/?with_geo={with_geo} + GET /api/v1/controller/device/?with_geo={with_geo} -You can filter a list of devices based on -their creation time using the ``creation_time``. +You can filter a list of devices based on their creation time using the +``creation_time``. .. code-block:: text - # Created exact - GET /api/v1/controller/device/?created={creation_time} + # Created exact + GET /api/v1/controller/device/?created={creation_time} - # Created greater than or equal to - GET /api/v1/controller/device/?created__gte={creation_time} + # Created greater than or equal to + GET /api/v1/controller/device/?created__gte={creation_time} - # Created is less than - GET /api/v1/controller/device/?created__lt={creation_time} + # Created is less than + GET /api/v1/controller/device/?created__lt={creation_time} Create device -############# ++++++++++++++ .. code-block:: text POST /api/v1/controller/device/ Get device detail -################# ++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{id}/ Download device configuration -############################# ++++++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{id}/configuration/ -The above endpoint triggers the download of a ``tar.gz`` file containing the generated configuration for that specific device. +The above endpoint triggers the download of a ``tar.gz`` file containing +the generated configuration for that specific device. Change details of device -######################## +++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/device/{id}/ Patch details of device -####################### ++++++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/device/{id}/ -**Note**: To assign, unassign, and change the order of the assigned templates add, -remove, and change the order of the ``{id}`` of the templates under the ``config`` field in the JSON response respectively. -Moreover, you can also select and unselect templates in the HTML Form of the Browsable API. +**Note**: To assign, unassign, and change the order of the assigned +templates add, remove, and change the order of the ``{id}`` of the +templates under the ``config`` field in the JSON response respectively. +Moreover, you can also select and unselect templates in the HTML Form of +the Browsable API. -The required template(s) from the organization(s) of the device will added automatically -to the ``config`` and cannot be removed. +The required template(s) from the organization(s) of the device will added +automatically to the ``config`` and cannot be removed. -**Example usage**: For assigning template(s) add the/their {id} to the config of a device, +**Example usage**: For assigning template(s) add the/their {id} to the +config of a device, .. code-block:: shell @@ -1718,7 +1825,8 @@ to the ``config`` and cannot be removed. } }' -**Example usage**: For removing assigned templates, simply remove the/their {id} from the config of a device, +**Example usage**: For removing assigned templates, simply remove +the/their {id} from the config of a device, .. code-block:: shell @@ -1732,7 +1840,8 @@ to the ``config`` and cannot be removed. } }' -**Example usage**: For reordering the templates simply change their order from the config of a device, +**Example usage**: For reordering the templates simply change their order +from the config of a device, .. code-block:: shell @@ -1752,119 +1861,119 @@ to the ``config`` and cannot be removed. }' Delete device -############# ++++++++++++++ .. code-block:: text DELETE /api/v1/controller/device/{id}/ List device connections -####################### ++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{id}/connection/ Create device connection -######################## +++++++++++++++++++++++++ .. code-block:: text POST /api/v1/controller/device/{id}/connection/ Get device connection detail -############################ +++++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{id}/connection/{id}/ Change device connection detail -############################### ++++++++++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/device/{id}/connection/{id}/ Patch device connection detail -############################## +++++++++++++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/device/{id}/connection/{id}/ Delete device connection -######################## +++++++++++++++++++++++++ .. code-block:: text DELETE /api/v1/controller/device/{id}/connection/{id}/ List credentials -################ +++++++++++++++++ .. code-block:: text GET /api/v1/connection/credential/ Create credential -################# ++++++++++++++++++ .. code-block:: text POST /api/v1/connection/credential/ Get credential detail -##################### ++++++++++++++++++++++ .. code-block:: text GET /api/v1/connection/credential/{id}/ Change credential detail -######################## +++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/connection/credential/{id}/ Patch credential detail -####################### ++++++++++++++++++++++++ .. code-block:: text PATCH /api/v1/connection/credential/{id}/ Delete credential -################# ++++++++++++++++++ .. code-block:: text DELETE /api/v1/connection/credential/{id}/ List commands of a device -######################### ++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{id}/command/ Execute a command a device -########################## +++++++++++++++++++++++++++ .. code-block:: text POST /api/v1/controller/device/{id}/command/ Get command details -################### ++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/device/{device_id}/command/{command_id}/ List device groups -################## +++++++++++++++++++ .. code-block:: text @@ -1872,58 +1981,59 @@ List device groups **Available filters** -You can filter a list of device groups based on their -organization using the ``organization_id`` or ``organization_slug``. +You can filter a list of device groups based on their organization using +the ``organization_id`` or ``organization_slug``. .. code-block:: text - GET /api/v1/controller/group/?organization={organization_id} + GET /api/v1/controller/group/?organization={organization_id} .. code-block:: text - GET /api/v1/controller/group/?organization_slug={organization_slug} + GET /api/v1/controller/group/?organization_slug={organization_slug} -You can filter a list of device groups that have a -device object using the ``empty`` (eg. true or false). +You can filter a list of device groups that have a device object using the +``empty`` (eg. true or false). .. code-block:: text - GET /api/v1/controller/group/?empty={empty} - + GET /api/v1/controller/group/?empty={empty} Create device group -################### ++++++++++++++++++++ .. code-block:: text POST /api/v1/controller/group/ Get device group detail -####################### ++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/group/{id}/ Change device group detail -########################## +++++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/group/{id}/ -This endpoint allows to change the `group templates <#group-templates>`_ too. +This endpoint allows to change the `group templates <#group-templates>`_ +too. Get device group from certificate common name -############################################# ++++++++++++++++++++++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/cert/{common_name}/group/ -This endpoint can be used to retrieve group information and metadata by the -common name of a certificate used in a VPN client tunnel, this endpoint is -used in layer 2 tunneling solutions for firewall/captive portals. +This endpoint can be used to retrieve group information and metadata by +the common name of a certificate used in a VPN client tunnel, this +endpoint is used in layer 2 tunneling solutions for firewall/captive +portals. It is also possible to filter device group by providing organization slug of certificate's organization as show in the example below: @@ -1933,24 +2043,21 @@ of certificate's organization as show in the example below: GET /api/v1/controller/cert/{common_name}/group/?org={org1_slug},{org2_slug} Get device location -################### ++++++++++++++++++++ .. code-block:: text - GET /api/v1/controller/device/{id}/location/ - Create device location -###################### +++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/device/{id}/location/ -You can create ``DeviceLocation`` object by using primary -keys of existing ``Location`` and ``FloorPlan`` objects as shown in -the example below. +You can create ``DeviceLocation`` object by using primary keys of existing +``Location`` and ``FloorPlan`` objects as shown in the example below. .. code-block:: json @@ -1960,10 +2067,10 @@ the example below. "indoor": "-36,264" } -**Note:** The ``indoor`` field represents the coordinates of the -point placed on the image from the top left corner. E.g. if you -placed the pointer on the top left corner of the floorplan image, -its indoor coordinates will be ``0,0``. +**Note:** The ``indoor`` field represents the coordinates of the point +placed on the image from the top left corner. E.g. if you placed the +pointer on the top left corner of the floorplan image, its indoor +coordinates will be ``0,0``. .. code-block:: text @@ -1980,8 +2087,8 @@ its indoor coordinates will be ``0,0``. You can also create related ``Location`` and ``FloorPlan`` objects for the device directly from this endpoint. -The following example demonstrates creating related location -object in a single request. +The following example demonstrates creating related location object in a +single request. .. code-block:: json @@ -2015,8 +2122,8 @@ object in a single request. } }' -**Note:** You can also specify the ``geometry`` in **Well-known text (WKT)** -format, like following: +**Note:** You can also specify the ``geometry`` in **Well-known text +(WKT)** format, like following: .. code-block:: json @@ -2029,10 +2136,10 @@ format, like following: } } -Similarly, you can create ``Floorplan`` object with the same request. -But, note that a ``FloorPlan`` can be added to ``DeviceLocation`` only -if the related ``Location`` object defines an indoor location. The example -below demonstrates creating both ``Location`` and ``FloorPlan`` objects. +Similarly, you can create ``Floorplan`` object with the same request. But, +note that a ``FloorPlan`` can be added to ``DeviceLocation`` only if the +related ``Location`` object defines an indoor location. The example below +demonstrates creating both ``Location`` and ``FloorPlan`` objects. .. code-block:: text @@ -2062,8 +2169,8 @@ below demonstrates creating both ``Location`` and ``FloorPlan`` objects. -F floorplan.floor=1 \ -F 'floorplan.image=@floorplan.png' -**Note:** The request in above example uses ``multipart content-type`` -for uploading floorplan image. +**Note:** The request in above example uses ``multipart content-type`` for +uploading floorplan image. You can also use an existing ``Location`` object and create a new floorplan for that location using this endpoint. @@ -2089,25 +2196,25 @@ floorplan for that location using this endpoint. -F 'floorplan.image=@floorplan.png' Change details of device location -################################# ++++++++++++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/device/{id}/location/ -**Note:** This endpoint can be used to update related ``Location`` -and ``Floorplan`` objects. Refer `examples of "Create device location" -section for information on payload format <#create-device-location>`_. +**Note:** This endpoint can be used to update related ``Location`` and +``Floorplan`` objects. Refer `examples of "Create device location" section +for information on payload format <#create-device-location>`_. Delete device location -###################### +++++++++++++++++++++++ .. code-block:: text DELETE /api/v1/controller/device/{id}/location/ Get device coordinates -###################### +++++++++++++++++++++++ .. code-block:: text @@ -2115,9 +2222,9 @@ Get device coordinates **Note:** This endpoint is intended to be used by devices. -This endpoint skips multi-tenancy and permission checks if the -device ``key`` is passed as ``query_param`` because the system -assumes that the device is updating it's position. +This endpoint skips multi-tenancy and permission checks if the device +``key`` is passed as ``query_param`` because the system assumes that the +device is updating it's position. .. code-block:: text @@ -2125,7 +2232,7 @@ assumes that the device is updating it's position. 'http://127.0.0.1:8000/api/v1/controller/device/8a85cc23-bad5-4c7e-b9f4-ffe298defb5c/coordinates/?key=10a0cb5a553c71099c0e4ef236435496' Update device coordinates -######################### ++++++++++++++++++++++++++ .. code-block:: text @@ -2133,9 +2240,9 @@ Update device coordinates **Note:** This endpoint is intended to be used by devices. -This endpoint skips multi-tenancy and permission checks if the -device ``key`` is passed as ``query_param`` because the system -assumes that the device is updating it's position. +This endpoint skips multi-tenancy and permission checks if the device +``key`` is passed as ``query_param`` because the system assumes that the +device is updating it's position. .. code-block:: json @@ -2161,7 +2268,7 @@ assumes that the device is updating it's position. }' List locations -############## +++++++++++++++ .. code-block:: text @@ -2169,8 +2276,8 @@ List locations **Available filters** -You can filter using ``organization_id`` or ``organization_slug`` -to get list locations that belongs to an organization. +You can filter using ``organization_id`` or ``organization_slug`` to get +list locations that belongs to an organization. .. code-block:: text @@ -2181,14 +2288,14 @@ to get list locations that belongs to an organization. GET /api/v1/controller/location/?organization_slug={organization_slug} Create location -############### ++++++++++++++++ .. code-block:: text POST /api/v1/controller/location/ -If you are creating an ``indoor`` location, you can use this endpoint -to create floorplan for the location. +If you are creating an ``indoor`` location, you can use this endpoint to +create floorplan for the location. The following example demonstrates creating floorplan along with location in a single request. @@ -2223,8 +2330,8 @@ in a single request. -F 'floorplan.image=@floorplan.png' \ -F organization=1f6c5666-1011-4f1d-bce9-fc6fcb4f3a05 -**Note:** You can also specify the ``geometry`` in **Well-known text (WKT)** -format, like following: +**Note:** You can also specify the ``geometry`` in **Well-known text +(WKT)** format, like following: .. code-block:: text @@ -2240,44 +2347,45 @@ format, like following: } Get location details -#################### +++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/location/{pk}/ Change location details -####################### ++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/location/{pk}/ -**Note**: Only the first floorplan data present can be -edited or changed. Setting the ``type`` of location to -outdoor will remove all the floorplans associated with it. +**Note**: Only the first floorplan data present can be edited or changed. +Setting the ``type`` of location to outdoor will remove all the floorplans +associated with it. -Refer `examples of "Create location" -section for information on payload format <#create-location>`_. +Refer `examples of "Create location" section for information on payload +format <#create-location>`_. Delete location -############### ++++++++++++++++ .. code-block:: text DELETE /api/v1/controller/location/{pk}/ List devices in a location -########################## +++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/location/{id}/device/ List locations with devices deployed (in GeoJSON format) -######################################################## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -**Note**: this endpoint will only list locations that have been assigned to a device. +**Note**: this endpoint will only list locations that have been assigned +to a device. .. code-block:: text @@ -2285,8 +2393,8 @@ List locations with devices deployed (in GeoJSON format) **Available filters** -You can filter using ``organization_id`` or ``organization_slug`` -to get list location of devices from that organization. +You can filter using ``organization_id`` or ``organization_slug`` to get +list location of devices from that organization. .. code-block:: text @@ -2297,7 +2405,7 @@ to get list location of devices from that organization. GET /api/v1/controller/location/geojson/?organization_slug={organization_slug} List floorplans -############### ++++++++++++++++ .. code-block:: text @@ -2305,8 +2413,8 @@ List floorplans **Available filters** -You can filter using ``organization_id`` or ``organization_slug`` -to get list floorplans that belongs to an organization. +You can filter using ``organization_id`` or ``organization_slug`` to get +list floorplans that belongs to an organization. .. code-block:: text @@ -2317,35 +2425,35 @@ to get list floorplans that belongs to an organization. GET /api/v1/controller/floorplan/?organization_slug={organization_slug} Create floorplan -################ +++++++++++++++++ .. code-block:: text POST /api/v1/controller/floorplan/ Get floorplan details -##################### ++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/floorplan/{pk}/ Change floorplan details -######################## +++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/floorplan/{pk}/ Delete floorplan -################ +++++++++++++++++ .. code-block:: text DELETE /api/v1/controller/floorplan/{pk}/ List templates -############## +++++++++++++++ .. code-block:: text @@ -2353,109 +2461,109 @@ List templates **Available filters** -You can filter a list of templates based on their organization -using the ``organization_id`` or ``organization_slug``. +You can filter a list of templates based on their organization using the +``organization_id`` or ``organization_slug``. .. code-block:: text - GET /api/v1/controller/template/?organization={organization_id} + GET /api/v1/controller/template/?organization={organization_id} .. code-block:: text GET /api/v1/controller/template/?organization_slug={organization_slug} -You can filter a list of templates based on their backend using -the ``backend`` (e.g netjsonconfig.OpenWrt or netjsonconfig.OpenWisp). +You can filter a list of templates based on their backend using the +``backend`` (e.g netjsonconfig.OpenWrt or netjsonconfig.OpenWisp). .. code-block:: text - GET /api/v1/controller/template/?backend={backend} + GET /api/v1/controller/template/?backend={backend} -You can filter a list of templates based on their -type using the ``type`` (eg. vpn or generic). +You can filter a list of templates based on their type using the ``type`` +(eg. vpn or generic). .. code-block:: text - GET /api/v1/controller/template/?type={type} + GET /api/v1/controller/template/?type={type} -You can filter a list of templates that are enabled -by default or not using the ``default`` (eg. true or false). +You can filter a list of templates that are enabled by default or not +using the ``default`` (eg. true or false). .. code-block:: text - GET /api/v1/controller/template/?default={default} + GET /api/v1/controller/template/?default={default} -You can filter a list of templates that are required -or not using the ``required`` (eg. true or false). +You can filter a list of templates that are required or not using the +``required`` (eg. true or false). .. code-block:: text - GET /api/v1/controller/template/?required={required} + GET /api/v1/controller/template/?required={required} -You can filter a list of templates based on -their creation time using the ``creation_time``. +You can filter a list of templates based on their creation time using the +``creation_time``. .. code-block:: text - # Created exact + # Created exact - GET /api/v1/controller/template/?created={creation_time} + GET /api/v1/controller/template/?created={creation_time} - # Created greater than or equal to + # Created greater than or equal to - GET /api/v1/controller/template/?created__gte={creation_time} + GET /api/v1/controller/template/?created__gte={creation_time} - # Created is less than + # Created is less than - GET /api/v1/controller/template/?created__lt={creation_time} + GET /api/v1/controller/template/?created__lt={creation_time} Create template -############### ++++++++++++++++ .. code-block:: text POST /api/v1/controller/template/ Get template detail -################### ++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/template/{id}/ Download template configuration -############################### ++++++++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/template/{id}/configuration/ -The above endpoint triggers the download of a ``tar.gz`` file -containing the generated configuration for that specific template. +The above endpoint triggers the download of a ``tar.gz`` file containing +the generated configuration for that specific template. Change details of template -########################## +++++++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/template/{id}/ Patch details of template -######################### ++++++++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/template/{id}/ Delete template -############### ++++++++++++++++ .. code-block:: text DELETE /api/v1/controller/template/{id}/ List VPNs -######### ++++++++++ .. code-block:: text @@ -2463,125 +2571,125 @@ List VPNs **Available filters** -You can filter a list of vpns based -on their backend using the ``backend`` -(e.g openwisp_controller.vpn_backends.OpenVpn -or openwisp_controller.vpn_backends.Wireguard). +You can filter a list of vpns based on their backend using the ``backend`` +(e.g openwisp_controller.vpn_backends.OpenVpn or +openwisp_controller.vpn_backends.Wireguard). .. code-block:: text - GET /api/v1/controller/vpn/?backend={backend} + GET /api/v1/controller/vpn/?backend={backend} -You can filter a list of vpns based on their subnet using the ``subnet_id``. +You can filter a list of vpns based on their subnet using the +``subnet_id``. .. code-block:: text - GET /api/v1/controller/vpn/?subnet={subnet_id} + GET /api/v1/controller/vpn/?subnet={subnet_id} -You can filter a list of vpns based on their organization -using the ``organization_id`` or ``organization_slug``. +You can filter a list of vpns based on their organization using the +``organization_id`` or ``organization_slug``. .. code-block:: text - GET /api/v1/controller/vpn/?organization={organization_id} + GET /api/v1/controller/vpn/?organization={organization_id} .. code-block:: text GET /api/v1/controller/vpn/?organization_slug={organization_slug} Create VPN -########## +++++++++++ .. code-block:: text POST /api/v1/controller/vpn/ Get VPN detail -############## +++++++++++++++ .. code-block:: text GET /api/v1/controller/vpn/{id}/ Download VPN configuration -########################## +++++++++++++++++++++++++++ .. code-block:: text GET /api/v1/controller/vpn/{id}/configuration/ -The above endpoint triggers the download of a ``tar.gz`` file -containing the generated configuration for that specific VPN. +The above endpoint triggers the download of a ``tar.gz`` file containing +the generated configuration for that specific VPN. Change details of VPN -##################### ++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/vpn/{id}/ Patch details of VPN -#################### +++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/vpn/{id}/ Delete VPN -########## +++++++++++ .. code-block:: text DELETE /api/v1/controller/vpn/{id}/ List CA -####### ++++++++ .. code-block:: text GET /api/v1/controller/ca/ Create new CA -############# ++++++++++++++ .. code-block:: text POST /api/v1/controller/ca/ Import existing CA -################## +++++++++++++++++++ .. code-block:: text POST /api/v1/controller/ca/ -**Note**: To import an existing CA, only ``name``, ``certificate`` -and ``private_key`` fields have to be filled in the ``HTML`` form or -included in the ``JSON`` format. +**Note**: To import an existing CA, only ``name``, ``certificate`` and +``private_key`` fields have to be filled in the ``HTML`` form or included +in the ``JSON`` format. Get CA Detail -############# ++++++++++++++ .. code-block:: text GET /api/v1/controller/ca/{id}/ Change details of CA -#################### +++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/ca/{id}/ Patch details of CA -################### ++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/ca/{id}/ Download CA(crl) -################ +++++++++++++++++ .. code-block:: text @@ -2591,81 +2699,81 @@ The above endpoint triggers the download of ``{id}.crl`` file containing up to date CRL of that specific CA. Delete CA -######### ++++++++++ .. code-block:: text DELETE /api/v1/controller/ca/{id}/ Renew CA -######## +++++++++ .. code-block:: text POST /api/v1/controller/ca/{id}/renew/ List Cert -######### ++++++++++ .. code-block:: text GET /api/v1/controller/cert/ Create new Cert -############### ++++++++++++++++ .. code-block:: text POST /api/v1/controller/cert/ Import existing Cert -#################### +++++++++++++++++++++ .. code-block:: text POST /api/v1/controller/cert/ **Note**: To import an existing Cert, only ``name``, ``ca``, -``certificate`` and ``private_key`` fields have to be filled -in the ``HTML`` form or included in the ``JSON`` format. +``certificate`` and ``private_key`` fields have to be filled in the +``HTML`` form or included in the ``JSON`` format. Get Cert Detail -############### ++++++++++++++++ .. code-block:: text GET /api/v1/controller/cert/{id}/ Change details of Cert -###################### +++++++++++++++++++++++ .. code-block:: text PUT /api/v1/controller/cert/{id}/ Patch details of Cert -##################### ++++++++++++++++++++++ .. code-block:: text PATCH /api/v1/controller/cert/{id}/ Delete Cert -########### ++++++++++++ .. code-block:: text DELETE /api/v1/controller/cert/{id}/ Renew Cert -########## +++++++++++ .. code-block:: text POST /api/v1/controller/cert/{id}/renew/ Revoke Cert -########### ++++++++++++ .. code-block:: text @@ -2674,95 +2782,97 @@ Revoke Cert Settings -------- -You can change the values for the following variables in -``settings.py`` to configure your instance of openwisp-controller. +You can change the values for the following variables in ``settings.py`` +to configure your instance of openwisp-controller. ``OPENWISP_SSH_AUTH_TIMEOUT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``int`` | -+--------------+-------------+ -| **default**: | ``2`` | -+--------------+-------------+ -| **unit**: | ``seconds`` | -+--------------+-------------+ +============ =========== +**type**: ``int`` +**default**: ``2`` +**unit**: ``seconds`` +============ =========== -Configure timeout to wait for an authentication response when establishing a SSH connection. +Configure timeout to wait for an authentication response when establishing +a SSH connection. ``OPENWISP_SSH_BANNER_TIMEOUT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``int`` | -+--------------+-------------+ -| **default**: | ``60`` | -+--------------+-------------+ -| **unit**: | ``seconds`` | -+--------------+-------------+ +============ =========== +**type**: ``int`` +**default**: ``60`` +**unit**: ``seconds`` +============ =========== -Configure timeout to wait for the banner to be presented when establishing a SSH connection. +Configure timeout to wait for the banner to be presented when establishing +a SSH connection. ``OPENWISP_SSH_COMMAND_TIMEOUT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``int`` | -+--------------+-------------+ -| **default**: | ``30`` | -+--------------+-------------+ -| **unit**: | ``seconds`` | -+--------------+-------------+ +============ =========== +**type**: ``int`` +**default**: ``30`` +**unit**: ``seconds`` +============ =========== -Configure timeout on blocking read/write operations when executing a command in a SSH connection. +Configure timeout on blocking read/write operations when executing a +command in a SSH connection. ``OPENWISP_SSH_CONNECTION_TIMEOUT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``int`` | -+--------------+-------------+ -| **default**: | ``5`` | -+--------------+-------------+ -| **unit**: | ``seconds`` | -+--------------+-------------+ +============ =========== +**type**: ``int`` +**default**: ``5`` +**unit**: ``seconds`` +============ =========== Configure timeout for the TCP connect when establishing a SSH connection. ``OPENWISP_CONNECTORS`` ~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------------------------------------------------------------------------+ -| **type**: | ``tuple`` | -+--------------+------------------------------------------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | ( | -| | ('openwisp_controller.connection.connectors.ssh.Ssh', 'SSH'), | -| | ('openwisp_controller.connection.connectors.openwrt.snmp.OpenWRTSnmp', 'OpenWRT SNMP'), | -| | ('openwisp_controller.connection.connectors.airos.snmp.AirOsSnmp', 'Ubiquiti AirOS SNMP'), | -| | ) | -+--------------+------------------------------------------------------------------------------------------------+ - -Available connector classes. Connectors are python classes that specify ways -in which OpenWISP can connect to devices in order to launch commands. +============ ================================================================================= +**type**: ``tuple`` +**default**: .. code-block:: python + + ( + ("openwisp_controller.connection.connectors.ssh.Ssh", "SSH"), + ( + "openwisp_controller.connection.connectors.openwrt.snmp.OpenWRTSnmp", + "OpenWRT SNMP", + ), + ( + "openwisp_controller.connection.connectors.airos.snmp.AirOsSnmp", + "Ubiquiti AirOS SNMP", + ), + ) +============ ================================================================================= + +Available connector classes. Connectors are python classes that specify +ways in which OpenWISP can connect to devices in order to launch commands. ``OPENWISP_UPDATE_STRATEGIES`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------------------------------------------------------------------------------------+ -| **type**: | ``tuple`` | -+--------------+----------------------------------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | ( | -| | ('openwisp_controller.connection.connectors.openwrt.ssh.OpenWrt', 'OpenWRT SSH'), | -| | ) | -+--------------+----------------------------------------------------------------------------------------+ +============ ============================================================================ +**type**: ``tuple`` +**default**: .. code-block:: python + + ( + ( + "openwisp_controller.connection.connectors.openwrt.ssh.OpenWrt", + "OpenWRT SSH", + ), + ) +============ ============================================================================ Available update strategies. An update strategy is a subclass of a -connector class which defines an ``update_config`` method which is -in charge of updating the configuration of the device. +connector class which defines an ``update_config`` method which is in +charge of updating the configuration of the device. This operation is launched in a background worker when the configuration of a device is changed. @@ -2773,243 +2883,254 @@ setting to make them available in OpenWISP. ``OPENWISP_CONFIG_UPDATE_MAPPING`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+--------------------------------------------------------------------+ -| **type**: | ``dict`` | -+--------------+--------------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | { | -| | 'netjsonconfig.OpenWrt': OPENWISP_UPDATE_STRATEGIES[0][0], | -| | } | -+--------------+--------------------------------------------------------------------+ +============ ================================================================== +**type**: ``dict`` +**default**: .. code-block:: python -A dictionary that maps configuration backends to update strategies in order to -automatically determine the update strategy of a device connection if the -update strategy field is left blank by the user. + { + "netjsonconfig.OpenWrt": OPENWISP_UPDATE_STRATEGIES[0][0], + } +============ ================================================================== + +A dictionary that maps configuration backends to update strategies in +order to automatically determine the update strategy of a device +connection if the update strategy field is left blank by the user. ``OPENWISP_CONTROLLER_BACKENDS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------------------------------------------+ -| **type**: | ``tuple`` | -+--------------+-----------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | ( | -| | ('netjsonconfig.OpenWrt', 'OpenWRT'), | -| | ('netjsonconfig.OpenWisp', 'OpenWISP'), | -| | ) | -+--------------+-----------------------------------------------+ - -Available configuration backends. For more information, see `netjsonconfig backends +============ =============================================== +**type**: ``tuple`` +**default**: .. code-block:: python + + ( + ("netjsonconfig.OpenWrt", "OpenWRT"), + ("netjsonconfig.OpenWisp", "OpenWISP"), + ) +============ =============================================== + +Available configuration backends. For more information, see `netjsonconfig +backends `_. ``OPENWISP_CONTROLLER_VPN_BACKENDS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------------------------------------------------------------------------------+ -| **type**: | ``tuple`` | -+--------------+----------------------------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | ( | -| | ('openwisp_controller.vpn_backends.OpenVpn', 'OpenVPN'), | -| | ('openwisp_controller.vpn_backends.Wireguard', 'WireGuard'), | -| | ('openwisp_controller.vpn_backends.VxlanWireguard', 'VXLAN over WireGuard'), | -| | ('openwisp_controller.vpn_backends.ZeroTier', 'ZeroTier'), | -| | ) | -+--------------+----------------------------------------------------------------------------------+ - -Available VPN backends for VPN Server objects. For more information, see `netjsonconfig VPN backends +============ ==================================================================== +**type**: ``tuple`` +**default**: .. code-block:: python + + ( + ("openwisp_controller.vpn_backends.OpenVpn", "OpenVPN"), + ("openwisp_controller.vpn_backends.Wireguard", "WireGuard"), + ( + "openwisp_controller.vpn_backends.VxlanWireguard", + "VXLAN over WireGuard", + ), + ("openwisp_controller.vpn_backends.ZeroTier", "ZeroTier"), + ) +============ ==================================================================== + +Available VPN backends for VPN Server objects. For more information, see +`netjsonconfig VPN backends `_. -A VPN backend must follow some basic rules in order to be compatible with *openwisp-controller*: +A VPN backend must follow some basic rules in order to be compatible with +*openwisp-controller*: -* it MUST allow at minimum and at maximum one VPN instance -* the main *NetJSON* property MUST match the lowercase version of the class name, - eg: when using the ``OpenVpn`` backend, the system will look into - ``config['openvpn']`` -* it SHOULD focus on the server capabilities of the VPN software being used +- it MUST allow at minimum and at maximum one VPN instance +- the main *NetJSON* property MUST match the lowercase version of the + class name, eg: when using the ``OpenVpn`` backend, the system will look + into ``config['openvpn']`` +- it SHOULD focus on the server capabilities of the VPN software being + used ``OPENWISP_CONTROLLER_DEFAULT_BACKEND`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------------------------------------+ -| **type**: | ``str`` | -+--------------+----------------------------------------+ -| **default**: | ``OPENWISP_CONTROLLER_BACKENDS[0][0]`` | -+--------------+----------------------------------------+ +============ ====================================== +**type**: ``str`` +**default**: ``OPENWISP_CONTROLLER_BACKENDS[0][0]`` +============ ====================================== -The preferred backend that will be used as initial value when adding new ``Config`` or -``Template`` objects in the admin. +The preferred backend that will be used as initial value when adding new +``Config`` or ``Template`` objects in the admin. -This setting defaults to the raw value of the first item in the ``OPENWISP_CONTROLLER_BACKENDS`` setting, -which is ``netjsonconfig.OpenWrt``. +This setting defaults to the raw value of the first item in the +``OPENWISP_CONTROLLER_BACKENDS`` setting, which is +``netjsonconfig.OpenWrt``. Setting it to ``None`` will force the user to choose explicitly. ``OPENWISP_CONTROLLER_DEFAULT_VPN_BACKEND`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+--------------------------------------------+ -| **type**: | ``str`` | -+--------------+--------------------------------------------+ -| **default**: | ``OPENWISP_CONTROLLER_VPN_BACKENDS[0][0]`` | -+--------------+--------------------------------------------+ +============ ========================================== +**type**: ``str`` +**default**: ``OPENWISP_CONTROLLER_VPN_BACKENDS[0][0]`` +============ ========================================== -The preferred backend that will be used as initial value when adding new ``Vpn`` objects in the admin. +The preferred backend that will be used as initial value when adding new +``Vpn`` objects in the admin. -This setting defaults to the raw value of the first item in the ``OPENWISP_CONTROLLER_VPN_BACKENDS`` setting, -which is ``openwisp_controller.vpn_backends.OpenVpn``. +This setting defaults to the raw value of the first item in the +``OPENWISP_CONTROLLER_VPN_BACKENDS`` setting, which is +``openwisp_controller.vpn_backends.OpenVpn``. Setting it to ``None`` will force the user to choose explicitly. ``OPENWISP_CONTROLLER_REGISTRATION_ENABLED`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== Whether devices can automatically register through the controller or not. This feature is enabled by default. -Autoregistration must be supported on the devices in order to work, see `openwisp-config automatic -registration `_ for more information. +Autoregistration must be supported on the devices in order to work, see +`openwisp-config automatic registration +`_ for +more information. ``OPENWISP_CONTROLLER_CONSISTENT_REGISTRATION`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -Whether devices that are already registered are recognized when reflashed or reset, hence keeping -the existing configuration without creating a new one. +Whether devices that are already registered are recognized when reflashed +or reset, hence keeping the existing configuration without creating a new +one. This feature is enabled by default. -Autoregistration must be enabled also on the devices in order to work, see `openwisp-config -consistent key generation `_ +Autoregistration must be enabled also on the devices in order to work, see +`openwisp-config consistent key generation +`_ for more information. ``OPENWISP_CONTROLLER_REGISTRATION_SELF_CREATION`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -Whether devices that are not already present in the system are allowed to register or not. +Whether devices that are not already present in the system are allowed to +register or not. -Turn this off if you still want to use auto-registration to avoid having to -manually set the device UUID and key in its configuration file but also want -to avoid indiscriminate registration of new devices without explicit permission. +Turn this off if you still want to use auto-registration to avoid having +to manually set the device UUID and key in its configuration file but also +want to avoid indiscriminate registration of new devices without explicit +permission. ``OPENWISP_CONTROLLER_CONTEXT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------+ -| **type**: | ``dict`` | -+--------------+------------------+ -| **default**: | ``{}`` | -+--------------+------------------+ +============ ======== +**type**: ``dict`` +**default**: ``{}`` +============ ======== -Additional context that is passed to the default context of each device object. +Additional context that is passed to the default context of each device +object. -``OPENWISP_CONTROLLER_CONTEXT`` can be used to define system-wide configuration variables. +``OPENWISP_CONTROLLER_CONTEXT`` can be used to define system-wide +configuration variables. -For more information regarding how to use configuration variables in OpenWISP, -see `How to use configuration variables <#how-to-use-configuration-variables>`_. +For more information regarding how to use configuration variables in +OpenWISP, see `How to use configuration variables +<#how-to-use-configuration-variables>`_. -For technical information about how variables are handled in the lower levels -of OpenWISP, see `netjsonconfig context: configuration variables +For technical information about how variables are handled in the lower +levels of OpenWISP, see `netjsonconfig context: configuration variables `_. ``OPENWISP_CONTROLLER_DEFAULT_AUTO_CERT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+---------------------------+ -| **type**: | ``bool`` | -+--------------+---------------------------+ -| **default**: | ``True`` | -+--------------+---------------------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== The default value of the ``auto_cert`` field for new ``Template`` objects. The ``auto_cert`` field is valid only for templates which have ``type`` -set to ``VPN`` and indicates whether configuration regarding the VPN tunnel is -provisioned automatically to each device using the template, eg: - -- when using OpenVPN, new `x509 `_ certificates - will be generated automatically using the same CA assigned to the related VPN object -- when using WireGuard, new pair of private and public keys - (using `Curve25519 `_) will be generated, as well as +set to ``VPN`` and indicates whether configuration regarding the VPN +tunnel is provisioned automatically to each device using the template, eg: + +- when using OpenVPN, new `x509 `_ + certificates will be generated automatically using the same CA assigned + to the related VPN object +- when using WireGuard, new pair of private and public keys (using + `Curve25519 `_) will be generated, as well as an IP address of the subnet assigned to the related VPN object -- when using `VXLAN `_ tunnels over Wireguad, - in addition to the configuration generated for WireGuard, a new VID will be generated - automatically for each device if the configuration option "auto VNI" is turned on in - the VPN object +- when using `VXLAN `_ tunnels over + Wireguad, in addition to the configuration generated for WireGuard, a + new VID will be generated automatically for each device if the + configuration option "auto VNI" is turned on in the VPN object All these auto generated configuration options will be available as template variables. -The objects that are automatically created will also be removed when they are not -needed anymore (eg: when the VPN template is removed from a configuration object). +The objects that are automatically created will also be removed when they +are not needed anymore (eg: when the VPN template is removed from a +configuration object). ``OPENWISP_CONTROLLER_CERT_PATH`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+---------------------------+ -| **type**: | ``str`` | -+--------------+---------------------------+ -| **default**: | ``/etc/x509`` | -+--------------+---------------------------+ +============ ============= +**type**: ``str`` +**default**: ``/etc/x509`` +============ ============= The filesystem path where x509 certificate will be installed when -downloaded on routers when ``auto_cert`` is being used (enabled by default). +downloaded on routers when ``auto_cert`` is being used (enabled by +default). ``OPENWISP_CONTROLLER_COMMON_NAME_FORMAT`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------+ -| **type**: | ``str`` | -+--------------+------------------------------+ -| **default**: | ``{mac_address}-{name}`` | -+--------------+------------------------------+ - -Defines the format of the ``common_name`` attribute of VPN client certificates -that are automatically created when using VPN templates which have ``auto_cert`` -set to ``True``. A unique slug generated using `shortuuid `_ -is appended to the common name to introduce uniqueness. Therefore, resulting -common names will have ``{OPENWISP_CONTROLLER_COMMON_NAME_FORMAT}-{unique-slug}`` +============ ======================== +**type**: ``str`` +**default**: ``{mac_address}-{name}`` +============ ======================== + +Defines the format of the ``common_name`` attribute of VPN client +certificates that are automatically created when using VPN templates which +have ``auto_cert`` set to ``True``. A unique slug generated using +`shortuuid `_ is appended to +the common name to introduce uniqueness. Therefore, resulting common names +will have ``{OPENWISP_CONTROLLER_COMMON_NAME_FORMAT}-{unique-slug}`` format. -**Note:** If the ``name`` and ``mac address`` of the device are equal, -the ``name`` of the device will be omitted from the common name to avoid redundancy. +**Note:** If the ``name`` and ``mac address`` of the device are equal, the +``name`` of the device will be omitted from the common name to avoid +redundancy. ``OPENWISP_CONTROLLER_MANAGEMENT_IP_DEVICE_LIST`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------+ -| **type**: | ``bool`` | -+--------------+------------------------------+ -| **default**: | ``True`` | -+--------------+------------------------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -In the device list page, the column ``IP`` will show the ``management_ip`` if -available, defaulting to ``last_ip`` otherwise. +In the device list page, the column ``IP`` will show the ``management_ip`` +if available, defaulting to ``last_ip`` otherwise. If this setting is set to ``False`` the ``management_ip`` won't be shown -in the device list page even if present, it will be shown only in the device -detail page. +in the device list page even if present, it will be shown only in the +device detail page. You may set this to ``False`` if for some reason the majority of your user doesn't care about the management ip address. @@ -3017,359 +3138,363 @@ doesn't care about the management ip address. ``OPENWISP_CONTROLLER_CONFIG_BACKEND_FIELD_SHOWN`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------+ -| **type**: | ``bool`` | -+--------------+------------------------------+ -| **default**: | ``True`` | -+--------------+------------------------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -This setting toggles the ``backend`` fields in add/edit pages in Device and Template configuration, -as well as the ``backend`` field/filter in Device list and Template list. +This setting toggles the ``backend`` fields in add/edit pages in Device +and Template configuration, as well as the ``backend`` field/filter in +Device list and Template list. -If this setting is set to ``False`` these items will be removed from the UI. +If this setting is set to ``False`` these items will be removed from the +UI. -Note: This setting affects only the configuration backend and NOT the VPN backend. +Note: This setting affects only the configuration backend and NOT the VPN +backend. ``OPENWISP_CONTROLLER_DEVICE_NAME_UNIQUE`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -This setting conditionally enforces unique Device names in an Organization. -The query to enforce this is case-insensitive. +This setting conditionally enforces unique Device names in an +Organization. The query to enforce this is case-insensitive. -Note: For this constraint to be optional, it is enforced on an application level and not on database. +Note: For this constraint to be optional, it is enforced on an application +level and not on database. ``OPENWISP_CONTROLLER_HARDWARE_ID_ENABLED`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``False`` | -+--------------+-------------+ +============ ========= +**type**: ``bool`` +**default**: ``False`` +============ ========= -The field ``hardware_id`` can be used to store a unique hardware id, for example a serial number. +The field ``hardware_id`` can be used to store a unique hardware id, for +example a serial number. -If this setting is set to ``True`` then this field will be shown first in the device list page -and in the add/edit device page. +If this setting is set to ``True`` then this field will be shown first in +the device list page and in the add/edit device page. This feature is disabled by default. ``OPENWISP_CONTROLLER_HARDWARE_ID_OPTIONS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+--------------------------------------------------------------+ -| **type**: | ``dict`` | -+--------------+--------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | { | -| | 'blank': not OPENWISP_CONTROLLER_HARDWARE_ID_ENABLED, | -| | 'null': True, | -| | 'max_length': 32, | -| | 'unique': True, | -| | 'verbose_name': _('Serial number'), | -| | 'help_text': _('Serial number of this device') | -| | } | -+--------------+--------------------------------------------------------------+ +============ ============================================================= +**type**: ``dict`` +**default**: .. code-block:: python + + { + "blank": not OPENWISP_CONTROLLER_HARDWARE_ID_ENABLED, + "null": True, + "max_length": 32, + "unique": True, + "verbose_name": _("Serial number"), + "help_text": _("Serial number of this device"), + } +============ ============================================================= Options for the model field ``hardware_id``. -* ``blank``: wether the field is allowed to be blank -* ``null``: wether an empty value will be stored as ``NULL`` in the database -* ``max_length``: maximum length of the field -* ``unique``: wether the value of the field must be unique -* ``verbose_name``: text for the human readable label of the field -* ``help_text``: help text to be displayed with the field +- ``blank``: wether the field is allowed to be blank +- ``null``: wether an empty value will be stored as ``NULL`` in the + database +- ``max_length``: maximum length of the field +- ``unique``: wether the value of the field must be unique +- ``verbose_name``: text for the human readable label of the field +- ``help_text``: help text to be displayed with the field ``OPENWISP_CONTROLLER_HARDWARE_ID_AS_NAME`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== When the hardware ID feature is enabled, devices will be referenced with their hardware ID instead of their name. -If you still want to reference devices by their name, set this to ``False``. +If you still want to reference devices by their name, set this to +``False``. ``OPENWISP_CONTROLLER_DEVICE_VERBOSE_NAME`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------------------------+ -| **type**: | ``tuple`` | -+--------------+----------------------------+ -| **default**: | ``('Device', 'Devices')`` | -+--------------+----------------------------+ +============ ========================= +**type**: ``tuple`` +**default**: ``('Device', 'Devices')`` +============ ========================= -Defines the ``verbose_name`` attribute of the ``Device`` model, which is displayed in the -admin site. The first and second element of the tuple represent the singular and plural forms. +Defines the ``verbose_name`` attribute of the ``Device`` model, which is +displayed in the admin site. The first and second element of the tuple +represent the singular and plural forms. -For example, if we want to change the verbose name to "Hotspot", we could write: +For example, if we want to change the verbose name to "Hotspot", we could +write: .. code-block:: python - OPENWISP_CONTROLLER_DEVICE_VERBOSE_NAME = ('Hotspot', 'Hotspots') + OPENWISP_CONTROLLER_DEVICE_VERBOSE_NAME = ("Hotspot", "Hotspots") ``OPENWISP_CONTROLLER_HIDE_AUTOMATICALLY_GENERATED_SUBNETS_AND_IPS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------+ -| **type**: | ``bool`` | -+--------------+-----------+ -| **default**: | ``False`` | -+--------------+-----------+ +============ ========= +**type**: ``bool`` +**default**: ``False`` +============ ========= -Setting this to ``True`` will hide subnets and IPs generated using `subnet division rules <#subnet-division-app>`_ -from being displayed on the changelist view of Subnet and IP admin. +Setting this to ``True`` will hide subnets and IPs generated using `subnet +division rules <#subnet-division-app>`_ from being displayed on the +changelist view of Subnet and IP admin. ``OPENWISP_CONTROLLER_SUBNET_DIVISION_TYPES`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+---------------------------------------------------------------------------------------------------------+ -| **type**: | ``tuple`` | -+--------------+---------------------------------------------------------------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | ( | -| | ('openwisp_controller.subnet_division.rule_types.device.DeviceSubnetDivisionRuleType', 'Device'), | -| | ('openwisp_controller.subnet_division.rule_types.vpn.VpnSubnetDivisionRuleType', 'VPN'), | -| | ) | -| | | -+--------------+---------------------------------------------------------------------------------------------------------+ - -`Available types for Subject Division Rule <#device-subnet-division-rule>`_ objects. -For more information on how to write your own types, read -`"Custom Subnet Division Rule Types" section of this documentation <#custom-subnet-division-rule-types>`_ +============ ================================================================================================= +**type**: ``tuple`` +**default**: .. code-block:: python + + ( + ( + "openwisp_controller.subnet_division.rule_types.device.DeviceSubnetDivisionRuleType", + "Device", + ), + ( + "openwisp_controller.subnet_division.rule_types.vpn.VpnSubnetDivisionRuleType", + "VPN", + ), + ) +============ ================================================================================================= + +`Available types for Subject Division Rule +<#device-subnet-division-rule>`_ objects. For more information on how to +write your own types, read `"Custom Subnet Division Rule Types" section of +this documentation <#custom-subnet-division-rule-types>`_ ``OPENWISP_CONTROLLER_API`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------+ -| **type**: | ``bool`` | -+--------------+-----------+ -| **default**: | ``True`` | -+--------------+-----------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -Indicates whether the API for Openwisp Controller is enabled or not. -To disable the API by default add `OPENWISP_CONTROLLER_API = False` in `settings.py` file. +Indicates whether the API for Openwisp Controller is enabled or not. To +disable the API by default add `OPENWISP_CONTROLLER_API = False` in +`settings.py` file. ``OPENWISP_CONTROLLER_API_HOST`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------+ -| **type**: | ``str`` | -+--------------+-----------+ -| **default**: | ``None`` | -+--------------+-----------+ +============ ======== +**type**: ``str`` +**default**: ``None`` +============ ======== -Allows to specify backend URL for API requests, if the frontend is hosted separately. +Allows to specify backend URL for API requests, if the frontend is hosted +separately. ``OPENWISP_CONTROLLER_USER_COMMANDS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------+ -| **type**: | ``list`` | -+--------------+----------+ -| **default**: | ``[]`` | -+--------------+----------+ +============ ======== +**type**: ``list`` +**default**: ``[]`` +============ ======== Allows to specify a ``list`` of tuples for adding commands as described in -`'How to define custom commands" <#how-to-define-new-options-in-the-commands-menu>`_ section. +`'How to define custom commands" +<#how-to-define-new-options-in-the-commands-menu>`_ section. ``OPENWISP_CONTROLLER_ORGANIZATION_ENABLED_COMMANDS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------------------------+ -| **type**: | ``dict`` | -+--------------+------------------------------------------------+ -| **default**: | .. code-block:: python | -| | | -| | { | -| | # By default all commands are allowed | -| | '__all__': '*', | -| | } | -| | | -+--------------+------------------------------------------------+ - -This setting controls the command types that are enabled on the system -By default, all command types are enabled to all the organizations, -but it's possible to disable a specific command for a specific organization -as shown in the following example: +============ ============================================= +**type**: ``dict`` +**default**: .. code-block:: python + + { + # By default all commands are allowed + "__all__": "*", + } +============ ============================================= + +This setting controls the command types that are enabled on the system By +default, all command types are enabled to all the organizations, but it's +possible to disable a specific command for a specific organization as +shown in the following example: .. code-block:: python OPENWISP_CONTROLLER_ORGANIZATION_ENABLED_COMMANDS = { - '__all__': '*', + "__all__": "*", # Organization UUID: # Tuple of enabled commands - '7448a190-6e65-42bf-b8ea-bb6603e593a5': ('reboot', 'change_password'), + "7448a190-6e65-42bf-b8ea-bb6603e593a5": ("reboot", "change_password"), } -In the example above, the organization with UUID ``7448a190-6e65-42bf-b8ea-bb6603e593a5`` -will allow to send only commands of type ``reboot`` and ``change_password``, -while all the other organizations will have all command types enabled. +In the example above, the organization with UUID +``7448a190-6e65-42bf-b8ea-bb6603e593a5`` will allow to send only commands +of type ``reboot`` and ``change_password``, while all the other +organizations will have all command types enabled. ``OPENWISP_CONTROLLER_DEVICE_GROUP_SCHEMA`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+------------------------------------------+ -| **type**: | ``dict`` | -+--------------+------------------------------------------+ -| **default**: | ``{'type': 'object', 'properties': {}}`` | -+--------------+------------------------------------------+ +============ ======================================== +**type**: ``dict`` +**default**: ``{'type': 'object', 'properties': {}}`` +============ ======================================== -Allows specifying JSONSchema used for validating meta-data of `Device Group <#device-groups>`__. +Allows specifying JSONSchema used for validating meta-data of `Device +Group <#device-groups>`__. ``OPENWISP_CONTROLLER_SHARED_MANAGEMENT_IP_ADDRESS_SPACE`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------+ -| **type**: | ``bool`` | -+--------------+----------+ -| **default**: | ``True`` | -+--------------+----------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== By default, the system assumes that the address space of the management tunnel is shared among all the organizations using the system, that is, the system assumes there's only one management VPN, tunnel or other networking technology to reach the devices it controls. -When set to ``True``, any device belonging to any -organization will never have the same ``management_ip`` as another device, -the latest device declaring the management IP will take the IP and any -other device who declared the same IP in the past will have the field -reset to empty state to avoid potential conflicts. +When set to ``True``, any device belonging to any organization will never +have the same ``management_ip`` as another device, the latest device +declaring the management IP will take the IP and any other device who +declared the same IP in the past will have the field reset to empty state +to avoid potential conflicts. Set this to ``False`` if every organization has its dedicated management -tunnel with a dedicated address space that is reachable by the OpenWISP server. +tunnel with a dedicated address space that is reachable by the OpenWISP +server. ``OPENWISP_CONTROLLER_MANAGEMENT_IP_ONLY`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-------------+ -| **type**: | ``bool`` | -+--------------+-------------+ -| **default**: | ``True`` | -+--------------+-------------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== By default, only the management IP will be used to establish connection with the devices. -If the devices are connecting to your OpenWISP instance using a shared layer2 -network, hence the OpenWSP server can reach the devices using the ``last_ip`` -field, you can set this to ``False``. +If the devices are connecting to your OpenWISP instance using a shared +layer2 network, hence the OpenWSP server can reach the devices using the +``last_ip`` field, you can set this to ``False``. ``OPENWISP_CONTROLLER_DSA_OS_MAPPING`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------+ -| **type**: | ``dict`` | -+--------------+----------+ -| **default**: | ``{}`` | -+--------------+----------+ +============ ======== +**type**: ``dict`` +**default**: ``{}`` +============ ======== -OpenWISP Controller can figure out whether it should use the new OpenWrt syntax -for DSA interfaces (Distributed Switch Architecture) introduced in OpenWrt 21 by -reading the ``os`` field of the ``Device`` object. However, if the firmware you -are using has a custom firmware identifier, the system will not be able to figure -out whether it should use the new syntax and it will default to -`OPENWISP_CONTROLLER_DSA_DEFAULT_FALLBACK <#openwisp_controller_dsa_default_fallback>`_. +OpenWISP Controller can figure out whether it should use the new OpenWrt +syntax for DSA interfaces (Distributed Switch Architecture) introduced in +OpenWrt 21 by reading the ``os`` field of the ``Device`` object. However, +if the firmware you are using has a custom firmware identifier, the system +will not be able to figure out whether it should use the new syntax and it +will default to `OPENWISP_CONTROLLER_DSA_DEFAULT_FALLBACK +<#openwisp_controller_dsa_default_fallback>`_. If you want to make sure the system can parse your custom firmware identifier properly, you can follow the example below. For the sake of the example, the OS identifier ``MyCustomFirmware 2.0`` -corresponds to ``OpenWrt 19.07``, while ``MyCustomFirmware 2.1`` corresponds to -``OpenWrt 21.02``. Configuring this setting as indicated below will allow -OpenWISP to supply the right syntax automatically. +corresponds to ``OpenWrt 19.07``, while ``MyCustomFirmware 2.1`` +corresponds to ``OpenWrt 21.02``. Configuring this setting as indicated +below will allow OpenWISP to supply the right syntax automatically. Example: .. code-block:: python OPENWISP_CONTROLLER_DSA_OS_MAPPING = { - 'netjsonconfig.OpenWrt': { + "netjsonconfig.OpenWrt": { # OpenWrt >=21.02 configuration syntax will be used for # these OS identifiers. - '>=21.02': [r'MyCustomFirmware 2.1(.*)'], + ">=21.02": [r"MyCustomFirmware 2.1(.*)"], # OpenWrt <=21.02 configuration syntax will be used for # these OS identifiers. - '<21.02': [r'MyCustomFirmware 2.0(.*)'] + "<21.02": [r"MyCustomFirmware 2.0(.*)"], } } -**Note**: The OS identifier should be a regular expression as shown in above example. +**Note**: The OS identifier should be a regular expression as shown in +above example. ``OPENWISP_CONTROLLER_DSA_DEFAULT_FALLBACK`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+----------+ -| **type**: | ``bool`` | -+--------------+----------+ -| **default**: | ``True`` | -+--------------+----------+ +============ ======== +**type**: ``bool`` +**default**: ``True`` +============ ======== -The value of this setting decides whether to use DSA syntax -(OpenWrt >=21 configuration syntax) if openwisp-controller fails -to make that decision automatically. +The value of this setting decides whether to use DSA syntax (OpenWrt >=21 +configuration syntax) if openwisp-controller fails to make that decision +automatically. ``OPENWISP_CONTROLLER_GROUP_PIE_CHART`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------+ -| **type**: | ``bool`` | -+--------------+-----------+ -| **default**: | ``False`` | -+--------------+-----------+ +============ ========= +**type**: ``bool`` +**default**: ``False`` +============ ========= Allows to show a pie chart like the one in the screenshot. .. image:: https://raw.githubusercontent.com/openwisp/openwisp-controller/docs/docs/devicegroups-piechart.png - :alt: device groups piechart + :alt: device groups piechart -Active groups are groups which have at least one device in them, -while emtpy groups do not have any device assigned. +Active groups are groups which have at least one device in them, while +emtpy groups do not have any device assigned. ``OPENWISP_CONTROLLER_API_TASK_RETRY_OPTIONS`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------------+-----------+ -| **type**: | ``dict`` | -+--------------+-----------+ -| **default**: | see below | -+--------------+-----------+ +============ ========= +**type**: ``dict`` +**default**: see below +============ ========= .. code-block:: python # default value of OPENWISP_CONTROLLER_API_TASK_RETRY_OPTIONS: dict( - max_retries=5, # total number of retries - retry_backoff=True, # exponential backoff - retry_backoff_max=600, # 10 minutes - retry_jitter=True, # randomness into exponential backoff + max_retries=5, # total number of retries + retry_backoff=True, # exponential backoff + retry_backoff_max=600, # 10 minutes + retry_jitter=True, # randomness into exponential backoff ) +This setting is utilized by background API tasks executed by `ZeroTier VPN +servers and ZeroTier VPN clients <#how-to-setup-zerotier-tunnels>`_ to +handle recoverable HTTP status codes such as 429, 500, 502, 503, and 504. +These tasks are retried with a maximum of 5 attempts with an exponential +backoff and jitter, with a maximum delay of 10 minutes. -This setting is utilized by background API tasks executed -by `ZeroTier VPN servers and ZeroTier VPN clients <#how-to-setup-zerotier-tunnels>`_ to handle recoverable -HTTP status codes such as 429, 500, 502, 503, and 504. These tasks are retried with a maximum -of 5 attempts with an exponential backoff and jitter, with a maximum delay of 10 minutes. - -This feature ensures that ZeroTier Service API calls -are resilient to recoverable failures, improving the reliability of the system. - -For more information on these settings, you can refer to the `the celery documentation regarding automatic retries -for known errors. `_ +This feature ensures that ZeroTier Service API calls are resilient to +recoverable failures, improving the reliability of the system. +For more information on these settings, you can refer to the `the celery +documentation regarding automatic retries for known errors. +`_ Signals ------- @@ -3382,39 +3507,41 @@ Signals **Arguments**: - ``instance``: instance of ``Config`` which got its ``config`` modified -- ``previous_status``: indicates the status of the config object before the - signal was emitted -- ``action``: action which emitted the signal, can be any of the list below: - - ``config_changed``: the configuration of the config object was changed - - ``related_template_changed``: the configuration of a related template was changed - - ``m2m_templates_changed``: the assigned templates were changed - (either templates were added, removed or their order was changed) - -This signal is emitted every time the configuration of a device is modified. - -It does not matter if ``Config.status`` is already modified, this signal will -be emitted anyway because it signals that the device configuration has changed. +- ``previous_status``: indicates the status of the config object before + the signal was emitted +- ``action``: action which emitted the signal, can be any of the list + below: - ``config_changed``: the configuration of the config object was + changed - ``related_template_changed``: the configuration of a related + template was changed - ``m2m_templates_changed``: the assigned templates + were changed (either templates were added, removed or their order was + changed) + +This signal is emitted every time the configuration of a device is +modified. + +It does not matter if ``Config.status`` is already modified, this signal +will be emitted anyway because it signals that the device configuration +has changed. This signal is used to trigger the update of the configuration on devices, when the push feature is enabled (requires Device credentials). -The signal is also emitted when one of the templates used by the device -is modified or if the templates assigned to the device are changed. +The signal is also emitted when one of the templates used by the device is +modified or if the templates assigned to the device are changed. Special cases in which ``config_modified`` is not emitted -######################################################### ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ This signal is not emitted when the device is created for the first time. It is also not emitted when templates assigned to a config object are -cleared (``post_clear`` m2m signal), this is necessary because -`sortedm2m `_, the package -we use to implement ordered templates, uses the clear action to -reorder templates (m2m relationships are first cleared and then added back), -therefore we ignore ``post_clear`` to avoid emitting signals twice -(one for the clear action and one for the add action). -Please keep this in mind if you plan on using the clear method -of the m2m manager. +cleared (``post_clear`` m2m signal), this is necessary because `sortedm2m +`_, the package we use to +implement ordered templates, uses the clear action to reorder templates +(m2m relationships are first cleared and then added back), therefore we +ignore ``post_clear`` to avoid emitting signals twice (one for the clear +action and one for the add action). Please keep this in mind if you plan +on using the clear method of the m2m manager. ``config_status_changed`` ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3425,12 +3552,13 @@ of the m2m manager. - ``instance``: instance of ``Config`` which got its ``status`` changed -This signal is emitted only when the configuration status of a device has changed. +This signal is emitted only when the configuration status of a device has +changed. The signal is emitted also when the m2m template relationships of a config object are changed, but only on ``post_add`` or ``post_remove`` actions, -``post_clear`` is ignored for the same reason explained -in the previous section. +``post_clear`` is ignored for the same reason explained in the previous +section. ``config_backend_changed`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3455,10 +3583,11 @@ It is not emitted when the device or config is created. checksum has been requested - ``request``: the HTTP request object -This signal is emitted when a device requests a checksum via the controller views. +This signal is emitted when a device requests a checksum via the +controller views. -The signal is emitted just before a successful response is returned, -it is not sent if the response was not successful. +The signal is emitted just before a successful response is returned, it is +not sent if the response was not successful. ``config_download_requested`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3467,15 +3596,15 @@ it is not sent if the response was not successful. **Arguments**: -- ``instance``: instance of ``Device`` for which its configuration has been - requested for download +- ``instance``: instance of ``Device`` for which its configuration has + been requested for download - ``request``: the HTTP request object -This signal is emitted when a device requests to download its configuration -via the controller views. +This signal is emitted when a device requests to download its +configuration via the controller views. -The signal is emitted just before a successful response is returned, -it is not sent if the response was not successful. +The signal is emitted just before a successful response is returned, it is +not sent if the response was not successful. ``is_working_changed`` ~~~~~~~~~~~~~~~~~~~~~~ @@ -3488,8 +3617,10 @@ it is not sent if the response was not successful. - ``is_working``: value of ``DeviceConnection.is_working`` - ``old_is_working``: previous value of ``DeviceConnection.is_working``, either ``None`` (for new connections), ``True`` or ``False`` -- ``failure_reason``: error message explaining reason for failure in establishing connection -- ``old_failure_reason``: previous value of ``DeviceConnection.failure_reason`` +- ``failure_reason``: error message explaining reason for failure in + establishing connection +- ``old_failure_reason``: previous value of + ``DeviceConnection.failure_reason`` This signal is emitted every time ``DeviceConnection.is_working`` changes. @@ -3518,12 +3649,12 @@ It is not triggered when the device is created for the first time. **Arguments**: - ``instance``: instance of ``Device`` which got registered. -- ``is_new``: boolean, will be ``True`` when the device is new, - ``False`` when the device already exists - (eg: a device which gets a factory reset will register again) +- ``is_new``: boolean, will be ``True`` when the device is new, ``False`` + when the device already exists (eg: a device which gets a factory reset + will register again) -This signal is emitted when a device registers automatically through the controller -HTTP API. +This signal is emitted when a device registers automatically through the +controller HTTP API. ``device_name_changed`` ~~~~~~~~~~~~~~~~~~~~~~~ @@ -3556,14 +3687,14 @@ It is not emitted when the device is created. ``group_templates_changed`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - **Path**: ``openwisp_controller.config.signals.group_templates_changed`` **Arguments**: - ``instance``: instance of ``DeviceGroup``. - ``templates``: list of ``Template`` objects assigned to ``DeviceGroup`` -- ``old_templates``: list of ``Template`` objects assigned earlier to ``DeviceGroup`` +- ``old_templates``: list of ``Template`` objects assigned earlier to + ``DeviceGroup`` The signal is emitted when the device group templates changes. @@ -3572,7 +3703,8 @@ It is not emitted when the device is created. ``subnet_provisioned`` ~~~~~~~~~~~~~~~~~~~~~~ -**Path**: ``openwisp_controller.subnet_division.signals.subnet_provisioned`` +**Path**: +``openwisp_controller.subnet_division.signals.subnet_provisioned`` **Arguments**: @@ -3581,8 +3713,8 @@ It is not emitted when the device is created. ``None`` if nothing is provisioned The signal is emitted when subnets and IP addresses have been provisioned -for a ``VpnClient`` for a VPN server with a subnet with -`subnet division rule <#subnet-division-app>`_. +for a ``VpnClient`` for a VPN server with a subnet with `subnet division +rule <#subnet-division-app>`_. ``vpn_server_modified`` ~~~~~~~~~~~~~~~~~~~~~~~ @@ -3606,54 +3738,60 @@ The signal is emitted when the VPN server is modified. The signal is emitted when the peers of VPN server gets changed. -It is only emitted for ``Vpn`` object with **WireGuard** or -**VXLAN over WireGuard** backend. +It is only emitted for ``Vpn`` object with **WireGuard** or **VXLAN over +WireGuard** backend. Extending openwisp-controller ----------------------------- -One of the core values of the OpenWISP project is -`Software Reusability `_, -for this reason *openwisp-controller* provides a set of base classes -which can be imported, extended and reused to create derivative apps. +One of the core values of the OpenWISP project is `Software Reusability +`_, +for this reason *openwisp-controller* provides a set of base classes which +can be imported, extended and reused to create derivative apps. -In order to implement your custom version of *openwisp-controller*, -you need to perform the steps described in this section. +In order to implement your custom version of *openwisp-controller*, you +need to perform the steps described in this section. -When in doubt, the code in the -`test project `_ -will serve you as source of truth: just replicate and adapt that code -to get a basic derivative of *openwisp-controller* working. +When in doubt, the code in the `test project +`_ +will serve you as source of truth: just replicate and adapt that code to +get a basic derivative of *openwisp-controller* working. -If you want to add new users fields, please follow the `tutorial to extend the -openwisp-users `_. -As an example, we have extended *openwisp-users* to *sample_users* app and +If you want to add new users fields, please follow the `tutorial to extend +the openwisp-users +`_. As +an example, we have extended *openwisp-users* to *sample_users* app and added a field ``social_security_number`` in the `sample_users/models.py `_. -**Premise**: if you plan on using a customized version of this module, -we suggest to start with it since the beginning, because migrating your data +**Premise**: if you plan on using a customized version of this module, we +suggest to start with it since the beginning, because migrating your data from the default module to your extended version may be time consuming. 1. Initialize your project & custom apps ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Firstly, to get started you need to create a django project:: +Firstly, to get started you need to create a django project: + +:: django-admin startproject mycontroller -Now, you need to do is to create some new django apps which will -contain your custom version of *openwisp-controller*. +Now, you need to do is to create some new django apps which will contain +your custom version of *openwisp-controller*. + +A django project is a collection of django apps. There are 4 django apps +in the openwisp_controller project, namely config, pki, connection & geo. +You'll need to create 4 apps in your project for each app in +openwisp_controller. -A django project is a collection of django apps. There are 4 django apps in the -openwisp_controller project, namely config, pki, connection & geo. -You'll need to create 4 apps in your project for each app in openwisp_controller. +A django app is nothing more than a `python package +`_ (a directory +of python scripts), in the following examples we'll call these django app +``sample_config``, ``sample_pki``, ``sample_connection``, ``sample_geo`` & +``sample_subnet_division``. but you can name it how you want: -A django app is nothing more than a -`python package `_ -(a directory of python scripts), in the following examples we'll call these django app -``sample_config``, ``sample_pki``, ``sample_connection``, ``sample_geo`` -& ``sample_subnet_division``. but you can name it how you want:: +:: django-admin startapp sample_config django-admin startapp sample_pki @@ -3661,17 +3799,21 @@ A django app is nothing more than a django-admin startapp sample_geo django-admin startapp sample_subnet_division -Keep in mind that the command mentioned above must be called from a directory -which is available in your `PYTHON_PATH `_ -so that you can then import the result into your project. +Keep in mind that the command mentioned above must be called from a +directory which is available in your `PYTHON_PATH +`_ so that +you can then import the result into your project. -For more information about how to work with django projects and django apps, -please refer to the `django documentation `_. +For more information about how to work with django projects and django +apps, please refer to the `django documentation +`_. 2. Install ``openwisp-controller`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Install (and add to the requirement of your project) openwisp-controller:: +Install (and add to the requirement of your project) openwisp-controller: + +:: pip install openwisp-controller @@ -3691,42 +3833,43 @@ Now you need to add ``mycontroller.sample_config``, # Remember: Order in INSTALLED_APPS is important. INSTALLED_APPS = [ # other django installed apps - 'openwisp_utils.admin_theme', - 'admin_auto_filters', + "openwisp_utils.admin_theme", + "admin_auto_filters", # all-auth - 'django.contrib.sites', - 'allauth', - 'allauth.account', - 'allauth.socialaccount', + "django.contrib.sites", + "allauth", + "allauth.account", + "allauth.socialaccount", # openwisp2 module # 'openwisp_controller.config', <-- comment out or delete this line # 'openwisp_controller.pki', <-- comment out or delete this line # 'openwisp_controller.geo', <-- comment out or delete this line # 'openwisp_controller.connection', <-- comment out or delete this line # 'openwisp_controller.subnet_division', <-- comment out or delete this line - 'mycontroller.sample_config', - 'mycontroller.sample_pki', - 'mycontroller.sample_geo', - 'mycontroller.sample_connection', - 'mycontroller.sample_subnet_division', - 'openwisp_users', + "mycontroller.sample_config", + "mycontroller.sample_pki", + "mycontroller.sample_geo", + "mycontroller.sample_connection", + "mycontroller.sample_subnet_division", + "openwisp_users", # admin - 'django.contrib.admin', + "django.contrib.admin", # other dependencies - 'sortedm2m', - 'reversion', - 'leaflet', + "sortedm2m", + "reversion", + "leaflet", # rest framework - 'rest_framework', - 'rest_framework_gis', + "rest_framework", + "rest_framework_gis", # channels - 'channels', + "channels", # django-import-export - 'import_export', + "import_export", ] -Substitute ``mycontroller``, ``sample_config``, ``sample_pki``, ``sample_connection``, -``sample_geo`` & ``sample_subnet_division`` with the name you chose in step 1. +Substitute ``mycontroller``, ``sample_config``, ``sample_pki``, +``sample_connection``, ``sample_geo`` & ``sample_subnet_division`` with +the name you chose in step 1. 4. Add ``EXTENDED_APPS`` ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3736,13 +3879,13 @@ Add the following to your ``settings.py``: .. code-block:: python EXTENDED_APPS = ( - 'django_x509', - 'django_loci', - 'openwisp_controller.config', - 'openwisp_controller.pki', - 'openwisp_controller.geo', - 'openwisp_controller.connection', - 'openwisp_controller.subnet_division', + "django_x509", + "django_loci", + "openwisp_controller.config", + "openwisp_controller.pki", + "openwisp_controller.geo", + "openwisp_controller.connection", + "openwisp_controller.subnet_division", ) 5. Add ``openwisp_utils.staticfiles.DependencyFinder`` @@ -3754,36 +3897,36 @@ Add ``openwisp_utils.staticfiles.DependencyFinder`` to .. code-block:: python STATICFILES_FINDERS = [ - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'openwisp_utils.staticfiles.DependencyFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "openwisp_utils.staticfiles.DependencyFinder", ] 6. Add ``openwisp_utils.loaders.DependencyLoader`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES`` -in your ``settings.py``, but ensure it comes before +Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES`` in your +``settings.py``, but ensure it comes before ``django.template.loaders.app_directories.Loader``: .. code-block:: python TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - 'django.template.loaders.filesystem.Loader', - 'openwisp_utils.loaders.DependencyLoader', - 'django.template.loaders.app_directories.Loader', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + "django.template.loaders.filesystem.Loader", + "openwisp_utils.loaders.DependencyLoader", + "django.template.loaders.app_directories.Loader", ], - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'openwisp_utils.admin_theme.context_processor.menu_items', - 'openwisp_notifications.context_processors.notification_api_settings', + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "openwisp_utils.admin_theme.context_processor.menu_items", + "openwisp_notifications.context_processors.notification_api_settings", ], }, } @@ -3797,13 +3940,14 @@ Ensure you are using one of the available geodjango backends, eg: .. code-block:: python DATABASES = { - 'default': { - 'ENGINE': 'openwisp_utils.db.backends.spatialite', - 'NAME': 'openwisp-controller.db', + "default": { + "ENGINE": "openwisp_utils.db.backends.spatialite", + "NAME": "openwisp-controller.db", } } -For more information about GeoDjango, please refer to the `geodjango documentation `_. +For more information about GeoDjango, please refer to the `geodjango +documentation `_. 6. Django Channels Setup ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3818,14 +3962,16 @@ Create ``asgi.py`` in your project folder and add following lines in it: from django.core.asgi import get_asgi_application from openwisp_controller.routing import get_routes + # You can also add your routes like this from my_app.routing import my_routes application = ProtocolTypeRouter( - { "http": get_asgi_application(), - 'websocket': AllowedHostsOriginValidator( + { + "http": get_asgi_application(), + "websocket": AllowedHostsOriginValidator( AuthMiddlewareStack(URLRouter(get_routes() + my_routes)) - ) + ), } ) @@ -3836,21 +3982,22 @@ Add the following settings to ``settings.py``: .. code-block:: python - FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' + FORM_RENDERER = "django.forms.renderers.TemplatesSetting" - ASGI_APPLICATION = 'my_project.asgi.application' + ASGI_APPLICATION = "my_project.asgi.application" CHANNEL_LAYERS = { - 'default': { - 'BACKEND': 'channels.layers.InMemoryChannelLayer' - }, + "default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}, } For more information about FORM_RENDERER setting, please refer to the -`FORM_RENDERER documentation `_. -For more information about ASGI_APPLICATION setting, please refer to the -`ASGI_APPLICATION documentation `_. +`FORM_RENDERER documentation +`_. For +more information about ASGI_APPLICATION setting, please refer to the +`ASGI_APPLICATION documentation +`_. For more information about CHANNEL_LAYERS setting, please refer to the -`CHANNEL_LAYERS documentation `_. +`CHANNEL_LAYERS documentation +`_. 6. Inherit the AppConfig class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3858,29 +4005,36 @@ For more information about CHANNEL_LAYERS setting, please refer to the Please refer to the following files in the sample app of the test project: - sample_config: - - `sample_config/__init__.py `_. - - `sample_config/apps.py `_. - + - `sample_config/__init__.py + `_. + - `sample_config/apps.py + `_. - sample_geo: - - `sample_geo/__init__.py `_. - - `sample_geo/apps.py `_. - + - `sample_geo/__init__.py + `_. + - `sample_geo/apps.py + `_. - sample_pki: - - `sample_pki/__init__.py `_. - - `sample_pki/apps.py `_. - + - `sample_pki/__init__.py + `_. + - `sample_pki/apps.py + `_. - sample_connection: - - `sample_connection/__init__.py `_. - - `sample_connection/apps.py `_. - + - `sample_connection/__init__.py + `_. + - `sample_connection/apps.py + `_. - sample_subnet_division: - - `sample_subnet_division/__init__.py `_. - - `sample_subnet_division/apps.py `_. + - `sample_subnet_division/__init__.py + `_. + - `sample_subnet_division/apps.py + `_. You have to replicate and adapt that code in your project. -For more information regarding the concept of ``AppConfig`` please refer to -the `"Applications" section in the django documentation `_. +For more information regarding the concept of ``AppConfig`` please refer +to the `"Applications" section in the django documentation +`_. 7. Create your custom models ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3888,98 +4042,131 @@ the `"Applications" section in the django documentation `_ -- `sample_geo models `_ -- `sample_pki models `_ -- `sample_connection models `_ -- `sample_subnet_division `_ +- `sample_config models + `_ +- `sample_geo models + `_ +- `sample_pki models + `_ +- `sample_connection models + `_ +- `sample_subnet_division + `_ You can add fields in a similar way in your ``models.py`` file. -**Note**: for doubts regarding how to use, extend or develop models please refer to -the `"Models" section in the django documentation `_. +**Note**: for doubts regarding how to use, extend or develop models please +refer to the `"Models" section in the django documentation +`_. 8. Add swapper configurations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Once you have created the models, add the following to your ``settings.py``: +Once you have created the models, add the following to your +``settings.py``: .. code-block:: python # Setting models for swapper module - CONFIG_DEVICE_MODEL = 'sample_config.Device' - CONFIG_DEVICEGROUP_MODEL = 'sample_config.DeviceGroup' - CONFIG_CONFIG_MODEL = 'sample_config.Config' - CONFIG_TEMPLATETAG_MODEL = 'sample_config.TemplateTag' - CONFIG_TAGGEDTEMPLATE_MODEL = 'sample_config.TaggedTemplate' - CONFIG_TEMPLATE_MODEL = 'sample_config.Template' - CONFIG_VPN_MODEL = 'sample_config.Vpn' - CONFIG_VPNCLIENT_MODEL = 'sample_config.VpnClient' - CONFIG_ORGANIZATIONCONFIGSETTINGS_MODEL = 'sample_config.OrganizationConfigSettings' - CONFIG_ORGANIZATIONLIMITS_MODEL = 'sample_config.OrganizationLimits' - DJANGO_X509_CA_MODEL = 'sample_pki.Ca' - DJANGO_X509_CERT_MODEL = 'sample_pki.Cert' - GEO_LOCATION_MODEL = 'sample_geo.Location' - GEO_FLOORPLAN_MODEL = 'sample_geo.FloorPlan' - GEO_DEVICELOCATION_MODEL = 'sample_geo.DeviceLocation' - CONNECTION_CREDENTIALS_MODEL = 'sample_connection.Credentials' - CONNECTION_DEVICECONNECTION_MODEL = 'sample_connection.DeviceConnection' - CONNECTION_COMMAND_MODEL = 'sample_connection.Command' - SUBNET_DIVISION_SUBNETDIVISIONRULE_MODEL = 'sample_subnet_division.SubnetDivisionRule' - SUBNET_DIVISION_SUBNETDIVISIONINDEX_MODEL = 'sample_subnet_division.SubnetDivisionIndex' + CONFIG_DEVICE_MODEL = "sample_config.Device" + CONFIG_DEVICEGROUP_MODEL = "sample_config.DeviceGroup" + CONFIG_CONFIG_MODEL = "sample_config.Config" + CONFIG_TEMPLATETAG_MODEL = "sample_config.TemplateTag" + CONFIG_TAGGEDTEMPLATE_MODEL = "sample_config.TaggedTemplate" + CONFIG_TEMPLATE_MODEL = "sample_config.Template" + CONFIG_VPN_MODEL = "sample_config.Vpn" + CONFIG_VPNCLIENT_MODEL = "sample_config.VpnClient" + CONFIG_ORGANIZATIONCONFIGSETTINGS_MODEL = ( + "sample_config.OrganizationConfigSettings" + ) + CONFIG_ORGANIZATIONLIMITS_MODEL = "sample_config.OrganizationLimits" + DJANGO_X509_CA_MODEL = "sample_pki.Ca" + DJANGO_X509_CERT_MODEL = "sample_pki.Cert" + GEO_LOCATION_MODEL = "sample_geo.Location" + GEO_FLOORPLAN_MODEL = "sample_geo.FloorPlan" + GEO_DEVICELOCATION_MODEL = "sample_geo.DeviceLocation" + CONNECTION_CREDENTIALS_MODEL = "sample_connection.Credentials" + CONNECTION_DEVICECONNECTION_MODEL = "sample_connection.DeviceConnection" + CONNECTION_COMMAND_MODEL = "sample_connection.Command" + SUBNET_DIVISION_SUBNETDIVISIONRULE_MODEL = ( + "sample_subnet_division.SubnetDivisionRule" + ) + SUBNET_DIVISION_SUBNETDIVISIONINDEX_MODEL = ( + "sample_subnet_division.SubnetDivisionIndex" + ) Substitute ``sample_config``, ``sample_pki``, ``sample_connection``, -``sample_geo`` & ``sample_subnet_division`` with the name you chose in step 1. +``sample_geo`` & ``sample_subnet_division`` with the name you chose in +step 1. 9. Create database migrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create database migrations:: +Create database migrations: + +:: ./manage.py makemigrations Now, to use the default ``administrator`` and ``operator`` user groups -like the used in the openwisp_controller module, you'll manually need to make a -migrations file which would look like: +like the used in the openwisp_controller module, you'll manually need to +make a migrations file which would look like: + +- `sample_config/migrations/0002_default_groups_permissions.py + `_ +- `sample_geo/migrations/0002_default_group_permissions.py + `_ +- `sample_pki/migrations/0002_default_group_permissions.py + `_ +- `sample_connection/migrations/0002_default_group_permissions.py + `_ +- `sample_subnet_division/migrations/0002_default_group_permissions.py + `_ -- `sample_config/migrations/0002_default_groups_permissions.py `_ -- `sample_geo/migrations/0002_default_group_permissions.py `_ -- `sample_pki/migrations/0002_default_group_permissions.py `_ -- `sample_connection/migrations/0002_default_group_permissions.py `_ -- `sample_subnet_division/migrations/0002_default_group_permissions.py `_ +Create database migrations: -Create database migrations:: +:: ./manage.py migrate -For more information, refer to the -`"Migrations" section in the django documentation `_. +For more information, refer to the `"Migrations" section in the django +documentation +`_. 10. Create the admin ~~~~~~~~~~~~~~~~~~~~ Refer to the ``admin.py`` file of the sample app. -- `sample_config admin.py `_. -- `sample_geo admin.py `_. -- `sample_pki admin.py `_. -- `sample_connection admin.py `_. -- `sample_subnet_division admin.py `_. - -To introduce changes to the admin, you can do it in two main ways which are described below. - -**Note**: for more information regarding how the django admin works, or how it can be customized, -please refer to `"The django admin site" section in the django documentation `_. +- `sample_config admin.py + `_. +- `sample_geo admin.py + `_. +- `sample_pki admin.py + `_. +- `sample_connection admin.py + `_. +- `sample_subnet_division admin.py + `_. + +To introduce changes to the admin, you can do it in two main ways which +are described below. + +**Note**: for more information regarding how the django admin works, or +how it can be customized, please refer to `"The django admin site" section +in the django documentation +`_. 1. Monkey patching -################## +++++++++++++++++++ -If the changes you need to add are relatively small, you can resort to monkey patching. +If the changes you need to add are relatively small, you can resort to +monkey patching. For example: sample_config -^^^^^^^^^^^^^ +............. .. code-block:: python @@ -3993,7 +4180,7 @@ sample_config # DeviceAdmin.fields += ['example'] <-- monkey patching example sample_connection -^^^^^^^^^^^^^^^^^ +................. .. code-block:: python @@ -4002,7 +4189,7 @@ sample_connection # CredentialsAdmin.fields += ['example'] <-- monkey patching example sample_geo -^^^^^^^^^^ +.......... .. code-block:: python @@ -4011,7 +4198,7 @@ sample_geo # FloorPlanAdmin.fields += ['example'] <-- monkey patching example sample_pki -^^^^^^^^^^ +.......... .. code-block:: python @@ -4020,22 +4207,24 @@ sample_pki # CaAdmin.fields += ['example'] <-- monkey patching example sample_subnet_division -^^^^^^^^^^^^^^^^^^^^^^ +...................... .. code-block:: python - from openwisp_controller.subnet_division.admin import SubnetDivisionRuleInlineAdmin + from openwisp_controller.subnet_division.admin import ( + SubnetDivisionRuleInlineAdmin, + ) # SubnetDivisionRuleInlineAdmin.fields += ['example'] <-- monkey patching example 2. Inheriting admin classes -########################### ++++++++++++++++++++++++++++ -If you need to introduce significant changes and/or you don't want to resort to -monkey patching, you can proceed as follows: +If you need to introduce significant changes and/or you don't want to +resort to monkey patching, you can proceed as follows: sample_config -^^^^^^^^^^^^^ +............. .. code-block:: python @@ -4074,7 +4263,7 @@ sample_config # add your changes here sample_connection -^^^^^^^^^^^^^^^^^ +................. .. code-block:: python @@ -4091,7 +4280,7 @@ sample_connection # add your changes here sample_geo -^^^^^^^^^^ +.......... .. code-block:: python @@ -4117,7 +4306,7 @@ sample_geo # add your changes here sample_pki -^^^^^^^^^^ +.......... .. code-block:: python @@ -4143,7 +4332,7 @@ sample_pki # add your changes here sample_subnet_division -^^^^^^^^^^^^^^^^^^^^^^ +...................... .. code-block:: python @@ -4183,6 +4372,7 @@ sample_subnet_division from django.contrib import admin from openwisp_controller.config.utils import get_controller_urls from openwisp_controller.geo.utils import get_geo_urls + # from .sample_config import views as config_views # from .sample_geo import views as geo_views @@ -4190,43 +4380,61 @@ sample_subnet_division # ... other urls in your project ... # Use only when changing controller API views (discussed below) # url(r'^controller/', include((get_controller_urls(config_views), 'controller'), namespace='controller')) - # Use only when changing geo API views (discussed below) # url(r'^geo/', include((get_geo_urls(geo_views), 'geo'), namespace='geo')), - # openwisp-controller urls - url(r'', include(('openwisp_controller.config.urls', 'config'), namespace='config')), - url(r'', include('openwisp_controller.urls')), + url( + r"", + include( + ("openwisp_controller.config.urls", "config"), + namespace="config", + ), + ), + url(r"", include("openwisp_controller.urls")), ] -For more information about URL configuration in django, please refer to the -`"URL dispatcher" section in the django documentation `_. +For more information about URL configuration in django, please refer to +the `"URL dispatcher" section in the django documentation +`_. 12. Import the automated tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When developing a custom application based on this module, it's a good -idea to import and run the base tests too, so that you can be sure the changes -you're introducing are not breaking some of the existing features of *openwisp-controller*. +idea to import and run the base tests too, so that you can be sure the +changes you're introducing are not breaking some of the existing features +of *openwisp-controller*. -In case you need to add breaking changes, you can overwrite the tests defined -in the base classes to test your own behavior. +In case you need to add breaking changes, you can overwrite the tests +defined in the base classes to test your own behavior. See the tests in sample_app to find out how to do this. -- `project common tests.py `_ -- `sample_config tests.py `_ -- `sample_geo tests.py `_ -- `sample_geo pytest.py `_ -- `sample_pki tests.py `_ -- `sample_connection tests.py `_ -- `sample_subnet_division tests.py `_ +- `project common tests.py + `_ +- `sample_config tests.py + `_ +- `sample_geo tests.py + `_ +- `sample_geo pytest.py + `_ +- `sample_pki tests.py + `_ +- `sample_connection tests.py + `_ +- `sample_subnet_division tests.py + `_ For running the tests, you need to copy fixtures as well: -- Change `sample_config` to your config app's name in `sample_config fixtures `_ and paste it in the ``sample_config/fixtures/`` directory. +- Change `sample_config` to your config app's name in `sample_config + fixtures + `_ + and paste it in the ``sample_config/fixtures/`` directory. -You can then run tests with:: +You can then run tests with: + +:: # the --parallel flag is optional ./manage.py test --parallel mycontroller @@ -4234,44 +4442,54 @@ You can then run tests with:: Substitute ``mycontroller`` with the name you chose in step 1. For more information about automated tests in django, please refer to -`"Testing in Django" `_. +`"Testing in Django" +`_. Other base classes that can be inherited and extended ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following steps are not required and are intended for more advanced customization. +The following steps are not required and are intended for more advanced +customization. 1. Extending the Controller API Views -##################################### ++++++++++++++++++++++++++++++++++++++ -Extending the `sample_config/views.py `_ +Extending the `sample_config/views.py +`_ is required only when you want to make changes in the controller API, -Remember to change ``config_views`` location in ``urls.py`` in point 11 for extending views. +Remember to change ``config_views`` location in ``urls.py`` in point 11 +for extending views. -For more information about django views, please refer to the `views section in the django documentation `_. +For more information about django views, please refer to the `views +section in the django documentation +`_. 2. Extending the Geo API Views -############################## +++++++++++++++++++++++++++++++ -Extending the `sample_geo/views.py `_ -is required only when you want to make changes in the geo API, -Remember to change ``geo_views`` location in ``urls.py`` in point 11 for extending views. +Extending the `sample_geo/views.py +`_ +is required only when you want to make changes in the geo API, Remember to +change ``geo_views`` location in ``urls.py`` in point 11 for extending +views. -For more information about django views, please refer to the `views section in the django documentation `_. +For more information about django views, please refer to the `views +section in the django documentation +`_. Custom Subnet Division Rule Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is possible to create your own `subnet division rule types <#subnet-division-app>`_. -The rule type determines when subnets and IPs will be provisioned and when they -will be destroyed. +It is possible to create your own `subnet division rule types +<#subnet-division-app>`_. The rule type determines when subnets and IPs +will be provisioned and when they will be destroyed. You can create your custom rule types by extending ``openwisp_controller.subnet_division.rule_types.base.BaseSubnetDivisionRuleType``. -Below is an example to create a subnet division rule type that will provision -subnets and IPs when a new device is created and will delete them upon deletion -for that device. +Below is an example to create a subnet division rule type that will +provision subnets and IPs when a new device is created and will delete +them upon deletion for that device. .. code-block:: python @@ -4284,7 +4502,8 @@ for that device. BaseSubnetDivisionRuleType, ) - Device = load_model('config', 'Device') + Device = load_model("config", "Device") + class CustomRuleType(BaseSubnetDivisionRuleType): # The signal on which provisioning should be triggered @@ -4292,14 +4511,14 @@ for that device. # The sender of the provision_signal provision_sender = Device # Dispatch UID for connecting provision_signal to provision_receiver - provision_dispatch_uid = 'some_unique_identifier_string' + provision_dispatch_uid = "some_unique_identifier_string" # The signal on which deletion should be triggered destroyer_signal = post_delete # The sender of the destroyer_signal destroyer_sender = Device # Dispatch UID for connecting destroyer_signal to destroyer_receiver - destroyer_dispatch_uid = 'another_unique_identifier_string' + destroyer_dispatch_uid = "another_unique_identifier_string" # Attribute path to organization_id # Example 1: If organization_id is direct attribute of provision_signal @@ -4308,17 +4527,17 @@ for that device. # Example 2: If organization_id is indirect attribute of provision signal # sender instance, then # organization_id_path = 'some_attribute.another_intermediate.organization_id' - organization_id_path = 'organization_id' + organization_id_path = "organization_id" # Similar to organization_id_path but for the required subnet attribute - subnet_path = 'subnet' + subnet_path = "subnet" # An intermediate method through which you can specify conditions for provisions @classmethod def should_create_subnets_ips(cls, instance, **kwargs): # Using "post_save" provision_signal, the rule should be only # triggered when a new object is created. - return kwargs['created'] + return kwargs["created"] # You can define logic to trigger provisioning for existing objects # using following classmethod. By default, BaseSubnetDivisionRuleType @@ -4331,8 +4550,8 @@ for that device. cls.provision_receiver(device, created=True) After creating a class for your custom rule type, you will need to set -`OPENWISP_CONTROLLER_SUBNET_DIVISION_TYPES <#openwisp-controller-subnet-division-types>`_ -setting as follows: +`OPENWISP_CONTROLLER_SUBNET_DIVISION_TYPES +<#openwisp-controller-subnet-division-types>`_ setting as follows: .. code-block:: python @@ -4352,25 +4571,28 @@ For more information, see the relevant `documentation section about registering notification types in openwisp-notifications `_. -Once a new notification type is registered, you have to use the -`"notify" signal provided in openwisp-notifications +Once a new notification type is registered, you have to use the `"notify" +signal provided in openwisp-notifications `_ to send notifications for this type. Contributing ------------ -Please refer to the `OpenWISP contributing guidelines `_. +Please refer to the `OpenWISP contributing guidelines +`_. Changelog --------- -See `CHANGES `_. +See `CHANGES +`_. License ------- -See `LICENSE `_. +See `LICENSE +`_. Support ------- diff --git a/openwisp_controller/admin.py b/openwisp_controller/admin.py index 84bf11d8f..5fe258262 100644 --- a/openwisp_controller/admin.py +++ b/openwisp_controller/admin.py @@ -1,6 +1,7 @@ """ Base admin classes and mixins """ + from django.core.exceptions import PermissionDenied from openwisp_users.multitenancy import ( diff --git a/openwisp_controller/config/base/multitenancy.py b/openwisp_controller/config/base/multitenancy.py index 169c71a41..05c9424e8 100644 --- a/openwisp_controller/config/base/multitenancy.py +++ b/openwisp_controller/config/base/multitenancy.py @@ -13,7 +13,6 @@ class AbstractOrganizationConfigSettings(UUIDModel): - organization = models.OneToOneField( swapper.get_model_name('openwisp_users', 'Organization'), verbose_name=_('organization'), diff --git a/openwisp_controller/config/base/vpn.py b/openwisp_controller/config/base/vpn.py index 7a6c8cd53..4e3f4228a 100644 --- a/openwisp_controller/config/base/vpn.py +++ b/openwisp_controller/config/base/vpn.py @@ -244,7 +244,7 @@ def _validate_host(self): def save(self, *args, **kwargs): """ - Calls _auto_create_cert() if cert is not set + Calls _auto_create_cert() if cert is not set. """ config = {} created = self._state.adding @@ -328,9 +328,9 @@ def dhparam(cls, length): @classmethod def post_delete(cls, instance, **kwargs): - """ - class method for ``post_delete`` signal - for managing automatic deletion of vpn servers + """Receiver for ``post_delete`` signal. + + Manages automatic deletion of vpn servers. """ if not instance._is_backend_type('zerotier'): return @@ -510,9 +510,11 @@ def get_system_context(self): return self.get_context() def _is_backend_type(self, backend_type): - """ - returns true if the backend path used converted to lowercase + """Returns True if backend contains specified backend_type. + + Returns true if the backend path used converted to lowercase contains ``backend_type``. + Checking for the exact path may not be the best choices given backends can be extended and customized. By using this method, customizations will just have @@ -521,22 +523,30 @@ def _is_backend_type(self, backend_type): return backend_type.lower() in self.backend.lower() def _get_auto_context_keys(self): - """ - returns a dictionary which indicates the names of + """Returns context keys automatically. + + Returns a dictionary which indicates the names of the configuration variables needed to access: - * path to CA file - * CA certificate in PEM format - * path to cert file - * cert in PEM format - * path to key file - * key in PEM format + + * path to CA file + * CA certificate in PEM format + * path to cert file + * cert in PEM format + * path to key file + * key in PEM format + WireGuard: - * public key - * ip address + + * public key + * ip address + VXLAN: - * vni (VXLAN Network Identifier) - ZeroTier - * network_id (ZeroTier Network Identifier) + + * vni (VXLAN Network Identifier) + + ZeroTier: + + * network_id (ZeroTier Network Identifier) """ pk = self.pk.hex context_keys = { @@ -585,8 +595,9 @@ def _get_auto_context_keys(self): return context_keys def auto_client(self, auto_cert=True, template_backend_class=None): - """ - calls backend ``auto_client`` method and returns a configuration + """Calls backend ``auto_client`` method. + + Returns a configuration dictionary that is suitable to be used as a template if ``auto_cert`` is ``False`` the resulting configuration won't include autogenerated key and certificate details @@ -653,9 +664,9 @@ def _auto_create_cert_extra(self, cert): return cert def _generate_wireguard_keys(self): - """ - generates wireguard private and public keys - and set the respctive attributes + """Generates wireguard private and public keys. + + Also sets the respctive instance attributes. """ if not self.private_key or not self.public_key: self.private_key, self.public_key = crypto.generate_wireguard_keys() @@ -669,9 +680,10 @@ def get_config(self): return config def _invalidate_peer_cache(self, update=False): - """ - Invalidates peer cache, if update=True is passed, - the peer cache will be regenerated + """Invalidates peer cache. + + If update=True is passed, + the peer cache will be regenerated. """ for backend in ['wireguard', 'vxlan']: if self._is_backend_type(backend): @@ -682,9 +694,10 @@ def _invalidate_peer_cache(self, update=False): vpn_peers_changed.send(sender=self.__class__, instance=self) def _get_peer_queryset(self): - """ - returns an iterator to iterate over tunnel peers - used to generate the list of peers of a tunnel (WireGuard/VXLAN) + """Returns peer queryset. + + Returns an iterator to iterate over tunnel peers + used to generate the list of peers of a tunnel (WireGuard/VXLAN). """ return ( self.vpnclient_set.select_related('config', 'ip') @@ -702,9 +715,9 @@ def _get_peer_queryset(self): ) def _add_wireguard(self, config): - """ - Adds wireguard peers and private key to the generated - configuration without the need of manual intervention. + """Adds wireguard peers and private key to the generated configuration + + without the need of manual intervention. Modifies the config data structure as a side effect. """ try: @@ -722,9 +735,7 @@ def _add_wireguard(self, config): @cache_memoize(_PEER_CACHE_TIMEOUT, args_rewrite=_peer_cache_key) def _get_wireguard_peers(self): - """ - Returns list of wireguard peers, the result is cached. - """ + """Returns list of wireguard peers, the result is cached.""" peers = [] for vpnclient in self._get_peer_queryset(): if vpnclient.ip: @@ -738,8 +749,8 @@ def _get_wireguard_peers(self): return peers def _add_vxlan(self, config): - """ - Adds VXLAN peers to the generated configuration + """Adds VXLAN peers to the generated configuration + without the need of manual intervention. Modifies the config data structure as a side effect. """ @@ -831,8 +842,8 @@ def zerotier_member_id(self): @classmethod def register_auto_ip_stopper(cls, func): - """ - Adds "func" to "_auto_ip_stopper_funcs". + """Adds "func" to "_auto_ip_stopper_funcs". + These functions are called in the "_auto_ip" method. Output from these functions are used to determine skipping automatic IP assignment. @@ -856,10 +867,7 @@ def _get_unique_checks(self, exclude=None, include_meta_constraints=False): return unique_checks, date_checks def save(self, *args, **kwargs): - """ - automatically provisions tunnel keys - and configuration if ``auto_cert`` is True - """ + """Performs automatic provisioning if ``auto_cert`` is True.""" if self.auto_cert: self._auto_x509() self._auto_ip() @@ -870,7 +878,7 @@ def save(self, *args, **kwargs): def _auto_x509(self): """ - automatically creates an x509 certificate + Automatically creates an x509 certificate. """ if not self.vpn._is_backend_type('openvpn') or self.cert: return @@ -879,7 +887,7 @@ def _auto_x509(self): def _get_common_name(self): """ - returns the common name for a new certificate + Returns the common name for a new certificate. """ d = self.config.device end = 63 - len(d.mac_address) @@ -908,10 +916,10 @@ def _post_save(): @classmethod def post_delete(cls, instance, **kwargs): - """ - class method for ``post_delete`` signal - automatically deletes related certificates - and ip addresses if necessary + """Receiver of ``post_delete`` signal. + + Automatically deletes related certificates + and ip addresses if necessary. """ # only invalidates, does not regenerate the cache # to avoid generating high load during bulk deletes diff --git a/openwisp_controller/config/migrations/0003_template_tags.py b/openwisp_controller/config/migrations/0003_template_tags.py index 80d3f85c7..fe4277fbc 100644 --- a/openwisp_controller/config/migrations/0003_template_tags.py +++ b/openwisp_controller/config/migrations/0003_template_tags.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('config', '0001_squashed_0002_config_settings_uuid'), diff --git a/openwisp_controller/config/migrations/0004_add_device_model.py b/openwisp_controller/config/migrations/0004_add_device_model.py index 98e8c2190..4d44fb349 100644 --- a/openwisp_controller/config/migrations/0004_add_device_model.py +++ b/openwisp_controller/config/migrations/0004_add_device_model.py @@ -17,7 +17,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0003_template_tags'), ] diff --git a/openwisp_controller/config/migrations/0006_config_device_not_null.py b/openwisp_controller/config/migrations/0006_config_device_not_null.py index 62a76b975..e9ed9add3 100644 --- a/openwisp_controller/config/migrations/0006_config_device_not_null.py +++ b/openwisp_controller/config/migrations/0006_config_device_not_null.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0005_populate_device')] operations = [ diff --git a/openwisp_controller/config/migrations/0007_simplify_config.py b/openwisp_controller/config/migrations/0007_simplify_config.py index e333864c8..4c68881a8 100644 --- a/openwisp_controller/config/migrations/0007_simplify_config.py +++ b/openwisp_controller/config/migrations/0007_simplify_config.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0006_config_device_not_null')] operations = [ diff --git a/openwisp_controller/config/migrations/0008_update_indexes.py b/openwisp_controller/config/migrations/0008_update_indexes.py index 6913c0c4d..cdd79ed3a 100644 --- a/openwisp_controller/config/migrations/0008_update_indexes.py +++ b/openwisp_controller/config/migrations/0008_update_indexes.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0007_simplify_config')] operations = [ diff --git a/openwisp_controller/config/migrations/0009_device_system.py b/openwisp_controller/config/migrations/0009_device_system.py index a41be8498..4692aeb70 100644 --- a/openwisp_controller/config/migrations/0009_device_system.py +++ b/openwisp_controller/config/migrations/0009_device_system.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0008_update_indexes')] operations = [ diff --git a/openwisp_controller/config/migrations/0010_auto_20180106_1814.py b/openwisp_controller/config/migrations/0010_auto_20180106_1814.py index 98cb1b4dd..b15508bdd 100644 --- a/openwisp_controller/config/migrations/0010_auto_20180106_1814.py +++ b/openwisp_controller/config/migrations/0010_auto_20180106_1814.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0009_device_system')] operations = [ diff --git a/openwisp_controller/config/migrations/0011_update_device_mac_address.py b/openwisp_controller/config/migrations/0011_update_device_mac_address.py index 19561ef69..d0664e81f 100644 --- a/openwisp_controller/config/migrations/0011_update_device_mac_address.py +++ b/openwisp_controller/config/migrations/0011_update_device_mac_address.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0010_auto_20180106_1814')] operations = [ diff --git a/openwisp_controller/config/migrations/0012_auto_20180219_1501.py b/openwisp_controller/config/migrations/0012_auto_20180219_1501.py index ccb7b50e1..9096f70ed 100644 --- a/openwisp_controller/config/migrations/0012_auto_20180219_1501.py +++ b/openwisp_controller/config/migrations/0012_auto_20180219_1501.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0011_update_device_mac_address')] operations = [ diff --git a/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py b/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py index 0694ab67d..f8db9b627 100644 --- a/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py +++ b/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py @@ -41,7 +41,6 @@ def migrate_status_backward(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [('config', '0012_auto_20180219_1501')] operations = [ diff --git a/openwisp_controller/config/migrations/0014_device_hardware_id.py b/openwisp_controller/config/migrations/0014_device_hardware_id.py index 01c164164..f68721c1b 100644 --- a/openwisp_controller/config/migrations/0014_device_hardware_id.py +++ b/openwisp_controller/config/migrations/0014_device_hardware_id.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0013_last_ip_management_ip_and_status_applied')] operations = [ diff --git a/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py b/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py index 7777caa3a..d413f7a76 100644 --- a/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py +++ b/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0016_default_organization_config_settings'), ] diff --git a/openwisp_controller/config/migrations/0018_config_context.py b/openwisp_controller/config/migrations/0018_config_context.py index 5c7050bf2..b42a698e4 100644 --- a/openwisp_controller/config/migrations/0018_config_context.py +++ b/openwisp_controller/config/migrations/0018_config_context.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0017_template_name_organization_unique_together')] operations = [ diff --git a/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py b/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py index 7b207c5d5..4780bb3a2 100644 --- a/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py +++ b/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0018_config_context'), ] diff --git a/openwisp_controller/config/migrations/0020_remove_config_organization.py b/openwisp_controller/config/migrations/0020_remove_config_organization.py index dfc6fa371..b7059d02a 100644 --- a/openwisp_controller/config/migrations/0020_remove_config_organization.py +++ b/openwisp_controller/config/migrations/0020_remove_config_organization.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0019_organization_mac_add_hardware_id_name_unique_together') ] diff --git a/openwisp_controller/config/migrations/0021_vpn_key.py b/openwisp_controller/config/migrations/0021_vpn_key.py index b8aa4131c..fdbe759ea 100644 --- a/openwisp_controller/config/migrations/0021_vpn_key.py +++ b/openwisp_controller/config/migrations/0021_vpn_key.py @@ -10,7 +10,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0020_remove_config_organization')] operations = [ diff --git a/openwisp_controller/config/migrations/0022_vpn_format_dh.py b/openwisp_controller/config/migrations/0022_vpn_format_dh.py index a68926f87..48d18bfb6 100644 --- a/openwisp_controller/config/migrations/0022_vpn_format_dh.py +++ b/openwisp_controller/config/migrations/0022_vpn_format_dh.py @@ -11,7 +11,6 @@ def format_dh(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [('config', '0021_vpn_key')] operations = [ diff --git a/openwisp_controller/config/migrations/0023_update_context.py b/openwisp_controller/config/migrations/0023_update_context.py index 20d136155..9003d6328 100644 --- a/openwisp_controller/config/migrations/0023_update_context.py +++ b/openwisp_controller/config/migrations/0023_update_context.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0022_vpn_format_dh')] operations = [ diff --git a/openwisp_controller/config/migrations/0024_update_context_data.py b/openwisp_controller/config/migrations/0024_update_context_data.py index dac2143ca..70f81064a 100644 --- a/openwisp_controller/config/migrations/0024_update_context_data.py +++ b/openwisp_controller/config/migrations/0024_update_context_data.py @@ -15,7 +15,6 @@ def forward(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [('config', '0023_update_context')] operations = [migrations.RunPython(forward, reverse_code=migrations.RunPython.noop)] diff --git a/openwisp_controller/config/migrations/0025_update_device_key.py b/openwisp_controller/config/migrations/0025_update_device_key.py index c20325702..724603366 100644 --- a/openwisp_controller/config/migrations/0025_update_device_key.py +++ b/openwisp_controller/config/migrations/0025_update_device_key.py @@ -10,7 +10,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0024_update_context_data')] operations = [ diff --git a/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py b/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py index 25e6102e8..dcf3070a9 100644 --- a/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py +++ b/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0025_update_device_key')] operations = [ diff --git a/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py b/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py index 3d49cc0d2..7e143de81 100644 --- a/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py +++ b/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0026_hardware_id_not_unique')] operations = [ diff --git a/openwisp_controller/config/migrations/0028_template_default_values.py b/openwisp_controller/config/migrations/0028_template_default_values.py index 80111c489..65b365535 100644 --- a/openwisp_controller/config/migrations/0028_template_default_values.py +++ b/openwisp_controller/config/migrations/0028_template_default_values.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0027_add_indexes_on_ip_fields')] operations = [ diff --git a/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py b/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py index 40421c4b2..407d3b306 100644 --- a/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py +++ b/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0028_template_default_values')] operations = [ diff --git a/openwisp_controller/config/migrations/0030_django_taggit_update.py b/openwisp_controller/config/migrations/0030_django_taggit_update.py index 78b8a3dfa..73be97c04 100644 --- a/openwisp_controller/config/migrations/0030_django_taggit_update.py +++ b/openwisp_controller/config/migrations/0030_django_taggit_update.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('config', '0029_merge_django_netjsonconfig'), diff --git a/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py b/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py index 42880e6e1..3e4d9b4e0 100644 --- a/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py +++ b/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0030_django_taggit_update')] operations = [ diff --git a/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py b/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py index 4f6db104b..0beda5f62 100644 --- a/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py +++ b/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py @@ -9,7 +9,6 @@ def update_legacy_vpn_backend(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [('config', '0031_update_vpn_dh_param')] operations = [ diff --git a/openwisp_controller/config/migrations/0033_name_unique_per_organization.py b/openwisp_controller/config/migrations/0033_name_unique_per_organization.py index 83ffff0e7..d2b7387be 100644 --- a/openwisp_controller/config/migrations/0033_name_unique_per_organization.py +++ b/openwisp_controller/config/migrations/0033_name_unique_per_organization.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0032_update_legacy_vpn_backend'), ] diff --git a/openwisp_controller/config/migrations/0034_template_required.py b/openwisp_controller/config/migrations/0034_template_required.py index 258aee7a5..f9af82eb5 100644 --- a/openwisp_controller/config/migrations/0034_template_required.py +++ b/openwisp_controller/config/migrations/0034_template_required.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('config', '0033_name_unique_per_organization')] operations = [ diff --git a/openwisp_controller/config/migrations/0035_device_name_unique_optional.py b/openwisp_controller/config/migrations/0035_device_name_unique_optional.py index cbbd0866b..11e27477b 100644 --- a/openwisp_controller/config/migrations/0035_device_name_unique_optional.py +++ b/openwisp_controller/config/migrations/0035_device_name_unique_optional.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0034_template_required'), ] diff --git a/openwisp_controller/config/migrations/0036_device_group.py b/openwisp_controller/config/migrations/0036_device_group.py index 1bb00482d..899ccc9ac 100644 --- a/openwisp_controller/config/migrations/0036_device_group.py +++ b/openwisp_controller/config/migrations/0036_device_group.py @@ -16,7 +16,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0035_device_name_unique_optional'), ] diff --git a/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py b/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py index 93315a247..3b330b287 100644 --- a/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py +++ b/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('config', '0036_device_group'), diff --git a/openwisp_controller/config/migrations/0038_vpn_subnet.py b/openwisp_controller/config/migrations/0038_vpn_subnet.py index 171e45c5f..f48db9eba 100644 --- a/openwisp_controller/config/migrations/0038_vpn_subnet.py +++ b/openwisp_controller/config/migrations/0038_vpn_subnet.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.OPENWISP_IPAM_SUBNET_MODEL), ('config', '0037_alter_taggedtemplate'), diff --git a/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py b/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py index 23566c6e9..9d9414bf8 100644 --- a/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py +++ b/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ swapper.dependency('pki', 'Ca'), swapper.dependency('openwisp_ipam', 'IpAddress'), diff --git a/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py b/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py index 0f359bd8f..fe5c79cb0 100644 --- a/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py +++ b/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.OPENWISP_IPAM_IPADDRESS_MODEL), ('config', '0039_wireguard_vxlan_ipam'), diff --git a/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py b/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py index 098111eea..10c1e092f 100644 --- a/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py +++ b/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0040_vpnclient_ip_setnull'), ] diff --git a/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py b/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py index 3ceedefa2..12051bf1d 100644 --- a/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py +++ b/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py @@ -58,7 +58,6 @@ def disallow_multiple_wireguard_tunneling(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('config', '0041_default_groups_organizationconfigsettings_permission'), ] diff --git a/openwisp_controller/config/migrations/0043_devicegroup_templates.py b/openwisp_controller/config/migrations/0043_devicegroup_templates.py index 4d8726802..74b51391a 100644 --- a/openwisp_controller/config/migrations/0043_devicegroup_templates.py +++ b/openwisp_controller/config/migrations/0043_devicegroup_templates.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0042_multiple_wireguard_tunnels'), ] diff --git a/openwisp_controller/config/migrations/0044_config_error_reason.py b/openwisp_controller/config/migrations/0044_config_error_reason.py index dd35bd3aa..a2b772f57 100644 --- a/openwisp_controller/config/migrations/0044_config_error_reason.py +++ b/openwisp_controller/config/migrations/0044_config_error_reason.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0043_devicegroup_templates'), ] diff --git a/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py b/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py index a08c0ae4e..8cb1ffda6 100644 --- a/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py +++ b/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0044_config_error_reason'), ] diff --git a/openwisp_controller/config/migrations/0046_organizationlimits.py b/openwisp_controller/config/migrations/0046_organizationlimits.py index d112ec44e..10ed1ef45 100644 --- a/openwisp_controller/config/migrations/0046_organizationlimits.py +++ b/openwisp_controller/config/migrations/0046_organizationlimits.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0045_alter_vpn_webhook_endpoint'), ] diff --git a/openwisp_controller/config/migrations/0047_add_organizationlimits.py b/openwisp_controller/config/migrations/0047_add_organizationlimits.py index b74af58e2..24c5c3689 100644 --- a/openwisp_controller/config/migrations/0047_add_organizationlimits.py +++ b/openwisp_controller/config/migrations/0047_add_organizationlimits.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0046_organizationlimits'), ] diff --git a/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py b/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py index c81986921..8eeafcb1f 100644 --- a/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py +++ b/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py @@ -147,7 +147,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('config', '0047_add_organizationlimits'), ] diff --git a/openwisp_controller/config/migrations/0049_devicegroup_context.py b/openwisp_controller/config/migrations/0049_devicegroup_context.py index c54c41024..2d763a020 100644 --- a/openwisp_controller/config/migrations/0049_devicegroup_context.py +++ b/openwisp_controller/config/migrations/0049_devicegroup_context.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0048_wifi_radio_band_migration'), ] diff --git a/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py b/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py index 4cc45c946..a0fd122a7 100644 --- a/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py +++ b/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("config", "0049_devicegroup_context"), ] diff --git a/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py b/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py index d2717dedb..996998e08 100644 --- a/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py +++ b/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0050_alter_vpnclient_unique_together'), ] diff --git a/openwisp_controller/config/migrations/0052_vpn_node_network_id.py b/openwisp_controller/config/migrations/0052_vpn_node_network_id.py index 435ec68c0..79148e2ba 100644 --- a/openwisp_controller/config/migrations/0052_vpn_node_network_id.py +++ b/openwisp_controller/config/migrations/0052_vpn_node_network_id.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0051_organizationconfigsettings_context'), ] diff --git a/openwisp_controller/config/migrations/0053_vpnclient_secret.py b/openwisp_controller/config/migrations/0053_vpnclient_secret.py index 8745d8361..96e0d71b1 100644 --- a/openwisp_controller/config/migrations/0053_vpnclient_secret.py +++ b/openwisp_controller/config/migrations/0053_vpnclient_secret.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('config', '0052_vpn_node_network_id'), ] diff --git a/openwisp_controller/config/static/support.css b/openwisp_controller/config/static/support.css new file mode 100644 index 000000000..67d3ef090 --- /dev/null +++ b/openwisp_controller/config/static/support.css @@ -0,0 +1,4 @@ +.help.icon { + mask-image: url(http://localhost:8000/media/support.png); + -webkit-mask-image: url(http://localhost:8000/media/support.png); +} diff --git a/openwisp_controller/config/tasks_zerotier.py b/openwisp_controller/config/tasks_zerotier.py index 05591379c..c418d9e00 100644 --- a/openwisp_controller/config/tasks_zerotier.py +++ b/openwisp_controller/config/tasks_zerotier.py @@ -18,7 +18,6 @@ class OpenwispApiTask(OpenwispCeleryTask): - _RECOVERABLE_API_CODES = [ HTTPStatus.TOO_MANY_REQUESTS, # 429 HTTPStatus.INTERNAL_SERVER_ERROR, # 500 diff --git a/openwisp_controller/config/tests/test_admin.py b/openwisp_controller/config/tests/test_admin.py index d1361f9ec..737a5e8ad 100644 --- a/openwisp_controller/config/tests/test_admin.py +++ b/openwisp_controller/config/tests/test_admin.py @@ -2038,7 +2038,6 @@ class TestDeviceGroupAdminTransaction( TestAdminMixin, TransactionTestCase, ): - app_label = 'config' _device_group_params = { 'name': 'test-device-group', diff --git a/openwisp_controller/config/tests/test_controller.py b/openwisp_controller/config/tests/test_controller.py index 444d12924..05443e5f3 100644 --- a/openwisp_controller/config/tests/test_controller.py +++ b/openwisp_controller/config/tests/test_controller.py @@ -39,7 +39,6 @@ class TestController(CreateConfigTemplateMixin, TestVpnX509Mixin, TestCase): - """ tests for config.controller """ diff --git a/openwisp_controller/config/tests/test_notifications.py b/openwisp_controller/config/tests/test_notifications.py index ddb9eb302..e023450e0 100644 --- a/openwisp_controller/config/tests/test_notifications.py +++ b/openwisp_controller/config/tests/test_notifications.py @@ -234,7 +234,6 @@ def test_zerotier_api_tasks_notification( with self.subTest( 'Test notifications are generated for API tasks (unrecoverable errors)' ): - with self.subTest( 'Test error notification on failure of first call (update network)' ): diff --git a/openwisp_controller/config/tests/utils.py b/openwisp_controller/config/tests/utils.py index 16f86e070..900c53e7a 100644 --- a/openwisp_controller/config/tests/utils.py +++ b/openwisp_controller/config/tests/utils.py @@ -3,6 +3,7 @@ these mixins are reused also in openwisp2 change with care. """ + from copy import deepcopy from unittest import mock from uuid import uuid4 diff --git a/openwisp_controller/connection/migrations/0001_initial.py b/openwisp_controller/connection/migrations/0001_initial.py index fcb4f8eb7..6acd845d5 100644 --- a/openwisp_controller/connection/migrations/0001_initial.py +++ b/openwisp_controller/connection/migrations/0001_initial.py @@ -17,7 +17,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/openwisp_controller/connection/migrations/0002_credentials_auto_add.py b/openwisp_controller/connection/migrations/0002_credentials_auto_add.py index d3bc34b1e..e1226f44f 100644 --- a/openwisp_controller/connection/migrations/0002_credentials_auto_add.py +++ b/openwisp_controller/connection/migrations/0002_credentials_auto_add.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('connection', '0001_initial')] operations = [ diff --git a/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py b/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py index ff5a81953..bc69290a6 100644 --- a/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py +++ b/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('connection', '0003_default_group_permissions')] operations = [ diff --git a/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py b/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py index 08c1c8ba4..c337feb11 100644 --- a/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py +++ b/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py @@ -10,7 +10,6 @@ def truncate_failure_reason(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [('connection', '0004_django3_1_upgrade')] operations = [ diff --git a/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py b/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py index 9d02320ee..b61f07ac8 100644 --- a/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py +++ b/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('connection', '0005_device_connection_failure_reason'), ] diff --git a/openwisp_controller/connection/migrations/0007_command.py b/openwisp_controller/connection/migrations/0007_command.py index f9272837b..4a5e0e424 100644 --- a/openwisp_controller/connection/migrations/0007_command.py +++ b/openwisp_controller/connection/migrations/0007_command.py @@ -16,7 +16,6 @@ class Migration(migrations.Migration): - dependencies = [ ('connection', '0006_name_unique_per_organization'), swapper.dependency('config', 'Device'), diff --git a/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py b/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py index 0f9276628..cd652b5c4 100644 --- a/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py +++ b/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py @@ -19,7 +19,6 @@ def remove_conflicting_deviceconnections(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('connection', '0007_command'), ] diff --git a/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py b/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py index 496f676b2..fe213bb40 100644 --- a/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py +++ b/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.CONFIG_DEVICE_MODEL), ('connection', '0008_remove_conflicting_deviceconnections'), diff --git a/openwisp_controller/connection/tests/utils.py b/openwisp_controller/connection/tests/utils.py index 740c8d4e4..b2d599573 100644 --- a/openwisp_controller/connection/tests/utils.py +++ b/openwisp_controller/connection/tests/utils.py @@ -29,7 +29,6 @@ def _run(self, *args, **kwargs): class CreateConnectionsMixin(CreateConfigTemplateMixin, TestOrganizationMixin): - _TEST_RSA_PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'test-key.rsa') _TEST_RSA_PRIVATE_KEY_VALUE = None _TEST_ED_PRIVATE_KEY_PATH = os.path.join( diff --git a/openwisp_controller/geo/migrations/0001_initial.py b/openwisp_controller/geo/migrations/0001_initial.py index 562c178b2..76c552a00 100644 --- a/openwisp_controller/geo/migrations/0001_initial.py +++ b/openwisp_controller/geo/migrations/0001_initial.py @@ -15,7 +15,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py b/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py index 951c3ef95..d18b90cd0 100644 --- a/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py +++ b/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('geo', '0002_default_groups_permissions'), ] diff --git a/openwisp_controller/pki/base/models.py b/openwisp_controller/pki/base/models.py index 281a36219..4c8a2d275 100644 --- a/openwisp_controller/pki/base/models.py +++ b/openwisp_controller/pki/base/models.py @@ -21,7 +21,6 @@ class Meta(BaseCa.Meta): class AbstractCert(ShareableOrgMixin, UnqiueCommonNameMixin, BaseCert): - ca = models.ForeignKey( get_model_name('django_x509', 'Ca'), verbose_name=_('CA'), diff --git a/openwisp_controller/pki/migrations/0001_initial.py b/openwisp_controller/pki/migrations/0001_initial.py index 1d1a1b774..d4251a271 100644 --- a/openwisp_controller/pki/migrations/0001_initial.py +++ b/openwisp_controller/pki/migrations/0001_initial.py @@ -14,7 +14,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/openwisp_controller/pki/migrations/0002_add_organization_name.py b/openwisp_controller/pki/migrations/0002_add_organization_name.py index 6fdad87f3..cd9a16bc9 100644 --- a/openwisp_controller/pki/migrations/0002_add_organization_name.py +++ b/openwisp_controller/pki/migrations/0002_add_organization_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0001_initial')] operations = [ diff --git a/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py b/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py index 82a2ca8c4..aefb5f67b 100644 --- a/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py +++ b/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0003_fill_organization_name')] operations = [ diff --git a/openwisp_controller/pki/migrations/0005_organizational_unit_name.py b/openwisp_controller/pki/migrations/0005_organizational_unit_name.py index ba6dd59ee..d24856211 100644 --- a/openwisp_controller/pki/migrations/0005_organizational_unit_name.py +++ b/openwisp_controller/pki/migrations/0005_organizational_unit_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0004_auto_20180106_1814')] operations = [ diff --git a/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py b/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py index e73ee26e5..4107b1d63 100644 --- a/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py +++ b/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0005_organizational_unit_name')] operations = [ diff --git a/openwisp_controller/pki/migrations/0008_serial_number_length.py b/openwisp_controller/pki/migrations/0008_serial_number_length.py index a2cb3b998..bc9a631ac 100644 --- a/openwisp_controller/pki/migrations/0008_serial_number_length.py +++ b/openwisp_controller/pki/migrations/0008_serial_number_length.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0007_default_groups_permissions')] operations = [ diff --git a/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py b/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py index 8835bfe15..229cb3cd8 100644 --- a/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py +++ b/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [('pki', '0008_serial_number_length')] operations = [ diff --git a/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py b/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py index 1c1feb5dd..425c7e040 100644 --- a/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py +++ b/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py @@ -62,7 +62,6 @@ def make_cert_common_name_unique(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('pki', '0009_common_name_maxlength_64'), ] diff --git a/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py b/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py index fcbcc4339..9385ba64d 100644 --- a/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py +++ b/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ('pki', '0010_common_name_organization_unique'), ] diff --git a/openwisp_controller/subnet_division/migrations/0001_initial.py b/openwisp_controller/subnet_division/migrations/0001_initial.py index b222f9712..350ac0f41 100644 --- a/openwisp_controller/subnet_division/migrations/0001_initial.py +++ b/openwisp_controller/subnet_division/migrations/0001_initial.py @@ -12,7 +12,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py b/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py index f8631f1b6..8c42595ca 100644 --- a/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py +++ b/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.CONFIG_CONFIG_MODEL), migrations.swappable_dependency(settings.OPENWISP_IPAM_IPADDRESS_MODEL), diff --git a/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py b/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py index b9b1911d0..f0ac4a186 100644 --- a/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py +++ b/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('subnet_division', '0003_related_field_allow_blank'), ] diff --git a/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py b/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py index b059acf21..7eb38e077 100644 --- a/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py +++ b/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ('subnet_division', '0004_index_rule_on_delete'), ] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a3a5341f6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[tool.isort] +known_third_party = ["django", "django_x509"] +known_first_party = ["openwisp_users", "openwisp_utils"] +default_section = "THIRDPARTY" +line_length = 88 +multi_line_output = 3 +use_parentheses = true +include_trailing_comma = true +force_grid_wrap = 0 + +[tool.coverage.run] +parallel = true +omit = [ + "**/test*", + "tests", + "**/__init__.py", + "setup.py", + "**/migrations/*" +] +source = ["openwisp_controller"] +concurrency = ["multiprocessing"] + +[tool.docstrfmt] +extend_exclude = ["**/*.py", "README.rst"] diff --git a/setup.cfg b/setup.cfg index f5ba781a5..639f180a7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,16 +1,6 @@ [bdist_wheel] universal=1 -[isort] -known_third_party = django,django_x509 -known_first_party = openwisp_users, openwisp_utils -default_section = THIRDPARTY -line_length=88 -multi_line_output=3 -use_parentheses=True -include_trailing_comma=True -force_grid_wrap=0 - [flake8] # W503: line break before or after operator # W504: line break after or after operator diff --git a/tests/openwisp2/sample_config/migrations/0001_initial.py b/tests/openwisp2/sample_config/migrations/0001_initial.py index b50a15208..9b36aae04 100644 --- a/tests/openwisp2/sample_config/migrations/0001_initial.py +++ b/tests/openwisp2/sample_config/migrations/0001_initial.py @@ -22,7 +22,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_config/migrations/0003_name_unique_per_organization.py b/tests/openwisp2/sample_config/migrations/0003_name_unique_per_organization.py index 6462f3fb9..11360a672 100644 --- a/tests/openwisp2/sample_config/migrations/0003_name_unique_per_organization.py +++ b/tests/openwisp2/sample_config/migrations/0003_name_unique_per_organization.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_config', '0002_default_groups_permissions'), ] diff --git a/tests/openwisp2/sample_config/migrations/0004_devicegroup_templates.py b/tests/openwisp2/sample_config/migrations/0004_devicegroup_templates.py index 62feeb8c4..8ebb554ae 100644 --- a/tests/openwisp2/sample_config/migrations/0004_devicegroup_templates.py +++ b/tests/openwisp2/sample_config/migrations/0004_devicegroup_templates.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_config', '0003_name_unique_per_organization'), ] diff --git a/tests/openwisp2/sample_config/migrations/0005_add_organizationalloweddevice.py b/tests/openwisp2/sample_config/migrations/0005_add_organizationalloweddevice.py index f7d6a040e..2ac457b16 100644 --- a/tests/openwisp2/sample_config/migrations/0005_add_organizationalloweddevice.py +++ b/tests/openwisp2/sample_config/migrations/0005_add_organizationalloweddevice.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_config', '0004_devicegroup_templates'), ] diff --git a/tests/openwisp2/sample_connection/migrations/0001_initial.py b/tests/openwisp2/sample_connection/migrations/0001_initial.py index 0e95da9bc..769afa4fc 100644 --- a/tests/openwisp2/sample_connection/migrations/0001_initial.py +++ b/tests/openwisp2/sample_connection/migrations/0001_initial.py @@ -18,7 +18,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_connection/migrations/0003_name_unique_per_organization.py b/tests/openwisp2/sample_connection/migrations/0003_name_unique_per_organization.py index 4e2bd95cb..0b5b861cc 100644 --- a/tests/openwisp2/sample_connection/migrations/0003_name_unique_per_organization.py +++ b/tests/openwisp2/sample_connection/migrations/0003_name_unique_per_organization.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_connection', '0002_default_group_permissions'), ] diff --git a/tests/openwisp2/sample_geo/migrations/0001_initial.py b/tests/openwisp2/sample_geo/migrations/0001_initial.py index 6a16cf264..c68bb608d 100644 --- a/tests/openwisp2/sample_geo/migrations/0001_initial.py +++ b/tests/openwisp2/sample_geo/migrations/0001_initial.py @@ -15,7 +15,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_geo/migrations/0003_alter_devicelocation_floorplan_location.py b/tests/openwisp2/sample_geo/migrations/0003_alter_devicelocation_floorplan_location.py index 8e58699ba..731cbe250 100644 --- a/tests/openwisp2/sample_geo/migrations/0003_alter_devicelocation_floorplan_location.py +++ b/tests/openwisp2/sample_geo/migrations/0003_alter_devicelocation_floorplan_location.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_geo', '0002_default_group_permissions'), ] diff --git a/tests/openwisp2/sample_pki/migrations/0001_initial.py b/tests/openwisp2/sample_pki/migrations/0001_initial.py index f1ed8c01b..f6f2ac461 100644 --- a/tests/openwisp2/sample_pki/migrations/0001_initial.py +++ b/tests/openwisp2/sample_pki/migrations/0001_initial.py @@ -15,7 +15,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_pki/migrations/0003_disallowed_blank_key_length_or_digest.py b/tests/openwisp2/sample_pki/migrations/0003_disallowed_blank_key_length_or_digest.py index 544cb8109..9e84635a3 100644 --- a/tests/openwisp2/sample_pki/migrations/0003_disallowed_blank_key_length_or_digest.py +++ b/tests/openwisp2/sample_pki/migrations/0003_disallowed_blank_key_length_or_digest.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ('sample_pki', '0002_default_group_permissions'), ] diff --git a/tests/openwisp2/sample_subnet_division/migrations/0001_initial.py b/tests/openwisp2/sample_subnet_division/migrations/0001_initial.py index 87d3fbe38..ba8c465a0 100644 --- a/tests/openwisp2/sample_subnet_division/migrations/0001_initial.py +++ b/tests/openwisp2/sample_subnet_division/migrations/0001_initial.py @@ -14,7 +14,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_users/migrations/0001_initial.py b/tests/openwisp2/sample_users/migrations/0001_initial.py index abe717549..2f74dbc9b 100644 --- a/tests/openwisp2/sample_users/migrations/0001_initial.py +++ b/tests/openwisp2/sample_users/migrations/0001_initial.py @@ -17,7 +17,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_users/migrations/0004_default_groups.py b/tests/openwisp2/sample_users/migrations/0004_default_groups.py index cb80cb0ff..b750b7171 100644 --- a/tests/openwisp2/sample_users/migrations/0004_default_groups.py +++ b/tests/openwisp2/sample_users/migrations/0004_default_groups.py @@ -13,7 +13,6 @@ class Migration(migrations.Migration): - org_model = swapper.get_model_name('openwisp_users', 'organization') model_app_label = swapper.split(org_model)[0] dependencies = [(model_app_label, '0001_initial')] diff --git a/tests/openwisp2/sample_users/tests.py b/tests/openwisp2/sample_users/tests.py index 7bbbe0c9d..40982c841 100644 --- a/tests/openwisp2/sample_users/tests.py +++ b/tests/openwisp2/sample_users/tests.py @@ -32,7 +32,6 @@ class TestMultitenantAdmin(BaseTestMultitenantAdmin): class TestUsers(BaseTestUsers): - # This task access the organizations_dict when user is created. # This makes the test fail because the cache is already populated. @patch('openwisp_notifications.tasks.update_superuser_notification_settings') From 7157a04948fad3cdb794bb67422ff978d7f7687a Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Wed, 31 Jul 2024 14:59:04 -0400 Subject: [PATCH 2/4] [ci] Combine coverage for different test runs --- .github/workflows/ci.yml | 7 +++---- pyproject.toml | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5762cbde..28dfbd168 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,6 @@ on: - master jobs: - build: name: Python==${{ matrix.python-version }} | ${{ matrix.django-version }} runs-on: ubuntu-24.04 @@ -56,7 +55,7 @@ jobs: id: deps run: | sudo apt update - sudo apt-get -qq -y install sqlite3 gdal-bin libproj-dev \ + sudo apt -qq -y install sqlite3 gdal-bin libproj-dev \ libgeos-dev libspatialite-dev spatialite-bin \ libsqlite3-mod-spatialite sudo npm install -g jshint stylelint @@ -75,10 +74,10 @@ jobs: # the following command runs tests with Postgres/PostGIS but # only for specific test cases which are tagged with "db_tests" POSTGRESQL=1 coverage run runtests.py --parallel --keepdb + # tests the extension capability + SAMPLE_APP=1 coverage run ./runtests.py --parallel --keepdb coverage combine coverage xml - # tests the extension capability - SAMPLE_APP=1 ./runtests.py --keepdb env: SELENIUM_HEADLESS: 1 diff --git a/pyproject.toml b/pyproject.toml index a3a5341f6..eb261c779 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,16 @@ +[tool.coverage.run] +source = ["openwisp_controller"] +parallel = true +concurrency = ["multiprocessing"] +omit = [ + "openwisp_controller/__init__.py", + "*/tests/*", + "*/migrations/*", +] + +[tool.docstrfmt] +extend_exclude = ["**/*.py", "README.rst"] + [tool.isort] known_third_party = ["django", "django_x509"] known_first_party = ["openwisp_users", "openwisp_utils"] @@ -7,18 +20,3 @@ multi_line_output = 3 use_parentheses = true include_trailing_comma = true force_grid_wrap = 0 - -[tool.coverage.run] -parallel = true -omit = [ - "**/test*", - "tests", - "**/__init__.py", - "setup.py", - "**/migrations/*" -] -source = ["openwisp_controller"] -concurrency = ["multiprocessing"] - -[tool.docstrfmt] -extend_exclude = ["**/*.py", "README.rst"] From f523b89b2aa7e186187a8435510000adb5e91c1e Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Wed, 31 Jul 2024 18:17:50 -0400 Subject: [PATCH 3/4] [chores] Updated setup.py --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index c7e57a5bb..74b609af0 100644 --- a/setup.py +++ b/setup.py @@ -43,9 +43,9 @@ def get_install_requires(): name="openwisp-controller", version=get_version(), license="GPL3", - author="Federico Capoano", - author_email="federico.capoano@gmail.com", - description="OpenWISP 2 Controller", + author="OpenWISP", + author_email="support@openwisp.io", + description="OpenWISP Controller", long_description=open("README.rst").read(), url="http://openwisp.org", download_url="https://github.com/openwisp/openwisp-controller/releases", @@ -56,7 +56,7 @@ def get_install_requires(): zip_safe=False, install_requires=get_install_requires(), classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Topic :: Internet :: WWW/HTTP', 'Topic :: System :: Networking', From 16a396a60dec301713abc05f8c694992e7043a3d Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Thu, 1 Aug 2024 13:50:45 -0400 Subject: [PATCH 4/4] [change] Removed support for deprecated settings --- openwisp_controller/config/settings.py | 67 ++++++++++---------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/openwisp_controller/config/settings.py b/openwisp_controller/config/settings.py index 01f79b5af..113347805 100644 --- a/openwisp_controller/config/settings.py +++ b/openwisp_controller/config/settings.py @@ -6,26 +6,11 @@ logger = logging.getLogger(__name__) -def get_settings_value(option, default): - if option == 'CONFIG_BACKEND_FIELD_SHOWN' and hasattr( - settings, 'OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST' - ): - logger.warn( - 'OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST is deprecated and will be ' - 'removed in the future, please use ' - 'OPENWISP_CONTROLLER_CONFIG_BACKEND_FIELD_SHOWN instead.' - ) - return getattr(settings, 'OPENWISP_CONTROLLER_BACKEND_DEVICE_LIST', default) - if hasattr(settings, f'NETJSONCONFIG_{option}'): - logger.warn( - f'NETJSONCONFIG_{option} setting is deprecated. It will be removed ' - f'in the future, please use OPENWISP_CONTROLLER_{option} instead.' - ) - return getattr(settings, f'NETJSONCONFIG_{option}') +def get_setting(option, default): return getattr(settings, f'OPENWISP_CONTROLLER_{option}', default) -BACKENDS = get_settings_value( +BACKENDS = get_setting( 'BACKENDS', ( ('netjsonconfig.OpenWrt', 'OpenWRT'), @@ -33,7 +18,7 @@ def get_settings_value(option, default): ), ) -VPN_BACKENDS = get_settings_value( +VPN_BACKENDS = get_setting( 'VPN_BACKENDS', ( ('openwisp_controller.vpn_backends.OpenVpn', 'OpenVPN'), @@ -42,21 +27,21 @@ def get_settings_value(option, default): ('openwisp_controller.vpn_backends.ZeroTier', 'ZeroTier'), ), ) -DEFAULT_BACKEND = get_settings_value('DEFAULT_BACKEND', BACKENDS[0][0]) -DEFAULT_VPN_BACKEND = get_settings_value('DEFAULT_VPN_BACKEND', VPN_BACKENDS[0][0]) -REGISTRATION_ENABLED = get_settings_value('REGISTRATION_ENABLED', True) -CONSISTENT_REGISTRATION = get_settings_value('CONSISTENT_REGISTRATION', True) -REGISTRATION_SELF_CREATION = get_settings_value('REGISTRATION_SELF_CREATION', True) +DEFAULT_BACKEND = get_setting('DEFAULT_BACKEND', BACKENDS[0][0]) +DEFAULT_VPN_BACKEND = get_setting('DEFAULT_VPN_BACKEND', VPN_BACKENDS[0][0]) +REGISTRATION_ENABLED = get_setting('REGISTRATION_ENABLED', True) +CONSISTENT_REGISTRATION = get_setting('CONSISTENT_REGISTRATION', True) +REGISTRATION_SELF_CREATION = get_setting('REGISTRATION_SELF_CREATION', True) -CONTEXT = get_settings_value('CONTEXT', {}) +CONTEXT = get_setting('CONTEXT', {}) assert isinstance(CONTEXT, dict), 'OPENWISP_CONTROLLER_CONTEXT must be a dictionary' -DEFAULT_AUTO_CERT = get_settings_value('DEFAULT_AUTO_CERT', True) -CERT_PATH = get_settings_value('CERT_PATH', '/etc/x509') -COMMON_NAME_FORMAT = get_settings_value('COMMON_NAME_FORMAT', '{mac_address}-{name}') -MANAGEMENT_IP_DEVICE_LIST = get_settings_value('MANAGEMENT_IP_DEVICE_LIST', True) -CONFIG_BACKEND_FIELD_SHOWN = get_settings_value('CONFIG_BACKEND_FIELD_SHOWN', True) +DEFAULT_AUTO_CERT = get_setting('DEFAULT_AUTO_CERT', True) +CERT_PATH = get_setting('CERT_PATH', '/etc/x509') +COMMON_NAME_FORMAT = get_setting('COMMON_NAME_FORMAT', '{mac_address}-{name}') +MANAGEMENT_IP_DEVICE_LIST = get_setting('MANAGEMENT_IP_DEVICE_LIST', True) +CONFIG_BACKEND_FIELD_SHOWN = get_setting('CONFIG_BACKEND_FIELD_SHOWN', True) -HARDWARE_ID_ENABLED = get_settings_value('HARDWARE_ID_ENABLED', False) +HARDWARE_ID_ENABLED = get_setting('HARDWARE_ID_ENABLED', False) HARDWARE_ID_OPTIONS = { 'blank': not HARDWARE_ID_ENABLED, 'null': True, @@ -65,22 +50,20 @@ def get_settings_value(option, default): 'verbose_name': _('Serial number'), 'help_text': _('Serial number of this device'), } -HARDWARE_ID_OPTIONS.update(get_settings_value('HARDWARE_ID_OPTIONS', {})) -HARDWARE_ID_AS_NAME = get_settings_value('HARDWARE_ID_AS_NAME', True) -DEVICE_VERBOSE_NAME = get_settings_value( - 'DEVICE_VERBOSE_NAME', (_('Device'), _('Devices')) -) -DEVICE_NAME_UNIQUE = get_settings_value('DEVICE_NAME_UNIQUE', True) -DEVICE_GROUP_SCHEMA = get_settings_value( +HARDWARE_ID_OPTIONS.update(get_setting('HARDWARE_ID_OPTIONS', {})) +HARDWARE_ID_AS_NAME = get_setting('HARDWARE_ID_AS_NAME', True) +DEVICE_VERBOSE_NAME = get_setting('DEVICE_VERBOSE_NAME', (_('Device'), _('Devices'))) +DEVICE_NAME_UNIQUE = get_setting('DEVICE_NAME_UNIQUE', True) +DEVICE_GROUP_SCHEMA = get_setting( 'DEVICE_GROUP_SCHEMA', {'type': 'object', 'properties': {}} ) -SHARED_MANAGEMENT_IP_ADDRESS_SPACE = get_settings_value( +SHARED_MANAGEMENT_IP_ADDRESS_SPACE = get_setting( 'SHARED_MANAGEMENT_IP_ADDRESS_SPACE', True ) -DSA_OS_MAPPING = get_settings_value('DSA_OS_MAPPING', {}) -DSA_DEFAULT_FALLBACK = get_settings_value('DSA_DEFAULT_FALLBACK', True) -GROUP_PIE_CHART = get_settings_value('GROUP_PIE_CHART', False) -API_TASK_RETRY_OPTIONS = get_settings_value( +DSA_OS_MAPPING = get_setting('DSA_OS_MAPPING', {}) +DSA_DEFAULT_FALLBACK = get_setting('DSA_DEFAULT_FALLBACK', True) +GROUP_PIE_CHART = get_setting('GROUP_PIE_CHART', False) +API_TASK_RETRY_OPTIONS = get_setting( 'API_TASK_RETRY_OPTIONS', dict(max_retries=5, retry_backoff=True, retry_backoff_max=600, retry_jitter=True), )