Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: A New Concept for Gluon Config Generation #2238

Open
lemoer opened this issue Jun 13, 2021 · 9 comments
Open

RFC: A New Concept for Gluon Config Generation #2238

lemoer opened this issue Jun 13, 2021 · 9 comments

Comments

@lemoer
Copy link
Member

lemoer commented Jun 13, 2021

Hi all,

in the last days I have been working on a concept to improve the config generation of Gluon. Please give me some feedback on this concept. Since this concept is a very raw design, feel free to leave raw comments. Early feedback is more important than accurate feedback. So especially if you have concerns but no solutions yet, please raise the concerns.

Also please use the 👍/:eyes:/👎 to indicate your first gut feelings, whether this is going in the right direction:

  • 👍 = Most of this concept looks good to me.
  • 👀 = I appreciate your efforts, but I think some critical parts need to be discussed and maybe done differently.
  • 👎 = I appreciate your efforts, but the aims are completely outside of Gluon's objective.

Kind regards,
lemoer


A New Concept for Gluon Config Generation

Aims

  1. Provide a REST API to reconfigure nodes.
  2. Enable reconfiguration without reboot.
  3. Especially: Only restart as many daemons as necessary.
  4. Enable automatic reset of the configuration (if the user does not confirm that everything still works).

1. API Idea

  • Introduce a new config named local.json.
  • This new config file would contain all the device configurations made by the user.
    • Uci values are derived from local.json using scripts in /lib/gluon/upgrade/*.lua. (Similar to the site.json)
    • As the local.json is stored on the device, this means, that no values are stored exclusively in uci anymore.
    • But if desired, values can exclusively be stored in local.json.
  • JSON-Schema is used to verify this config.
    • Since gluon is modular, this JSON-schema must be assembled dynamically based on the installed packages.
    • Most likely, we can reuse the schema code from ECE. See docs here.
    • From now on, this is called local-schema.json.
  • REST API:
    • GET /local.json
    • POST /local.json
    • PUT /local.json
    • GET /local-schema.json
    • If the posted local.json is not matching the JSON-Schema, the firmware will reject it.
  • Config-Mode:
    • Discard the current config-mode approach and use: javascript app + REST API.
    • Use JSON-Editor (or something similar) to build the web-forms.
      • This Javascript-App is able to generate web forms based on a JSON-Schema automatically.
        • This can be done based on the schema local-schema.json.
      • Size: ~80 KB (minified & gzipped)
      • Link to Example using JSON-Editor
    • Perform an HTTP POST or PUT with a complete local.json.
  • Migration:
    • In case, a gluon package changes the way it stores data to the local.json, the upgrade scripts in /lib/gluon/upgrade/*.lua need to take care of this and migrate the old local.json to the new local.json.
    • The migrated local.json MUST match with the JSON-Schema of the new firmware.
    • TO BE DISCUSSED: What happens, if it does not? Rejecting the local.json it is not possible, because we have no ability to interact with the user during the migration.
  • Verification and the derivation of uci config would be separated:
    • Verification of the local.json would be done using JSON-Schema.
    • Uci config are derived using scripts in /lib/gluon/upgrade/*.lua
  • This concept has also other benefits:
    • Moving the configuration of a node to new hardware becomes easier.
      • If a user wants to move the his configuration to new hardware, the local.json can be used for this purpose:
      • Simply export the local.json from the old node and then import it to the new node.
    • Maybe we can use JSON-Schema also to check the site.conf one day.
    • In case, we introduce "pre-configured images" #2172, the local.json could be used to implement this.
    • We can eliminate the situation where some uci values are used to generate other uci values. Such cyclic dependencies are not very transparent. A clear data flow direction is preferable.
  • Potential problems:
    • Some config-mode pages depend on the sysconfig or on the site.conf?
  • TO BE DISCUSSED: Which REST API Technology? There are two options:
    • gluon-web based REST API
    • ubus and rpcd based REST API

2. Allowing Reconfiguration without Reboot

  • The gluon-reload framework already exists.
  • Before this concept, however, all daemons are restarted by gluon-reload. This is exhausting.
    • For example, it causes a VPN reconnect even if the VPN configuration has not changed. This causes the TQ for the mesh VPN connection to drop to zero. Since the TQ is slow to rise again, this causes a connection failure of about 30 seconds.
  • To change this, the following steps will be implemented to apply a config change:
    1. The new local.json is stored in /var/gluon/local-new.json.
    2. gluon-reconfigure is executed to generate the new uci configs.
      • uci:commit() is not yet called here!
    3. Call gluon-reload:
      • gluon-reload will use uci changes to see which uci configs/uci sections are changed.
      • From that, it will only restart the necessary daemons.
    4. Persist the config:
      1. If the user has confirmed, that the device is still working:
        • uci:commit() is called.
        • The old local.json is replaced by the new local-new.json.
      2. If the user hasn't confirmed, that the device is still working after 30s:
        • uci:revert() is called.
        • The old local-new.json is deleted.
      3. If the device has a power outage during that time:
        • The old config state is automatically recovered, as nothing has been written to the flash yet.
@lemoer lemoer changed the title Concept: Gluon Config Generation A New Concept for Gluon Config Generation Jun 13, 2021
@lemoer lemoer changed the title A New Concept for Gluon Config Generation RFC: A New Concept for Gluon Config Generation Jun 13, 2021
@AiyionPrime
Copy link
Member

http://netjson.org/#third ?

I have mixed feelings regarding an ever open API.

Mandatory relying on Javascript for the configmode is likely raising the hurdle for not just a few users.

I like a lot about the goal of part two though.

@lemoer
Copy link
Member Author

lemoer commented Jun 15, 2021

http://netjson.org/#third ?

The scope of Netjson is very different from the current Gluon configuration approach. Netjson is a low-level definition of device configuration. The level of detail of Netjson is on par with the OpenWrt uci config. In fact, you can represent almost any possible OpenWrt router configuration in Netjson. In Gluon, we have a different approach. We only allow high-level configuration options like Is MeshOnWAN active?. Low-level configuration is derived in an automated way from the high-level configuration, and directly changing the low-level configuration is explicitly unsupported.

This has two advantages:

  • The Gluon firmware is easy to use even for non-technical people.
  • We are able to provide unattended upgrades.

If we were to open the way for low-level configuration and officially support it, I think Gluon would become a maintenance hell.

I have mixed feelings regarding an ever open API.

I would like to postpone the discussion of this concern to a later date. This API does not have to be made openly accessible. There are many technical ways to protect it: using HTTPS, SSH tunneling, enabling the API only in configuration mode, exposing it only on a special Lan port, ... However, for the implementation of the API itself, this is not important for now. You can always just put security in front of an HTTP API.

Mandatory relying on Javascript for the configmode is likely raising the hurdle for not just a few users.

In fact, this is one of the choices to be made. The other option would be to add the REST API as an additional way to configure the node besides the existing config-mode. But then we would have to maintain two separate ways to configure a device. In my opinion, this should be avoided.

@neocturne
Copy link
Member

  • I think this proposal contains at least two different ideas that should be discussed separately. Allowing runtime reconfiguration is orthogonal to the move to a REST API. JSON config storage could be seen as a third proposed change.
  • Replacing the config mode with a SPA + API sounds like a good idea to me. If we can improve usability, I don't have any issues with sacrificing the half-broken functionality our config mode currently provides without JS.
  • Storing all user configuration in a single place sounds good to me (whether that means a single file or one file per package/feature/subsystem remains to be discussed - not having UCI as the primary source would be an improvement IMO, but we need a story for console-based configuration via SSH)
  • Allowing reconfiguration without a reboot seems risky to me, and I don't think there is much value in reducing daemon restarts if it increases code complexity. The save/revert/commit to test configuration would increase our use of UCI again.
  • I like our security model of requiring physical access to change the configuration

@lemoer
Copy link
Member Author

lemoer commented Aug 4, 2021

Okay, you are right. That there are orthogonal ideas. I would like to focus on the REST API idea first.

Some Requirements for the REST API:

  • REQ1: Packages must be able to add configuration options.
  • REQ2: The available configuration options may depend on additional conditions. (E.g. on hardware, site config, ...).
  • REQ3: Versioning. Always add a version number to your REST APIs.
  • REQ4: The user of the API should be able to discover the available configuration options in an automated manner.

Especially REQ4 is challenging to realize, incorporating all the possibilities resulting from REQ1, REQ2 and REQ3. Even more, if we intend to provide a somewhat intuitive API.

"Nice To Haves" (NTH) for the REST API:

  • NTH1: A single API resource (JSON object) representing the whole configuration of the router.
    • (To those of you, which are not familiar with the REST jargon: API resource = URL)
    • I suspect, this will simplify the code in the SPA.
    • This resource could be downloaded as a "backup" of the router. And maybe it could be restored one day.
    • Of course, packages add configuration options, so it may appeal to assign an individual API resource to each package.
      • I doubt, that the assignment package <-> resource would make sense at all. There may be inter-dependencies between packages, or packages would want to add configuration options to other packages resources or so.
      • Furthermore there are not only conditional config options due to REQ1, but also due to REQ2.
    • While it makes sense to discuss the orthogonal ideas orthogonal to each other, it is still worth mentioning that there are points of contact. If we decide that the "json config storage" idea is a good idea, the json object from the REST API could directly be saved to disk (after verification).
  • NTH2: A standardized way to fulfill REQ4.
    • NTH2a: One way to realize this would be to provide a json-schema.
      • An advantage of this would be, that a potential SPA could directly derive other aspects (like value types, etc.) from the schema as well.
      • If we add a json-schema implementation to gluon, we could also use this schema for the verification of the config.
      • A disadvantage would be, that this schema would have to be merged from multiple packages.
    • NTH2b: Another way would be, to define a first level information, which contains the "featureset" of the particular router. (This could be implemented using a json array like: { ..., "featureset": ["has_fastd", "has_lan_port", ...] }.)
      • An implication of this way would be, that conditional configuration options could only depend on the "featureset".
      • I am not sure, if all conditional configuration options from REQ1 and REQ2 could be described by a "featureset". (Please comment on this!)

My Current Feeling

Currently I tend towards implementing NTH1 and NTH2b and towards using something similar to the check_site.lua framework for the verification of the config.

What I Need From You

  • Please comment on the idea.
  • Did I miss requirements?
  • Are there other NTH, that you desire?
  • Should I go ahead?
  • Is my reasoning understandable?
  • Are there any other aspects, which are worth mentioning in that context?
  • What do you think about "my current feeling"?

@lemoer
Copy link
Member Author

lemoer commented Aug 6, 2021

I just created an example how a single JSON resource could look like. It is based on a current image from Freifunk Hannover. The JSON structure is oriented to the current structure of the config-mode web interface. This example can be used for discussion. It gives an overview of which config options we currently support in the web interface.

EDIT: Some options have been added.

{
	"wizard": {
		"hostname": "freifunk-foobar",
		"mesh-vpn": {
			"enabled": true,
			"bandwidth_limit": {
				"enabled": true,
				"up": 40000,
				"down": false
			}
		},
		"domain": "burgdorf",
		"location": {
			"share_location": true,
			"lat": 57.0912121,
			"lon": 10.2121211,
			"altitude": 2.332
		},
		"contact": "[email protected]",
		"is_outdoor_device": false
	},
	"advanced": {
		"remote-access": {
			"password": "1337",
			"ssh-keys": [
				"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK4qBzYhG0oXJCAVr5Bgh9dJ2ZqgzsB9oTGZlBn5ZIjO lemoer@orange",
				"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK4qBzYhG0oXJCAVr5Bgh9dJ2ZqgzsB9oTGZlBn5ZIjO lemoer@orange"
			]
		},
		"autoupdates": {
			"enabled": true,
			"branch": "stable",
			"minute": 23
		},
		"private-wifi": {
			"enabled": true,
			"ssid": "my-very-clever-ssid",
			"key": "das-ist-mein-cleveres-passwort",
			"encryption": "wpa2",
			"management-frame-protection": false
		},
		"wifi-radios": {
			"2-4GHz": {
				"mesh_enabled": true,
				"client_enabled": false,
				"tx_power_dbm": 13.0
			},
			"5GHz": {
				"mesh_enabled": true,
				"client_enabled": false,
				"tx_power_dbm": 13.0,
				"outdoor_htmode": "default"
			}
		},
		"network": {
			"wan": {
				"ipv4": {
					"config": "static",
					"ip": "192.168.0.123",
					"netmask": "255.255.255.0",
					"gateway": "192.168.0.1"
				},
				"ipv6": {
					"config": "automatic"
				},
				"dns_servers": ["8.8.8.8", "1.1.1.1"]
			},
			"mesh_on_lan": true,
			"mesh_on_wan": false
		},
		"logging": {
			"enabled": true,
			"ip": "192.168.0.1",
			"port": 514
		},
		"mesh-vpn": {
			"security": "performance"
		},
		"node-role": "Offloader"
	}
}

@lemoer
Copy link
Member Author

lemoer commented Aug 7, 2021

I am currently preparing a table of external dependencies of the json structure. This will probably help to make decisions. I think I will be able to post this on sunday.

@lemoer
Copy link
Member Author

lemoer commented Aug 8, 2021

I finished the two tables. Please see below. In general, the options are referenced by their JSON path in the (updated) JSON structure above. However, the tables are based on the code in the current gluon-config-mode-* and gluon-web-* packages. Therefore the tables below represent the status quo of the dependencies of the options in the config mode in gluon.

These tables should provide an overview of the complexity of the json config. They can be used to make design decisions for the API.

I will post some questions, on which we need to decide (in my opinion) later on.

External Dependencies of the JSON structure

# Package Dependency Type Option(s) Description
E1 gluon-config-mode-autoupdater Package may not be installed. No influence on config.
E2 gluon-config-mode-autoupdater Autoupdater is enabled/enabled. Shows a message in the wizard or not.
E3 gluon-config-mode-contact-info Package may not be installed. wizard.contact Option is not available.
E4 gluon-config-mode-domain-select Package may not be installed. wizard.domain Option is not available.
E5 gluon-config-mode-domain-select Dependency to site.conf. wizard.domain Available choices depend on site.conf.
E6 gluon-config-mode-geo-location Package may not be installed. wizard.location.* Options are not available.
E7 gluon-config-mode-geo-location Dependency to site.conf. wizard.location.altitude Option can be disabled in site.conf
E8 gluon-config-mode-mesh-vpn Package may not be installed. wizard.mesh_vpn.* Options are not available.
E9 gluon-config-mode-mesh-vpn VPN is enabled/disabled. Shows the pubkey in the reboot page or not.
E10 gluon-config-mode-outdoor Package may not be installed. wizard.is_outdoor_device Option is not available.
E11 gluon-config-mode-outdoor Dependency to Hardware. wizard.is_outdoor_device Option is not available, depending if the device supports outdoor frequencies (or so…)
E12 gluon-config-mode-outdoor Dependency to UCI value. wizard.is_outdoor_device Option is not available, depending if the uci option preserve_channels is set.
E13 gluon-web-admin Package may not be installed. advanced.remote_access.* Options are not available.
E14 gluon-web-admin Dependency to site.conf. advanced.remote_access.password Option can be disabled in site.conf.
E15 gluon-web-autoupdater Package may not be installed. advanced.autoupdater.* Options are not available.
E16 gluon-web-autoupdater Dependency to site.conf. advanced.autoupdater.branch Available choices for option depend on site.conf.
E17 gluon-web-logging Package may not be installed. advanced.logging.* Options are not available.
E18 gluon-web-mesh-vpn-fastd Package may not be installed. advanced.mesh-vpn.security Option is not available.
E19 gluon-web-network Package may not be installed. advanced.network.* Options are not available.
E20 gluon-web-network Dependency to UCI value. advanced.network.dns_servers Option is not available, depending if the uci config gluon-wan-dnsmasq.static is available.
E21 gluon-web-node-role Package may not be installed. advanced.node-role Options are not available.
E22 gluon-web-node-role Dependency to site.conf. advanced.node-role Available choices depend on site.conf.
E23 gluon-web-private-wifi Package may not be installed. advanced.private-wifi.* Options are not available.
E24 gluon-web-private-wifi Dependency to Hardware. advanced.private-wifi.encryption Available choices depend on the hardware platform.
E25 gluon-web-private-wifi Dependency to Hardware. advanced.private-wifi.management-frame-protection Available choices depend on the hardware platform.
E26 gluon-web-wifi-config Package may not be installed. advanced.wifi-radios.* Options are not available.
E27 gluon-web-wifi-config Dependency to Hardware. (Or UCI) advanced.wifi-radios.2-4GHz.* Options may not be available depending on the hardware.
E28 gluon-web-wifi-config Dependency to Hardware. (Or UCI) advanced.wifi-radios.5GHz.* Options may not be available depending on the hardware.
E29 gluon-web-wifi-config Dependency to Hardware. (Or UCI) advanced.wifi-radios.* Actually there may be more than one radio for each frequency, so advanced.wifi-radios.* must be somewhat different!
E30 gluon-web-wifi-config Dependency to Hardware. advanced.wifi-radios.*.tx_power Available choices depend on the hardware platform.
E31 gluon-web-wifi-config Dupplicate option. wizard.is_outdoor_device The option wizard.is_outdoor_device is also shown here.
E32 gluon-web-wifi-config Dependency to Hardware. advanced.wifi-radios.5GHz.outdoor_htmode Available choices depend on the hardware.

Internal Dependencies of the JSON structure

# Package Option (only allowed if) Condition
I1 gluon-config-mode-geo-location wizard.location.lat wizard.location.lon must be set.
I2 gluon-config-mode-geo-location wizard.location.lon wizard.location.lat must be set.
I3 gluon-config-mode-geo-location wizard.location.altitude wizard.location.{lon,lan} must be set both.
I4 gluon-config-mode-mesh-vpn wizard.mesh-vpn.bandwidth_limit.* wizard.mesh-vpn.enabled must be true.
I5 gluon-web-network advanced.network.wan.ipv4.ip advanced.network.wan.ipv4.config must be „static“
I6 gluon-web-network advanced.network.wan.ipv4.netmask advanced.network.wan.ipv4.config must be „static“
I7 gluon-web-network advanced.network.wan.ipv4.gateway advanced.network.wan.ipv4.config must be „static“
I8 gluon-web-network advanced.network.wan.ipv6.ip advanced.network.wan.ipv6.config must be „static“
I9 gluon-web-network advanced.network.wan.ipv6.netmask advanced.network.wan.ipv6.config must be „static“
I10 gluon-web-network advanced.network.wan.ipv6.gateway advanced.network.wan.ipv6.config must be „static“
I11 gluon-web-private-wifi advanced.private-wifi.ssid advanced.private-wifi.enabled must be true.
I12 gluon-web-private-wifi advanced.private-wifi.key advanced.private-wifi.enabled must be true.
I13 gluon-web-private-wifi advanced.private-wifi.encryption advanced.private-wifi.enabled must be true.
I14 gluon-web-private-wifi advanced.private-wifi.management-frame-protection advanced.private-wifi.enabled must be true.
I15 gluon-web-wifi-config advanced.wifi-radios.5GHz.mesh_enabled wizard.is_outdoor_device must be false.
I16 gluon-web-wifi-config advanced.wifi-radios.5GHz.outdoor_htmode wizard.is_outdoor_device must be true.

@lemoer
Copy link
Member Author

lemoer commented Aug 10, 2021

Summary of the External Dependencies

  • The available options vary due to external dependencies:
    • Due to installed packages (E3, E4, E6, E8, E10, E13, E15, E17, E18, E19, E21, E23, E26)
    • Due to site.conf (E7, E14)
    • Due to hardware (E11, E27, E28)
    • Due to UCI settings (E12, E20)
  • For some options, the available choices (in dropdowns) vary due to external dependencies:
    • Due to site.conf (E5, E16, E22)
    • Due to hardware (E24, E25, E30, E32)

@lemoer
Copy link
Member Author

lemoer commented Aug 12, 2021

Based on all the (hard to digest) data here, I created #2296. The REST API can be discussed there. I hope things are less abstract based on the proposal in #2296.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants