wiki:Nodewatcher/Registry/NodeConfiguration
Last modified 2 years ago Last modified on 11/04/2014 10:02:59 AM

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

The latest version of the nodewatcher configuration schema can be found in its documentation.

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
RoutableInterface
routing_protocol registered choice

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:
      # 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
        ) 
      )
      
      Where the value function would enable construction of lazy expressions that would be evaluated on rule execution.

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