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: forwarding control requests to plugins #1682

Merged

Conversation

krnowak
Copy link
Contributor

@krnowak krnowak commented Jul 14, 2016

This is a tentative PR that implements forwarding control requests to plugins.

Problems so far:

  • I made iowait example plugin a controller (adds a button that switches between showing iowait and idle), but:
    • GUI shows plugin's statistics in a separate node, while it used to be in the same one
    • GUI shows no button from plugin

@krnowak krnowak force-pushed the krnowak/plugin-controls branch 2 times, most recently from b76e069 to e93a0cb Compare July 15, 2016 16:19
@krnowak
Copy link
Contributor Author

krnowak commented Jul 15, 2016

Updated the PR. There are still some more problems though:

  • NodeControls' not-really-merging behaviour of its Merge function causes races between plugins adding controls to the same node - only the plugin that sends a report with newest timestamp will have its controls displayed.
    • Probably needs a LatestMap style handling of the NodeControls, because my current hack causes the obsolete controls to be still shown for several seconds
  • Shows obsolete statistics
    • Likely the fix could be also as the LatestMap style handling.
  • Slow reaction to controls
    • The plugin gets the request quickly
    • The new statistics are shown after several seconds though

p.iowaitMode = !p.iowaitMode
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")
}

This comment was marked as abuse.

@alban
Copy link
Contributor

alban commented Jul 18, 2016

Could you update examples/plugins/README.md?

@krnowak krnowak force-pushed the krnowak/plugin-controls branch from e93a0cb to 8bb4ea3 Compare July 21, 2016 11:21

```json
{
"AppID": "some ID of an app"

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

@krnowak krnowak force-pushed the krnowak/plugin-controls branch 2 times, most recently from b0c1be0 to 4b537fa Compare July 22, 2016 12:50
@krnowak
Copy link
Contributor Author

krnowak commented Jul 22, 2016

Updated. There are still some failures, likely because of changing report.LatestEntry.Value from string to interface{}. I would appreciate some help/hints how to fix them.


## <a id="protocol"></a>Protocol
Each plugin should have an unique ID. It is forbidden to change it
during plugin's lifetime. The scope probe will get the plugin's ID

This comment was marked as abuse.

@paulbellamy
Copy link
Contributor

This looks like it's all backwards-compatibility with the existing controls? But wanted to check the interaction between them. For example, what happens if you have both?

krnowak added 20 commits August 12, 2016 17:03
This can be done by calling TESTDIRS="./report ./probe" make tests
So it displays differences behind interface that would otherwise go
unnoticed (like string vs []byte).
Changing plugin's ID only complicates control handling in plugins so
let's ban it.
The socket has the "http_requests.sock" filename, so ID should be
"http_requests", not "http-requests".
We will want to put plugin id in a control id, which is sent to an app
and then to GUI. When we get a control request from GUI, we will want
to extract the plugin ID from the control name. To do it unambiguously
we need some separator made of chars that are not allowed in a plugin
name. This is to avoid the situation when there are two plugins:
"Plugin" and "PluginFoo". "Plugin" exposes a control named
"FooControl" and "PluginFoo" exposes a control named "Control". Faking
the control names which will be sent to the app would result in two
"PluginFooControl".

One possible option for plugin ID and control name separator would be
"/", but that won't work, since the request sent from GUI to the app
to <probe>/<node>/<control> would actually be
<probe>/<node>/<plugin>/<control> and as such wouldn't match the URL
template in RegisterControlRoutes().
Plugin ID must be non-empty when the plugin is created and the
followup reports cannot change it.
It is not a singleton anymore. Instead it is an object with a registry
backend. The default registry backend is provided, which is equivalent
to what used to be before. Custom backend can be provided for testing
purposes.

The registry also supports batch operations to remove and add handlers
as an atomic step.
Thanks to that, plugins can react to requests from controls they
exposed.

To make it work, plugins registry modifies each plugin's report by
prepending the plugin ID to the control name the plugin has exposed
before sending it to the app. Then the registry installs the control
request handler for this faked control name, which forwards the
request to the correct plugin.

This adds a new API endpoint to plugins next to "/report" - a
"/control" entry. The body of the request is the JSON-encoded
xfer.Request instance.
The solution is taken from the toplevel Makefile.
It exposes a button that allows switching between showing an iowait
statistics and an idle statistics. When the button is pressed it
should be replaced with other button. The button is shown in the host
node.

This is a rather nasty case as it shows several problems:

- Button control races
  - The way the NodeControl currently works creates races between
    plugins adding buttons to the same node. This is because
    NodeControls are not really merged, but rather one of the two are
    chosen based on a NodeControls' timestamps, so the older one is
    thrown away entirely. In the end GUI can switch randomly between
    showing controls from one plugin or from another.

- Showing outdated statistics
  - When pressing the button to switch to show the other statistics,
    the old ones are still shown for several seconds.

- Slowness of the updates in GUI
  - Pressing the button yields no immediate reaction. Changes happen
    after several seconds. Probably related to the previous point.
This is better than writing JSON strings by hand, which is
error-prone.
This is better than writing JSON strings by hand, which is
error-prone.
Plugins are queried for reports two times in a second. That's often
enough to get the shortcut reports. The reports are sent together with
the response.
Just to make sure that all the node controls are rewritten, even those
that don't have a counterpart in topology controls.
This commit makes the LatestMap type a sort of a base class, that
should not be used directly. This also adds a generator for LatestMap
"concrete" types with a specific data type in the LatestEntry.
This LatestMap will hold a struct that has more information about the
state of the node control.
This allows plugins to add controls to nodes that already have some
controls set by other plugin. Previously only the last plugin that
sets the controls in the node would have its controls visible. That
was because of NodeControls' Merge function that actually weren't
merging data from two inputs, but rather returning data that was newer
and discarding the older one.
Give a bit more information about how to write a plugin.
The new probe will convert all node's LatestControls to Controls, so
the old app can consume them. Also, the new app will convert all
node's Controls to LatestControl, so it can consume the reports from
old probes.
@krnowak krnowak force-pushed the krnowak/plugin-controls branch from 6000729 to 0ecb908 Compare August 12, 2016 15:16
@krnowak
Copy link
Contributor Author

krnowak commented Aug 12, 2016

Updated to fix the merge conflict.

@paulbellamy
Copy link
Contributor

LGTM

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

Successfully merging this pull request may close these issues.

3 participants