Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Improve the Plugin Usage and Configuration Experience #3562

Closed
PhilippGackstatter opened this issue Nov 19, 2020 · 4 comments
Closed

Improve the Plugin Usage and Configuration Experience #3562

PhilippGackstatter opened this issue Nov 19, 2020 · 4 comments

Comments

@PhilippGackstatter
Copy link
Contributor

As I got back into working on Elektra, I rediscovered some quality of life issues with kdb. Elektra helps users configure their software with more safety and checks and kdb is supposed to help developers configure and use Elektra itself, safely and checked. Yet, I feel like it's not doing the best job it could be doing. I want to show some areas related to the usage and configuration of plugins, where I think the user experience could be improved.

Mounting plugins

Users don't want to deal with mounting plugins, they simply want to use them.

If a user wants to mount a file into the key database, in the majority of cases, all they should have to give to kdb mount is the path to the file and the path to the mountpoint. Making users specify exactly which plugins they need to mount the file itself and also which ones they want to use later, is quite cumbersome. They might not necessarily know which checks they want to perform later. Basically, two - from the user perspective - unrelated parts, mounting and plugins, are cobbled together into a single command.

So simply put, I think that in the majority of cases, it should be enough to do

kdb mount myfile.toml user/test/toml

and have kdb mount my file (or I wish that was the behavior) into the key database using the toml plugin. Right now if I do this, it defaults to the dump plugin. Based on the file extension kdb mount could easily determine a default plugin for toml, json, and many other popular file formats for which there is a good default plugin. That would make many kdb mount invocations easier. For some cases like mounting /etc/hosts or when the usage of a specific storage plugin is desired, the command can still take a plugin name as an optional argument.

That's only half the story though. More importantly, anything other than storage plugins shouldn't have to be mounted. There may be a technical reason for this that I am unaware of, but from a pure user perspective, I would simply like to do:

kdb mount myfile.toml /tests/toml # would default to toml plugin
kdb set /tests/toml/key value
kdb meta-set /tests/toml/key type string

and get instant validation from the type plugin. It makes mounting easier because the user doesn't have to think ahead about what they might want to do later. And they have instant access to all plugins. The plugins therefore need to be mounted on-demand. My proposal in the following section could enable this cleanly.

Plugin Configuration

Currently, users who want to use a plugin have to lookup the documentation and learn about, sometimes complicated syntaxes. Ideally, we can make configuring a bit more interactive and easier.

A fairly simple validation plugin like ipaddr needs to be enabled like this

kdb meta-set /tests/ipaddr/ipv4 check/ipaddr ""

The user needs to lookup the exact syntax, i.e. check/ipaddr in the documentation. To be fair, the check/<plugin_name> syntax is (afaik) standard across all validation plugins. One additional weirdness is having to set an "", when all the user wants to do is enable the plugin. (There are a number of other plugins where this is the case, rgbcolor, macaddr, and likely more).

At the same time, setting a nonsensical value

kdb meta-set /tests/ipaddr/ipv4 check/ipaddr ipv8

doesn't throw an error, because it is technically the same as the example above. However, a user executing this should probably get an error, or at least a warning.

Things get worse, as the plugin's complexity increases. Take specifying enums through the type plugin for instance:

kdb meta-set user/tests/type/multivalue check/enum/#0 small
kdb meta-set user/tests/type/multivalue check/enum/#1 middle
kdb meta-set user/tests/type/multivalue check/enum/#2 large
kdb meta-set user/tests/type/multivalue check/enum/#3 huge
kdb meta-set user/tests/type/multivalue check/enum/delimiter _
kdb meta-set user/tests/type/multivalue check/enum "#3"
kdb meta-set user/tests/type/multivalue type enum

The user needs to

  • set the type to enum
  • specify the highest index of the enum
  • specify all values (obviously)

and can optionally configure the delimiter, which is not a bad thing of course. However, all of this configuration needs to go through the narrow interface of key-value pairs. And while this data structure itself is not the issue, having the user specify it through it, is at least cumbersome. kdb meta-set also cannot do any validation, like in the "ipv8" example above, to give users feedback about the plugin configuration.

What if instead, kdb offered a higher level abstraction to enable an easier configuration syntax and validation? kdb could offer a sub-command for each category of plugins where it makes sense. I'll focus on validation/checker plugins for now. For a plugin like ipaddr it might look like this:

kdb validate /tests/ipaddr/ipv4 ipaddr

to simply enable the plugin. It reads like "validate the key /tests/ipaddr/ipv4 as an ip address".

Or use

kdb validate /tests/ipaddr/ipv4 ipaddr ipv4

to validate the given key as an ipv4 address. Providing anything other than ipv4 or ipv6 should return an error to the user.

Similarly, configuring the type plugin's enums could be a one-liner (compare that to the 7 lines above)

kdb validate user/tests/type/multivalue type enum --delimiter _ small middle large huge

and the type subcommand would determine the highest index of the enum automatically and set all the necessary meta-keys based on the given information.

The range subcommand could look like this:

kdb validate /tests/range/value range 1..10

And the validation plugin could be renamed to regex, so it would read:

kdb validate /tests/value regex "\w*"

Essentially each plugin would act like a sub-command of kdb validate and could, if necessary, take options. The enum example above takes a --delimiter option. The plugins would still be configured as they are today, through meta-keys, but the user-facing interface would be much nicer.

Similarly, for other plugin categories, the user could do

# Encode this key in base64
kdb encode /tests/base64/test base64
# Transform this key to uppercase
kdb transform /tests/test rename toupper
# Encrypt this key in the key database (I put crypto into this category)
kdb transform /tests/test crypto

There are 16 plugins in category "others", like crypto, which would have to be put into some category where it makes sense. Whether this works for all types of plugins I'm not sure.

Finally, disabling (effectively unmounting a plugin) could be done through:

kdb disable /tests/ipaddr/ipv4 ipaddr

to disable the validation of ipaddr on the given key. But this would work not just for validation plugins, but any plugin from any category.

As I've mentioned before, this proposal would need to mount plugins on-demand. kdb validate could mount the plugin when the user enables or configures it, while kdb disable could unmount it. However, that's all I want to say about the implementation, as the focus of this proposal is on the user interface.

Conclusion

To summarize, I think this system could have a number of advantages over the meta-set based system.

  • It gives users a nicer interface than setting key-values by hand. The syntax is clearer, easier and more in line with other cli-tools, which reduce the usage of special characters, which in turn makes it less error-prone to use.
  • Immediate verification of the user's input and the ability to give concrete feedback, which is not possible through meta-set. This syntax easily gets complicated and a single typo or error, like forgetting to update check/enum to the new highest index, is left for the user to find. Setting an enum through the cli means a task like this can be performed programmatically. Essentially, it reduces the number of bad configuration states that could be set.
  • Users don't always have to lookup the specific syntax for a plugin as kdb becomes more self-explanatory. And if they need to look it up, they can simply query it by invoking the command with --help.
  • Meta keys are an advanced concept that isn't easily understood, especially for first-time users. And it doesn't have to be exposed the way it is now. The meta keys can be mostly abstracted away through a system like this, where all the interaction goes through an easier interface.
  • Meta keys are still used for plugin configuration, so querying other plugin's configuration is still possible.

The major downside I see are the increased complexity, which depends on the implementation. But it's safe to say, that there'd be more code to maintain.

Thanks for reading and I'm curious what you think!

@markus2330
Copy link
Contributor

As I got back into working on Elektra, I rediscovered some quality of life issues with kdb. Elektra helps users configure their software with more safety and checks and kdb is supposed to help developers configure and use Elektra itself, safely and checked.

Exactly, it is one of the goals.

Yet, I feel like it's not doing the best job it could be doing. I want to show some areas related to the usage and configuration of plugins, where I think the user experience could be improved.

Thank you for sharing! In general docu&usability is unfortunately something that easily suffers in research projects as it is an "extra mile" that sometimes unfortunately needs to be sacrificed.

I think we should get first the basics right (core API, behavior of Elektra's plugins, see #3549) for a 1.0 release and get sane usability of the tooling we already have (some good suggestions are also in this proposal here!). Further tooling to improve usability can also be added later. It is a never-ending field with possibilities admins cannot even dream of currently. But without getting the basics out to the field, it will stay a dream.

Mounting plugins

Users don't want to deal with mounting plugins, they simply want to use them.

Yes, that is why in general the idea is that applications or distributions mount their stuff during installation. Admins of course might also want to (re)mount but are not the first target.

If a user wants to mount a file into the key database, in the majority of cases, all they should have to give to kdb mount is the path to the file and the path to the mountpoint. Making users specify exactly which plugins they need to mount the file itself and also which ones they want to use later, is quite cumbersome. They might not necessarily know which checks they want to perform later. Basically, two - from the user perspective - unrelated parts, mounting and plugins, are cobbled together into a single command.

So simply put, I think that in the majority of cases, it should be enough to do

kdb mount myfile.toml user/test/toml

and have kdb mount my file (or I wish that was the behavior) into the key database using the toml plugin. Right now if I do this, it defaults to the dump plugin.

Exactly this will be the behavior in future: #2330

Based on the file extension kdb mount could easily determine a default plugin for toml, json, and many other popular file formats for which there is a good default plugin. That would make many kdb mount invocations easier. For some cases like mounting /etc/hosts or when the usage of a specific storage plugin is desired, the command can still take a plugin name as an optional argument.

Yes, I agree. In GUIs the problem is actually even worse.
We already wanted to do something like this 5 years ago: #175
It is simply that nobody did it due to time constraints.

That's only half the story though. More importantly, anything other than storage plugins shouldn't have to be mounted. There may be a technical reason for this that I am unaware of, but from a pure user perspective, I would simply like to do:

kdb mount myfile.toml /tests/toml # would default to toml plugin
kdb set /tests/toml/key value
kdb meta-set /tests/toml/key type string

and get instant validation from the type plugin. It makes mounting easier because the user doesn't have to think ahead about what they might want to do later. And they have instant access to all plugins. The plugins therefore need to be mounted on-demand. My proposal in the following section could enable this cleanly.

This is hopefully something we will have once #690 is done. Some important plugins (like type&spec) should simply always be there.

Plugin Configuration

Currently, users who want to use a plugin have to lookup the documentation and learn about, sometimes complicated syntaxes. Ideally, we can make configuring a bit more interactive and easier.

A fairly simple validation plugin like ipaddr needs to be enabled like this

kdb meta-set /tests/ipaddr/ipv4 check/ipaddr ""

The user needs to lookup the exact syntax, i.e. check/ipaddr in the documentation. To be fair, the check/<plugin_name> syntax is (afaik) standard across all validation plugins. One additional weirdness is having to set an "", when all the user wants to do is enable the plugin. (There are a number of other plugins where this is the case, rgbcolor, macaddr, and likely more).

At the same time, setting a nonsensical value

kdb meta-set /tests/ipaddr/ipv4 check/ipaddr ipv8

Yes, this is very unfortunate because at many places the error checking is way too lax as we do not have guidelines about what should be an error. I wrote about this just today: cc10ee3

doesn't throw an error, because it is technically the same as the example above. However, a user executing this should probably get an error, or at least a warning.

I agree, I updated 834d890

Things get worse, as the plugin's complexity increases. Take specifying enums through the type plugin for instance:

What if instead, kdb offered a higher level abstraction to enable an easier configuration syntax and validation? kdb could offer a sub-command for each category of plugins where it makes sense. I'll focus on validation/checker plugins for now. For a plugin like ipaddr it might look like this:

kdb validate /tests/ipaddr/ipv4 ipaddr

Yes, I like the idea. Funnily, there was a kdb vset which did something like you propose but very poorly implemented. E.g. it did not ensure that the correct plugins are present. Thus it was not really useful and we removed it ac6472c

There are 16 plugins in category "others", like crypto, which would have to be put into some category where it makes sense. Whether this works for all types of plugins I'm not sure.

Exactly, and when it only partly or inconsistently works it is better to not have it all.

As I've mentioned before, this proposal would need to mount plugins on-demand. kdb validate could mount the plugin when the user enables or configures it, while kdb disable could unmount it. However, that's all I want to say about the implementation, as the focus of this proposal is on the user interface.

Currently, there is unfortunately no "remounting". It is missing purely because of implementation effort, not because there is something complicated about remounting. But I do not see remounting as 1.0 goal as it is in no way incompatible with anything and simply yet-another-feature.

To summarize, I think this system could have a number of advantages over the meta-set based system.

I fully agree. Did you look already into the qt-gui? It implements another way of mounting plugins where you can also interactively discover plugins.

  • It gives users a nicer interface than setting key-values by hand. The syntax is clearer, easier and more in line with other cli-tools, which reduce the usage of special characters, which in turn makes it less error-prone to use.

I agree, of course specialized tools would be easier to use!

  • Immediate verification of the user's input and the ability to give concrete feedback, which is not possible through meta-set. > This syntax easily gets complicated and a single typo or error, like forgetting to update check/enum to the new highest index, is left for the user to find. Setting an enum through the cli means a task like this can be performed programmatically. Essentially, it reduces the number of bad configuration states that could be set.

That there are no errors is simply because these cases are not checked. A poorly implemented tool would not improve the situation. A well implemented tool, however, certainly would! 💖

  • Users don't always have to lookup the specific syntax for a plugin as kdb becomes more self-explanatory. And if they need to look it up, they can simply query it by invoking the command with --help.
  • Meta keys are an advanced concept that isn't easily understood, especially for first-time users. And it doesn't have to be exposed the way it is now. The meta keys can be mostly abstracted away through a system like this, where all the interaction goes through an easier interface.
  • Meta keys are still used for plugin configuration, so querying other plugin's configuration is still possible.

The major downside I see are the increased complexity, which depends on the implementation. But it's safe to say, that there'd be more code to maintain.

Thanks for reading and I'm curious what you think!

Thank you very much for taking the time to think about this! I'd love to see such improvements! I see that you really understand what could be done with Elektra. 🚀

@mpranj
Copy link
Member

mpranj commented Nov 25, 2020

Thank you for taking the time and documenting your suggestions. I think you've made some excellent points.

As Markus already pointed out: for some problems issues already exist and could use some additional information/suggestions/implementation hints.

E.g.

So simply put, I think that in the majority of cases, it should be enough to do

kdb mount myfile.toml user/test/toml
and have kdb mount my file (or I wish that was the behavior) into the key database using the toml plugin. Right now if I do this, it defaults to the dump plugin.

Exactly this will be the behavior in future: #2330

I think what @PhilippGackstatter meant is that all formats are auto-detected and you don't have to provide a plugin name. Changing the default to toml will just fix this instance of the larger problem.

I think we will need to split this up into smaller tasks and have a clear path how to fix these problems. I fear that the issue is too large, but we could track the overall progress here.

Do you think some parts can be postponed until after the 1.0-release?

@PhilippGackstatter
Copy link
Contributor Author

Yes, that is why in general the idea is that applications or distributions mount their stuff during installation. Admins of course might also want to (re)mount but are not the first target.

Yes, I agree that applications or distributions are more important than admins here. But I think the interface as it applies to kdb would also apply to an API. For now, application developers also need to set meta keys to configure a plugin.

I think what @PhilippGackstatter meant is that all formats are auto-detected and you don't have to provide a plugin name. Changing the default to toml will just fix this instance of the larger problem.

Yes, that is what I meant 🙂

Yes, this is very unfortunate because at many places the error checking is way too lax as we do not have guidelines about what should be an error.

My understanding is that kdb meta-set cannot even know whether ipv4 or ipv8 are valid values, can it? That's why I'm arguing for an interface that can do this.

I fully agree. Did you look already into the qt-gui?

I haven't used it yet, but I'll check it out!

Do you think some parts can be postponed until after the 1.0-release?

In general, I think that this is not a 1.0 issue. I mainly wanted to write this down when I had the thoughts. Any change to the plugin configuration would build on top of meta keys and so it would be backwards compatible. The "mount plugin based on file extension" would probably also be ok to change post-1.0.

@markus2330
Copy link
Contributor

My understanding is that kdb meta-set cannot even know whether ipv4 or ipv8 are valid values, can it?

The spec plugin could, as it has access to all keys. It is the general enforcer of validity and presence of metadata (it is not yet implemented, however, that it actually enforces doc/METADATA.ini as this is a big topic).

I haven't used it yet, but I'll check it out!

And a look at spec-mount is also important, this is the new-generation mounting. And this tool should actually abort on invalid specifications but unfortunately, it currently does not (also does not implement the whole of doc/METADATA.ini).

So probably we should reduce doc/METADATA.ini to something small we can actually handle and release this for 1.0.

In general, I think that this is not a 1.0 issue.

Imho mounting would need a bit more love so that applications can be satisfied with it. E.g. #1074 #1306

Unfortunately not small issues and both are pending on big other tasks to be done first:

I close here for now, please open new issues if there are new ideas for making 1.0 better.

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

No branches or pull requests

3 participants