Hi George, 

> If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin 
> definitions? Or do I provide 1 plugin definition with multiple “urls” where 
> each one points to a distinct path? 

The JSON plugin definition file (maybe we should call it "plugin descriptor") 
should contain basic information about the plugin and how it's supposed to be 
loaded by WebAdmin, for example: 

{ 
"name": "test", 
"version": "1.0", 
"url": "/webadmin/webadmin/plugin/test/start.html", // Invokes the actual 
plugin code 
... more attributes ... 
} 

You can do many things inside one plugin (add multiple tabs, context menu 
items, etc.) - you just need to add multiple event handler functions inside the 
actual plugin code, for example: 

pluginApi.plugins['test'] = { 

// UiInit event handler function, the first function to be called on the plugin 
UiInit: function() { 
pluginApi.ui.addMainTab('Custom Tab One', 'custom-tab-1', 
'http://www.example.com/1'); 
pluginApi.ui.addMainTab('Custom Tab Two', 'custom-tab-2', 
'http://www.example.com/2'); 
} , 

// HostContextMenu event handler function, just an example (not implemented 
yet) 
HostContextMenu: function(ctx) { 
// 'ctx' represents the context of this event handler function, containing: 
// - information about host(s) currently selected 
// - API (functions) to add custom context menu items 
} 

// Similarly, we could define VmContextMenu, etc. (everything inside one 
plugin) 

}; 

> If “url” is configured to point to an external application server hosting my 
> plugin, what is the intent of “path”? For example, if I configure “url” to 
> point to “https://10.10.10.10/myplugin/entrypoint.html” then presumably the 
> application server will render the page it needs as a main tab or context 
> menu. It would have no need for “path” since all dependencies would be 
> resolved by the application server. 

You're right, the "path" attribute makes sense only when serving plugin 
resources (most importantly, plugin HTML page) through a special oVirt Engine 
servlet (currently called PluginSourcePageServlet , should be renamed to 
something like "PluginResourceServlet"). If "url" points to some external 
application server, the "path" attribute can be omitted (optional attribute). 
However, the "url" attribute denotes the location from which plugin HTML page 
will be requested by the plugin's iframe. 

Regards, 
Vojtech 


----- Original Message -----

From: "George Costea" <[email protected]> 
To: "Vojtech Szocs" <[email protected]>, "Chris Frantz" <[email protected]> 
Cc: "engine-devel" <[email protected]> 
Sent: Thursday, August 23, 2012 3:09:05 PM 
Subject: RE: [Engine-devel] UI Plugins configuration 



Thanks Chris and Vojtech for continuing this discussion. I think I’m missing 
the link between providing the plugin definition file and defining the plugins. 
If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin 
definitions? Or do I provide 1 plugin definition with multiple “urls” where 
each one points to a distinct path? 

If “url” is configured to point to an external application server hosting my 
plugin, what is the intent of “path”? For example, if I configure “url” to 
point to “https://10.10.10.10/myplugin/entrypoint.html” then presumably the 
application server will render the page it needs as a main tab or context menu. 
It would have no need for “path” since all dependencies would be resolved by 
the application server. 

George 



From: [email protected] [mailto:[email protected]] On 
Behalf Of Vojtech Szocs 
Sent: Thursday, August 23, 2012 8:14 AM 
To: Chris Frantz 
Cc: engine-devel 
Subject: Re: [Engine-devel] UI Plugins configuration 


Hi Chris, 

thanks for taking the time to make this patch, these are some excellent ideas! 
(CC'ing engine-devel so that we can discuss this with other guys as well) 

First of all, I really like the way you designed plugin source page URLs (going 
through PluginSourcePageServlet ), e.g. 
"/webadmin/webadmin/plugin/<pluginName>/<pluginSourcePage>.html", plus the 
concept of "path" JSON attribute. 

WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.json 
files), and directly embeds them into WebAdmin host page as pluginDefinitions 
JavaScript object. I'm assuming that pluginDefinitions object will now look 
like this: 

var pluginDefinitions = { 
"test": { 
"name": "test", 
"version": "1.0", 
"url": "/webadmin/webadmin/plugin/test/foo.html", 
"path": "/tmp", 
"config": {"a":1, "b":2, "c":3} 
} 
} 

Originally, the pluginDefinitions object looked like this: 

var pluginDefinitions = { 
"test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> 
pluginSourcePageUrl mappings 
} 

This is because PluginManager (WebAdmin) only needs pluginName ("name") and 
pluginSourcePageUrl ("url") during startup, when creating plugin iframe. But 
this can be changed :) 

Plugin "version" makes sense, plus the plugin configuration object ("config") 
can be useful directly on the client. Let me explain: 

Originally, plugin configuration was supposed to be passed to actual plugin 
code (through immediately-invoked-function-expression, or IIFE), just like 
this: 

(function (pluginApi, pluginConfig) { // JavaScript IIFE 
// ... actual plugin code ... 
})( 
parent.pluginApi, /* reference to global pluginApi object */ 
{"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object */ 
); 

The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin code 
into HTML, so that users don't need to write HTML pages for their plugins 
manually. PluginSourcePageServlet would handle any plugin dependencies (placed 
into HTML head), with actual plugin code being wrapped into IIFE, as shown 
above. Plugin configuration was meant to be stored in a separate file, e.g. 
<pluginName>-config.json , so that users could change the default plugin 
configuration to suit their needs. 

Inspired by your patch, rather than reading/embedding plugin configuration when 
serving plugin HTML page ( PluginSourcePageServlet ), it's even better to have 
the plugin configuration embedded directly into WebAdmin host page, along with 
introducing new pluginApi function to retrieve the plugin configuration object. 

Based on this, I suggest following modifications to the original concept: 

- modify original pluginDefinitions structure, from pluginName -> 
pluginSourcePageUrl , to pluginName -> pluginDefObject 
- pluginDefObject is basically a subset of physical plugin definition ( 
test.json , see below), suitable for use on the client 
- add following attributes to pluginDefObject : version , url , config 
* note #1: name is not needed, since it's already the key of pluginName -> 
pluginDefObject mapping 
* note #2: path is not needed on the client (more on this below) 
- introduce pluginApi.config(pluginName) function for plugins to retrieve their 
configuration object, and remove pluginConfig parameter from main IIFE (as 
shown above) 

[a] Physical plugin definition file (JSON) might be located at oVirt "DataDir", 
e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example: 

{ 
"name": "test", 
"version": "1.0", 
"url": "/webadmin/webadmin/plugin/test/start.html", 
"path": "/tmp", 
"config": "test-config.json" 
} 

[b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir", 
e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example: 

{ 
"a":1, "b":2, "c":3 
} 

[c] Finally, plugin static resources (plugin source page, actual plugin code, 
plugin dependencies, CSS/images, etc.) would be located at /tmp (as shown in 
[a]), for example: 

/tmp/start.html -> plugin source page, used to load actual plugin code 
/tmp/test.js -> actual plugin code 
/tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency 

For example: 
"/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.html 
"/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to 
/tmp/deps/jquery-min.js 

This approach has some pros and cons: 
(+) plugin static resources can be served through PluginSourcePageServlet 
(pretty much like oVirt documentation resources, served through oVirt Engine 
root war's FileServlet ) 
(+) plugin author has complete control over plugin source page 
(-) plugin author actually needs to write plugin source page 

Overall, I think this approach is better than the previous one (where 
PluginSourcePageServlet took care of rendering plugin source page, but 
sacrificed some flexibility). 

By the way, here's what would happen behind the scenes: 

    1. user requests WebAdmin host page, WebadminDynamicHostingServlet loads 
and caches all plugin definitions [a] + plugin configurations [b] and 
constructs/embeds appropriate pluginDefinitions JavaScript object 
    2. during WebAdmin startup, PluginManager registers the plugin 
(name/version/url/config), and creates/attaches the iframe to fetch plugin 
source page ansynchronously 
    3. PluginSourcePageServlet handles plugin source page request, resolves the 
correct path [c] and just streams the file content back to client 

> 1. The plugin configuration files should probably have an "enabled" field and 
> an "apiVersion" field that should be examined to determine whether or not to 
> use the plugin. 

Sounds good, we can implement these later on :) 

> 2. I suspect the way I've modified PluginSourcePage makes it vulnerable to 
> directory climbing attacks. 

Yes, but we can defend against these, restricting access only to plugin's 
"path" and its sub-directories. 

> 3. Is /usr/share/ovirt-engine the right place for the plugin config files? 

I suppose you mean plugin definition files [a], cannot tell for sure, but we 
can change this anytime :) 


Chris, please let me know what you think, and again - many thanks for sending 
the patch! 


Regards, 
Vojtech 


----- Original Message -----


From: "Chris Frantz" < [email protected] > 
To: [email protected] 
Sent: Wednesday, August 22, 2012 7:56:45 PM 
Subject: UI Plugins configuration 

Vojtech, 

I decided to work on making the plugin patch a bit more configurable, following 
some of the ideas expressed by Itamar and others in the meeting yesterday. The 
attached patch is a simple first-attempt. 

Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.json. 

Example: 
{ 
"name": "test", 
"version": "1.0", 
"url": "/webadmin/webadmin/plugin/test/foo.html", 
"path": "/tmp", 
"config": {"a":1, "b":2, "c": 3} 
} 

The engine reads all of the *.json files in that directory to build the list of 
known plugins and gives that list to the webadmin. 

When webadmin loads a plugin, it requests the URL given in the plugin config 
file. The "plugin" URL is mapped to PluginSourcePage, which will translate the 
first part of the path ("test") into whatever path is stored in pluginConfig 
("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html"). 

I didn't use the renderPluginSourcePage() method in favor of just serving a 
static file, but I have no strong opinion on the matter. However, a plugin may 
want to store static resources at "path" and have the engine serve those 
resources. By just serving files through PluginSourcePage, we don't need any 
other servlets to provide those resources. 

There is still a bit of work to do: 

1. The plugin configuration files should probably have an "enabled" field and 
an "apiVersion" field that should be examined to determine whether or not to 
use the plugin. 

2. I suspect the way I've modified PluginSourcePage makes it vulnerable to 
directory climbing attacks. 

3. Is /usr/share/ovirt-engine the right place for the plugin config files? 

Let me know what you think, 
--Chris 
_______________________________________________
Engine-devel mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-devel

Reply via email to