Configuration Registry
This page is for future nodewatcher version currently in development.
Configuration registry is a registry framework registration point node.config. It enables modular and extensible node configuration.
All registry item class names in this schema must end in Config.
Core Schema
We should describe a core registry schema that will be available in the core.* module set. For explanation of some common terms, please see nodewatcher terminology.
| REGISTRY ID | MULTIPLE | CLASS | FIELD | TYPE | |
| core.general | no | ||||
| GeneralConfig | |||||
| name | string | ||||
| type | registered choice | ||||
| CgmGeneralConfig (GeneralConfig) | |||||
| router | registered choice | ||||
| platform | registered choice | ||||
| version | foreign key | ||||
| core.project | no | ||||
| ProjectConfig | |||||
| project | foreign key | ||||
| core.location | no | ||||
| LocationConfig | |||||
| address | string | ||||
| city | registered choice | ||||
| country | registered choice | ||||
| geolocation | geospatial | ||||
| altitude | float | ||||
| core.routerid | yes | ||||
| RouterIdConfig | |||||
| family | registered choice | ||||
| router_id | string | ||||
| core.authentication | yes | ||||
| AuthenticationConfig (hidden registry anchor) | |||||
| PasswordAuthenticationConfig (AuthenticationConfig) | |||||
| password | string | ||||
| PublicKeyAuthenticationConfig (AuthenticationConfig) | |||||
| public_key | string | ||||
| core.roles | yes/static | ||||
| RoleConfig (hidden registry anchor) | |||||
| SystemRoleConfig (RoleConfig) | |||||
| system | boolean | ||||
| BorderRouterRoleConfig (RoleConfig) | |||||
| border_router | boolean | ||||
| VpnServerRoleConfig (RoleConfig) | |||||
| vpn_server | boolean | ||||
| RedundancyRequiredRoleConfig (RoleConfig) | |||||
| redundancy_required | boolean | ||||
| core.interfaces | yes | ||||
| InterfaceConfig (hidden registry anchor) | |||||
| enabled | boolean | ||||
| EthernetInterfaceConfig (InterfaceConfig) | |||||
| eth_port | registered choice (depends on router model) | ||||
| WifiInterfaceConfig (InterfaceConfig) | |||||
| wifi_radio | registered choice (depends on router model) | ||||
| protocol | registered choice (depends on radio) | ||||
| channel | registered choice (depends on protocol) | ||||
| channel_width | registered choice (depends on protocol) | ||||
| bitrate | registered choice (depends on protocol) | ||||
| rts_threshold | integer | ||||
| frag_threshold | integer | ||||
| antennas | related field (ConnectedWifiAntenna) | ||||
| EquippedWifiInterfaceConfig (WifiInterfaceConfig) (#944) | |||||
| equipment | many to many | ||||
| VpnInterfaceConfig (InterfaceConfig) | |||||
| mac | mac string (auto-generated) | ||||
| core.basic_addressing | yes | ||||
| only if core.cgm module is not enabled; otherwise replaced by core.interfaces.network allocators | |||||
| BasicAddressingConfig (IpAddressAllocator) | |||||
| core.interfaces.network | yes | ||||
| NetworkConfig (hidden registry anchor) | |||||
| enabled | boolean | ||||
| interface | intra-registry foreign key (core.interfaces) | ||||
| name | string | ||||
| StaticNetworkConfig (NetworkConfig) | |||||
| only available for EthernetInterfaceConfig entries | |||||
| address | ip address | ||||
| gateway | ip address | ||||
| AllocatedNetworkConfig (IpAddressAllocator, NetworkConfig) | |||||
| only available for EthernetInterfaceConfig entries | |||||
| DhcpNetworkConfig (NetworkConfig) | |||||
| only available for EthernetInterfaceConfig entries | |||||
| PppoeNetworkConfig (NetworkConfig) | |||||
| only available for EthernetInterfaceConfig entries | |||||
| username | string | ||||
| password | string | ||||
| WifiNetworkConfig (IpAddressAllocator, NetworkConfig) | |||||
| only available for WifiInterfaceConfig entries | |||||
| role | registered choice (mesh, users, backbone-ap, backbone-sta) | ||||
| mode | registered choice (depends on role and radio) | ||||
| essid | registered choice (depends on role) | ||||
| bssid | registered choice (depends on role) | ||||
| core.interfaces.limits | yes | ||||
| InterfaceLimitConfig (hidden registry anchor) | |||||
| enabled | boolean | ||||
| interface | intra-registry foreign key (core.interfaces) | ||||
| ThroughputInterfaceLimitConfig (InterfaceLimitConfig) | |||||
| limit_in | registered choice | ||||
| limit_out | registered choice | ||||
| core.servers.dns | yes | ||||
| DnsServerConfig | |||||
| address | ip address | ||||
| core.servers.time | yes | ||||
| TimeServerConfig | |||||
| protocol | registered choice | ||||
| address | ip address | ||||
| port | integer | ||||
| core.servers.vpn | yes | ||||
| VpnServerConfig | |||||
| protocol | registered choice | ||||
| address | ip address | ||||
| port | integer | ||||
| core.packages | yes | ||||
| PackageConfig (hidden registry anchor) | |||||
| enabled | boolean | ||||
| each package provides its own config class | |||||
For explanations of exotic types see registry types.
TODO:
- firewall
Auxilary Models
Models
Some models are not part of the registry (because they are not node-bound) but are referenced by registry items via foreign keys. Their schema is detailed below:
| MODEL | FIELD | TYPE | |
| cgm.Antenna | |||
| name | string | ||
| manufacturer | registered choice | ||
| internal_for | registered choice | ||
| internal_id | string | ||
| url | url | ||
| frequency_minimum | integer (-3dB cutoff) | ||
| frequency_maximum | integer (-3dB cutoff) | ||
| polarizations | many to many (AntennaPolarization) | ||
| connected_to | related field (ConnectedWifiAntenna) | ||
| cgm.AntennaPolarization | |||
| polarization | choice (vertical, horizontal, left circular, right circular) | ||
| angle_horizontal | integer (-3dB angle) | ||
| angle_vertical | integer (-3dB angle) | ||
| radiation_pattern | radiation pattern | ||
| tilt | float (down is negative) | ||
| gain | float | ||
| swr | float | ||
| cgm.ConnectedWifiAntenna (polymorphic) | |||
| interface | foreign key (WifiInterfaceConfig) (related name antennas) | ||
| antenna | foreign key (Antenna) (related name connected_to) | ||
| azimuth | float | ||
| elevation_angle | float (down is negative) | ||
| rotation | float (counterclockwise is positive, 0 for no rotation) | ||
| cgm.EquippedConnectedWifiAntenna (ConnectedWifiAntenna) (#944) | |||
| equipment | many to many | ||
| core.allocation.pool.IpPool (PoolBase) | |||
| family | choice (ipv4, ipv6) | ||
| network | ip network | ||
| prefix_length | integer | ||
| status | choice (free, full, partial) | ||
| name | string | ||
| prefix_length_default | integer | ||
| prefix_length_minimum | integer | ||
| prefix_length_maximum | integer | ||
Abstract Models
| MODEL | FIELD | TYPE | |
| core.allocation.AddressAllocator | |||
| usage | registered choice (primary, additional) | ||
| core.allocation.IpAddressAllocator (AddressAllocator) | |||
| family | choice (ipv4, ipv6) | ||
| pool | foreign key (IpPool) | ||
| prefix_length | integer | ||
| subnet_hint | ip address | ||
| allocation | foreign key (IpPool) | ||
| core.allocation.pool.PoolBase | |||
| parent | foreign key (self) | ||
| projects | many to many (Project) | ||
| allocation_owner | generic | ||
| allocation_timestamp | datetime | ||
Optional Schema
| REGISTRY ID | MULTIPLE | CLASS | FIELD | TYPE | |
| description | no | ||||
| DescriptionConfig | |||||
| notes | text | ||||
| url | url | ||||
| equipment | no | ||||
| EquipmentConfig (#944) | |||||
| equipment | many to many | ||||
| sensors | yes | ||||
| SensorConfig (hidden registry anchor) | |||||
| shown | boolean | ||||
| serial | string | ||||
| description | text | ||||
| TemperatureSensorConfig (SensorConfig) | |||||
| VoltageSensorConfig (SensorConfig) | |||||
| CurrentSensorConfig (SensorConfig) | |||||
| SolarSensorConfig (SensorConfig) | |||||
| each sensor provides its own config class | |||||
Use Cases
At least the following use cases must be easily handled by the configuration registry framework:
- Regulatory Domains
- A regulatory domain is a set of limits applied over all node's radio sections and it limits channels. For example, node maintainers with HAM license can have different channels available than others.
- Projects
- An ability to define a project (group of nodes) set of defaults that are applied to configuration items.
- Router Types
- Router types may have their own sets of defaults, for example related to multiple radios. Or switch layout.
- Platforms
- Platforms (SDKs/toolchains/OSes) may have their own sets of defaults. Not all router types have all platforms and not all platforms have all router types.
- Antennas
- Antenna selections may have their own sets of defaults.
- Routers with Exchangeable WiFi Cards
- Some routers can have exchangeable WiFi cards, like miniPCI. So defaults should be applied based on the selected miniPCI card and not based on the router type itself. Similar should be possible also for other hardware components (SD cards, cameras, sensors ...).
- Optional Packages
- User could select optional packages which could define additional configuration options and thus additional defaults.
- Geography
- Based on location of the node some defaults (and also regulatory domain) could be defined. Other examples are IP pools based on location (some countries have divided IPs based on geography).
- Node Types
- Different node types: backbone, mesh, AP. Supporting clients or not.
- Broken Hardware
- Sometimes some part of a router does not work anymore properly. For example WAN port is an example of this. Or diversity chip (so only one antenna is selected). So this is an example of per-node configuration options overrides.
- Ad-hoc vs. AP
- Some WiFi cards/drivers support both ad-hoc and AP at the same time. Some do not. Some do not support ad-hoc very well. So based on chosen hardware (router type or WiFi card) configuration options presented to user should change. So if everything can be supported then user should be able to choose ad-hoc only, AP only or mixed mode operation. Or in other cases those options should be limited accordingly.
- Support for virtual SSIDs
- Sometimes we would want to have multiple SSIDs on nodes, one for the local organization hosting nodes. It would be maybe then also useful to have different configuration for those SSIDs (like encrypted network, separate IP pools, connected directly into the LAN, without VPN).
- LAN only nodes
- Some nodes have only LAN interface and do not have integrated WiFi.
- Registration of IPs in subnets
- It should be possible to allocate IPs in subnets to particular devices attached to the node. Those IPs should not be given to clients but just those devices.
- IP address/subnet renumbering
- Sometimes it is necessary (or you would like) to renumber allocated IPs/subnets.
As nodewatcher can be extended by plugins, also this framework should support new use cases (and configuration options and defaults) provided by plugins.
How will permissions integrate in all this?
Maybe all configuration could be seen as selection of (dummy) packages, which provide options and defaults?
Regulatory Domains
This is handled by registry item inheritance where superclasses contain all options and then subclasses can limit them. And also define additional model/form fields.
Router Types
All firmware-specific capabilities will be validated by the router-specific configuration generating modules (CGMs). This includes things like support for multiple radios. GUI hinting is possible through router-metadata registration in CGMs.
Should we make router type hierarchical? For example, have options and default for WiFi modules and ethernet switches, which would then be linked with a given router type. So that all router types with a given ethernet switch layout would share the same options and defaults?
Features
- Automatic generation of forms based on available options and defaults. (Using Django's ModelForm approach if possible.)
- Do-not-repeat-yourself approach to validation of selected values. Fast failing in cases of validation failure.
- Automatic/dynamic opening/closing of new options based on combination of selected other options.
This automatic behavior means mostly that all this should be made in a generic way so that users/programmers do not need to reimplement things to get such behavior. And that it can be achieved with some simple definitions and not code itself.
Should we also support clients/browsers without JavaScript? According to progressive enhancement idea?
Rules
The configuration system needs to be able to apply partial configuration options. This is because the following is a realistic scenario for a set of defaults:
# Defaults if supported_radios >= 1: radios[0].role = "endusers" radios[0].essid = "open.wlan-si.net" radios[0].bssid = "02:CA:FF:EE:BA:BE" if supported_radios >= 2: radios[1].role = "mesh" radios[1].essid = "backbone.wlan-si.net" radios[1].bssid = "03:CA:FF:EE:BA:BE" # Per-project rules if project == Projects.Ljubljana: # Override defaults, we want wlan-lj.net if supported_radios >= 1: radios[0].essid = "open.wlan-lj.net" if supported_radios >= 2: radios[1].essid = "backbone.wlan-lj.net"
Note that all rules need to be applied when changing a project or changing the router type (with different number of supported radios) as it changes the defaults.
Rules should support throwing an exception if some combination should not be allowed (is disabled).
Script-Based Solution (Python)
This proposal is being implemented in registry branch, see code for details.
The most flexible solution that would not introduce complex tree structures is to specify such rules as Python scripts in a manner similar to the above. These rules would then be evaluated when specific fields change and new configuration defaults would be preset in the GUI. These rules can also easily incorporate hints from modules like the above mentioned equipment warehouse or from any other modules that are installed in local nodewatcher installation.
Such rules could then simply be saved into a rules.py configuration file that would be imported in the proper scope when evaluating rules.
Showstoppers:
- This soulution does not provide condition-action separation which is needed because one would like to determine if a certian action list should be evaluated again when changing some attribute's value via a frontend form. This is to avoid re-evaluting all the rules whenever any attribute changes.
- We could use functional-like style to write this using custom functions instead of Python statements:
Where the value function would enable construction of lazy expressions that would be evaluated on rule execution.
# Alias definitions project = "core.general#project" supported_radios = "core.general#equipment.supported_radios" radios = "core.radio" vpn = "core.vpn.server" # Defaults rule(changed(supported_radios), clear_config(radios) ) rule(value(supported_radios) >= 1, append(radios, role = "endusers", essid = "open.wlan-si.net", bssid = "02:CA:FF:EE:BA:BE" ) ) rule(value(supported_radios) >= 2, append(radios, role = "mesh", essid = "backbone.wlan-si.net", bssid = "03:CA:FF:EE:BA:BE" ) ) # Per-project rules rule(value(project) == "Ljubljana", # Override defaults, we want wlan-lj.net rule(value(supported_radios) >= 1, assign(radios, 0, essid = "open.wlan-lj.net") ), rule(value(supported_radios) >= 2, assign(radios, 1, essid = "backbone.wlan-lj.net") ), clear_config(vpn), append(vpn, protocol = "openvpn", hostname = "127.0.0.1", port = 9999 ), append(vpn, protocol = "openvpn", hostname = "127.0.0.2", port = 9999 ) )
- We could use functional-like style to write this using custom functions instead of Python statements:
In addition to rules, this implementation supports dynamic forms, where modules can define how to render fields based on current configuration values. This enables a great amount of flexibility.
The following use cases are covered by this implementation:
- Projects
- This implementation enables application of partial configuration options depending on project type.
- Router Types
- Rules can use additional attributes defined by other modules (such as the number of supported radios that will be available only with the warehouse module, but not before). As rules can be nested, we can support hierarchies if needed.
- Platforms
- Same as for projects.
- Antennas
- Same as for router types.
- Geography
- Same as for projects.
- Node Types
- Same as for projects.
- Routers with Exchangeable WiFi Cards
- This implementation supports flexible forms, so this should be possible. Requires #944.
- Broken Hardware
- Same as for routers with exchangeable WiFi cards.
- Ad-hoc vs. AP
- Same as for routers with exchangeable WiFi cards.
- Optional Packages
- Supported via multiple configuration options and hidden top-level registry items.
The following use cases are currently NOT covered by this implementation:
N/A
