------=_Part_14076039_700554763.1346074851578
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Hi George,=20
If I want to add 3 main tabs and 6 context menus, do I provide 9
plugin d=
efinitions? Or do I provide 1 plugin definition with multiple
=E2=80=9Curls=
=E2=80=9D where each one points to a distinct path?=20
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:=20
{=20
"name": "test",=20
"version": "1.0",=20
"url": "/webadmin/webadmin/plugin/test/start.html", // Invokes the
actual p=
lugin code=20
... more attributes ...=20
}=20
You can do many things inside one plugin (add multiple tabs, context menu i=
tems, etc.) - you just need to add multiple event handler functions inside =
the actual plugin code, for example:=20
pluginApi.plugins['test'] =3D {=20
// UiInit event handler function, the first function to be called on the pl=
ugin=20
UiInit: function() {=20
pluginApi.ui.addMainTab('Custom Tab One', 'custom-tab-1',
'http://www.examp=
le.com/1');=20
pluginApi.ui.addMainTab('Custom Tab Two', 'custom-tab-2',
'http://www.examp=
le.com/2');=20
} ,=20
// HostContextMenu event handler function, just an example (not implemented=
yet)=20
HostContextMenu: function(ctx) {=20
// 'ctx' represents the context of this event handler function, containing:=
=20
// - information about host(s) currently selected=20
// - API (functions) to add custom context menu items=20
}=20
// Similarly, we could define VmContextMenu, etc. (everything inside one pl=
ugin)=20
};=20
If =E2=80=9Curl=E2=80=9D is configured to point to an external
applicatio=
n server hosting my plugin, what is the intent of
=E2=80=9Cpath=E2=80=9D? F=
or example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps=
://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applic=
ation server will render the page it needs as a main tab or context menu. I=
t would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies woul=
d be resolved by the application server.=20
You're right, the "path" attribute makes sense only when serving plugin
res=
ources (most importantly, plugin HTML page) through a special oVirt Engine =
servlet (currently called PluginSourcePageServlet , should be renamed to so=
mething like "PluginResourceServlet"). If "url" points to some
external app=
lication server, the "path" attribute can be omitted (optional attribute). =
However, the "url" attribute denotes the location from which plugin HTML pa=
ge will be requested by the plugin's iframe.=20
Regards,=20
Vojtech=20
----- Original Message -----
From: "George Costea" <George.Costea(a)netapp.com>=20
To: "Vojtech Szocs" <vszocs(a)redhat.com>, "Chris Frantz"
<Chris.Frantz(a)hp.co=
m>=20
Cc: "engine-devel" <engine-devel(a)ovirt.org>=20
Sent: Thursday, August 23, 2012 3:09:05 PM=20
Subject: RE: [Engine-devel] UI Plugins configuration=20
Thanks Chris and Vojtech for continuing this discussion. I think I=E2=80=99=
m missing the link between providing the plugin definition file and definin=
g the plugins. If I want to add 3 main tabs and 6 context menus, do I provi=
de 9 plugin definitions? Or do I provide 1 plugin definition with multiple =
=E2=80=9Curls=E2=80=9D where each one points to a distinct path?=20
If =E2=80=9Curl=E2=80=9D is configured to point to an external application =
server hosting my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For=
example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps:/=
/10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applicat=
ion server will render the page it needs as a main tab or context menu. It =
would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies would =
be resolved by the application server.=20
George=20
From: engine-devel-bounces(a)ovirt.org [mailto:engine-devel-bounces@ovirt.org=
] On Behalf Of Vojtech Szocs=20
Sent: Thursday, August 23, 2012 8:14 AM=20
To: Chris Frantz=20
Cc: engine-devel=20
Subject: Re: [Engine-devel] UI Plugins configuration=20
Hi Chris,=20
thanks for taking the time to make this patch, these are some excellent ide=
as! (CC'ing engine-devel so that we can discuss this with other guys as wel=
l)=20
First of all, I really like the way you designed plugin source page URLs (g=
oing through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pl=
uginName>/<pluginSourcePage>.html", plus the concept of "path"
JSON attribu=
te.=20
WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.j=
son files), and directly embeds them into WebAdmin host page as pluginDefin=
itions JavaScript object. I'm assuming that pluginDefinitions object will n=
ow look like this:=20
var pluginDefinitions =3D {=20
"test": {=20
"name": "test",=20
"version": "1.0",=20
"url": "/webadmin/webadmin/plugin/test/foo.html",=20
"path": "/tmp",=20
"config": {"a":1, "b":2, "c":3}=20
}=20
}=20
Originally, the pluginDefinitions object looked like this:=20
var pluginDefinitions =3D {=20
"test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName
-> p=
luginSourcePageUrl mappings=20
}=20
This is because PluginManager (WebAdmin) only needs pluginName ("name") and=
pluginSourcePageUrl ("url") during startup, when creating plugin iframe. B=
ut this can be changed :)=20
Plugin "version" makes sense, plus the plugin configuration object
("config=
") can be useful directly on the client. Let me explain:=20
Originally, plugin configuration was supposed to be passed to actual plugin=
code (through immediately-invoked-function-expression, or IIFE), just like=
this:=20
(function (pluginApi, pluginConfig) { // JavaScript IIFE=20
// ... actual plugin code ...=20
})(=20
parent.pluginApi, /* reference to global pluginApi object */=20
{"a":1, "b":2, "c":3} /* embedded plugin configuration as
JavaScript object=
*/=20
);=20
The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin co=
de into HTML, so that users don't need to write HTML pages for their plugin=
s manually. PluginSourcePageServlet would handle any plugin dependencies (p=
laced 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 pl=
ugin configuration to suit their needs.=20
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 conf=
iguration object.=20
Based on this, I suggest following modifications to the original concept:=
=20
- modify original pluginDefinitions structure, from pluginName -> pluginSou=
rcePageUrl , to pluginName -> pluginDefObject=20
- pluginDefObject is basically a subset of physical plugin definition ( tes=
t.json , see below), suitable for use on the client=20
- add following attributes to pluginDefObject : version , url , config=20
* note #1: name is not needed, since it's already the key of pluginName -> =
pluginDefObject mapping=20
* note #2: path is not needed on the client (more on this below)=20
- introduce pluginApi.config(pluginName) function for plugins to retrieve t=
heir configuration object, and remove pluginConfig parameter from main IIFE=
(as shown above)=20
[a] Physical plugin definition file (JSON) might be located at oVirt "DataD=
ir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:=20
{=20
"name": "test",=20
"version": "1.0",=20
"url": "/webadmin/webadmin/plugin/test/start.html",=20
"path": "/tmp",=20
"config": "test-config.json"=20
}=20
[b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",=
e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:=20
{=20
"a":1, "b":2, "c":3=20
}=20
[c] Finally, plugin static resources (plugin source page, actual plugin cod=
e, plugin dependencies, CSS/images, etc.) would be located at /tmp (as show=
n in [a]), for example:=20
/tmp/start.html -> plugin source page, used to load actual plugin code=20
/tmp/test.js -> actual plugin code=20
/tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency=20
For example:=20
"/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.ht=
ml=20
"/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/=
deps/jquery-min.js=20
This approach has some pros and cons:=20
(+) plugin static resources can be served through PluginSourcePageServlet (=
pretty much like oVirt documentation resources, served through oVirt Engine=
root war's FileServlet )=20
(+) plugin author has complete control over plugin source page=20
(-) plugin author actually needs to write plugin source page=20
Overall, I think this approach is better than the previous one (where Plugi=
nSourcePageServlet took care of rendering plugin source page, but sacrifice=
d some flexibility).=20
By the way, here's what would happen behind the scenes:=20
1. user requests WebAdmin host page, WebadminDynamicHostingServlet load=
s and caches all plugin definitions [a] + plugin configurations [b] and con=
structs/embeds appropriate pluginDefinitions JavaScript object=20
2. during WebAdmin startup, PluginManager registers the plugin (name/ve=
rsion/url/config), and creates/attaches the iframe to fetch plugin source p=
age ansynchronously=20
3. PluginSourcePageServlet handles plugin source page request, resolves=
the correct path [c] and just streams the file content back to client=20
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.=20
Sounds good, we can implement these later on :)=20
2. I suspect the way I've modified PluginSourcePage makes it
vulnerable t=
o directory climbing attacks.=20
Yes, but we can defend against these, restricting access only to plugin's "=
path" and its sub-directories.=20
3. Is /usr/share/ovirt-engine the right place for the plugin config
files=
?=20
I suppose you mean plugin definition files [a], cannot tell for sure, but w=
e can change this anytime :)=20
Chris, please let me know what you think, and again - many thanks for sendi=
ng the patch!=20
Regards,=20
Vojtech=20
----- Original Message -----
From: "Chris Frantz" < Chris.Frantz(a)hp.com >=20
To: vszocs(a)redhat.com=20
Sent: Wednesday, August 22, 2012 7:56:45 PM=20
Subject: UI Plugins configuration=20
Vojtech,=20
I decided to work on making the plugin patch a bit more configurable, follo=
wing some of the ideas expressed by Itamar and others in the meeting yester=
day. The attached patch is a simple first-attempt.=20
Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js=
on.=20
Example:=20
{=20
"name": "test",=20
"version": "1.0",=20
"url": "/webadmin/webadmin/plugin/test/foo.html",=20
"path": "/tmp",=20
"config": {"a":1, "b":2, "c": 3}=20
}=20
The engine reads all of the *.json files in that directory to build the lis=
t of known plugins and gives that list to the webadmin.=20
When webadmin loads a plugin, it requests the URL given in the plugin confi=
g file. The "plugin" URL is mapped to PluginSourcePage, which will translat=
e the first part of the path ("test") into whatever path is stored in plugi=
nConfig ("/tmp") in this case, and then serve the static file (e.g.
"/tmp/f=
oo.html").=20
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 tho=
se resources. By just serving files through PluginSourcePage, we don't need=
any other servlets to provide those resources.=20
There is still a bit of work to do:=20
1. The plugin configuration files should probably have an "enabled" field a=
nd an "apiVersion" field that should be examined to determine whether or no=
t to use the plugin.=20
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to =
directory climbing attacks.=20
3. Is /usr/share/ovirt-engine the right place for the plugin config files?=
=20
Let me know what you think,=20
--Chris=20
------=_Part_14076039_700554763.1346074851578
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<html><head><style type=3D'text/css'>p { margin: 0;
}</style></head><body><=
div style=3D'font-family: times new roman,new york,times,serif; font-size: =
12pt; color: #000000'>Hi George,<br><br><span
style=3D"font-size:11.0pt;fon=
t-family:"Calibri","sans-serif";color:#1F497D">>
If
I want to add 3 main tabs and 6 context menus, do I provide 9 plugin=20
definitions? Or do I provide 1 plugin definition with multiple =E2=80=
=9Curls=E2=80=9D=20
where each one points to a distinct path?</span><br><br>The JSON plugin
def=
inition file (maybe we should call it "plugin descriptor") should contain b=
asic information about the plugin and how it's supposed to be loaded by Web=
Admin, for example:<br><br style=3D"font-family: courier
new,courier,monaco=
,monospace,sans-serif;"><span style=3D"font-family: courier
new,courier,mon=
aco,monospace,sans-serif;">{</span><br style=3D"font-family: courier
new,co=
urier,monaco,monospace,sans-serif;"><span style=3D"font-family: courier
new=
,courier,monaco,monospace,sans-serif;"> "name":
"test",</span><br sty=
le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span
=
style=3D"font-family: courier
new,courier,monaco,monospace,sans-serif;">&nb=
sp; "version": "1.0",</span><br style=3D"font-family:
courier new,courier,m=
onaco,monospace,sans-serif;"><span style=3D"font-family: courier
new,courie=
r,monaco,monospace,sans-serif;"> "url":
"/webadmin/webadmin/plugin/te=
st/start.html", // Invokes the actual plugin code</span><br
style=3D"font-f=
amily: courier new,courier,monaco,monospace,sans-serif;"><span
style=3D"fon=
t-family: courier new,courier,monaco,monospace,sans-serif;"> ... more=
attributes ...</span><br style=3D"font-family: courier
new,courier,monaco,=
monospace,sans-serif;"><span style=3D"font-family: courier
new,courier,mona=
co,monospace,sans-serif;">}</span><br><br>You can do many things
inside one=
plugin (add multiple tabs, context menu items, etc.) - you just need to ad=
d multiple event handler functions inside the actual plugin code, for examp=
le:<br><br><span style=3D"font-family: courier
new,courier,monaco,monospace=
,sans-serif;">pluginApi.plugins['test'] =3D {</span><br><br
style=3D"font-f=
amily: courier new,courier,monaco,monospace,sans-serif;"><span
style=3D"fon=
t-family: courier new,courier,monaco,monospace,sans-serif;"> // UiIni=
t event handler function, the first function to be called on the plugin</sp=
an><br style=3D"font-family: courier new,courier,monaco,monospace,sans-seri=
f;"><span style=3D"font-family: courier
new,courier,monaco,monospace,sans-s=
erif;"> UiInit: function() {</span><br
style=3D"font-family: courier =
new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family:
couri=
er new,courier,monaco,monospace,sans-serif;">
pluginApi.u=
i.addMainTab('Custom Tab One', 'custom-tab-1',
'http://www.example.com/1');=
</span><br style=3D"font-family: courier
new,courier,monaco,monospace,sans-=
serif;"><span style=3D"font-family: courier
new,courier,monaco,monospace,sa=
ns-serif;"> pluginApi.ui.addMainTab('Custom Tab
Two', 'cu=
stom-tab-2', 'http://www.example.com/2');</span><br
style=3D"font-family: c=
ourier new,courier,monaco,monospace,sans-serif;"><span
style=3D"font-family=
: courier new,courier,monaco,monospace,sans-serif;">
},</span><br sty=
le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><br
st=
yle=3D"font-family: courier
new,courier,monaco,monospace,sans-serif;"><span=
style=3D"font-family: courier
new,courier,monaco,monospace,sans-serif;">&n=
bsp; // HostContextMenu event handler function, just an example (not implem=
ented yet)</span><br style=3D"font-family: courier
new,courier,monaco,monos=
pace,sans-serif;"><span style=3D"font-family: courier
new,courier,monaco,mo=
nospace,sans-serif;"> HostContextMenu: function(ctx)
{</span><br><spa=
n style=3D"font-family: courier
new,courier,monaco,monospace,sans-serif;">&=
nbsp; // 'ctx' represents the context of this event handler
fun=
ction, containing:<br> // - information about host(s)
cur=
rently selected<br style=3D"font-family: courier new,courier,monaco,monospa=
ce,sans-serif;"></span><span style=3D"font-family: courier
new,courier,mona=
co,monospace,sans-serif;"></span><span style=3D"font-family: courier
new,co=
urier,monaco,monospace,sans-serif;"> // - API (functions) to
a=
dd custom context menu items<br></span><span style=3D"font-family:
courier =
new,courier,monaco,monospace,sans-serif;"> }</span><br
style=3D"font-=
family: courier new,courier,monaco,monospace,sans-serif;"><br
style=3D"font=
-family: courier new,courier,monaco,monospace,sans-serif;"><span
style=3D"f=
ont-family: courier new,courier,monaco,monospace,sans-serif;"> // Sim=
ilarly, we could define VmContextMenu, etc. (everything inside one plugin)<=
/span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-s=
erif;"><br style=3D"font-family: courier
new,courier,monaco,monospace,sans-=
serif;"><span style=3D"font-family: courier
new,courier,monaco,monospace,sa=
ns-serif;">};</span><br><br><span
style=3D"font-size:11.0pt;font-family:&qu=
ot;Calibri","sans-serif";color:#1F497D">> If
=E2=80=9Curl=E2=80=9D is configured to point to an external application se=
rver hosting=20
my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For example,=
if I configure=20
=E2=80=9Curl=E2=80=9D to point
to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre=
sumably the application server will render the page it needs as a main tab =
or=20
context menu. It would have no need for =E2=80=9Cpath=E2=80=9D since =
all dependencies=20
would be resolved by the application server.</span><br><br>You're
right, th=
e "path" attribute makes sense only when serving plugin resources (most imp=
ortantly, plugin HTML page) through a special oVirt Engine servlet (current=
ly called <em>PluginSourcePageServlet</em>, 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.<br><br>Regards,<br>Vojtech<br><br><br>=
<hr id=3D"zwchr"><div
style=3D"color:#000;font-weight:normal;font-style:nor=
mal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:1=
2pt;"><b>From: </b>"George Costea"
&lt;George.Costea(a)netapp.com&gt;<br><b>T=
o: </b>"Vojtech Szocs" &lt;vszocs(a)redhat.com&gt;, "Chris
Frantz" <Chris.=
Frantz(a)hp.com&gt;<br><b>Cc: </b>"engine-devel"
&lt;engine-devel(a)ovirt.org&g=
t;<br><b>Sent: </b>Thursday, August 23, 2012 3:09:05
PM<br><b>Subject: </b>=
RE: [Engine-devel] UI Plugins configuration<br><br
<style><!--
@font-face
=09{font-family:Calibri;
=09panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
=09{font-family:Tahoma;
=09panose-1:2 11 6 4 3 5 4 4 2 4;}
p.MsoNormal, li.MsoNormal, div.MsoNormal
=09{margin:0in;
=09margin-bottom:.0001pt;
=09font-size:12.0pt;
=09font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
=09{mso-style-priority:99;
=09color:blue;
=09text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
=09{mso-style-priority:99;
=09color:purple;
=09text-decoration:underline;}
p
=09{mso-style-priority:99;
=09margin:0in;
=09margin-bottom:.0001pt;
=09font-size:12.0pt;
=09font-family:"Times New Roman","serif";}
span.EmailStyle19
=09{mso-style-type:personal-reply;
=09font-family:"Calibri","sans-serif";
=09color:#1F497D;}
.MsoChpDefault
=09{mso-style-type:export-only;
=09font-size:10.0pt;}
@page WordSection1
=09{size:8.5in 11.0in;
=09margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
=09{page:WordSection1;}
@list l0
=09{mso-list-id:306739626;
=09mso-list-template-ids:-2112482452;}
ol
=09{margin-bottom:0in;}
ul
=09{margin-bottom:0in;}
--></style
<div class=3D"WordSection1"
<p
class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">Thanks Chris and
Vojtech =
for continuing this discussion. I think I=E2=80=99m 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 de=
finitions? Or do I provide 1 plugin definition with multiple =E2=80=
=9Curls=E2=80=9D where each one points to a distinct path?</span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">If
=E2=80=9Curl=E2=80=9D =
is configured to point to an external application server hosting my plugin,=
what is the intent of =E2=80=9Cpath=E2=80=9D? For example, if I conf=
igure =E2=80=9Curl=E2=80=9D to point
to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre=
sumably the application server will render the page it needs as a main tab =
or context menu. It would have no need for =E2=80=9Cpath=E2=80=9D sin=
ce all dependencies would be resolved by the application server.</span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">George</span></p
<p class=3D"MsoNormal"><a
name=3D"_MailEndCompose"><span style=3D"font-size=
:11.0pt;font-family:"Calibri","sans-serif";color:#1F497=
D"> </span></a></p
<div
<div
style=3D"border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in =
0in 0in"
<p
class=3D"MsoNormal"><b><span
style=3D"font-size:10.0pt;font-family:"=
;Tahoma","sans-serif"">From:</span></b><span
style=3D"font-s=
ize:10.0pt;font-family:"Tahoma","sans-serif"">
engine-d=
evel-bounces(a)ovirt.org [mailto:engine-devel-bounces@ovirt.org]
<b>On Behalf Of </b>Vojtech Szocs<br
<b>Sent:</b> Thursday, August 23, 2012 8:14 AM<br
<b>To:</b> Chris Frantz<br
<b>Cc:</b> engine-devel<br
<b>Subject:</b> Re: [Engine-devel] UI Plugins
configuration</span></p
</div
</div
<p
class=3D"MsoNormal"> </p
<div
<p
class=3D"MsoNormal"><span style=3D"color:black">Hi
Chris,<br
<br
thanks
for taking the time to make this patch, these are some excellent ide=
as! (CC'ing engine-devel so that we can discuss this with other guys as wel=
l)<br
<br
First of
all, I really like the way you designed plugin source page URLs (g=
oing through
<em>PluginSourcePageServlet</em>), e.g.
"/webadmin/webadmin/plugin/<plug=
inName>/<pluginSourcePage>.html", plus the concept of
"path" JSON =
attribute.<br
<br
<i>WebadminDynamicHostingServlet</i> loads and caches all plugin
definition=
s (<i>*.json</i> files), and directly embeds them into WebAdmin host page a=
s
<i>pluginDefinitions</i> JavaScript object. I'm assuming that
<i>pluginDefi=
nitions</i> object will now look like this:<br
<br
</span><span
style=3D"font-family:"Courier New";color:black">var =
pluginDefinitions =3D {<br
"test": {<br
"name": "test",<br
"version":
"1.0",<br
"url": "/webadmin/webadmin/plugin/test/foo.html",<br
"path":
"/tmp",<br
"config": {"a":1, "b":2,
"c":3}<br
}<br
}</span><span
style=3D"color:black"><br
<br
Originally, the
<i>pluginDefinitions</i> object looked like this:<br
</span><span
style=3D"font-family:"Courier New";color:black"><br
var pluginDefinitions =3D {<br
"test":
"/webadmin/webadmin/plugin/test/foo.html" // Simple plu=
ginName -> pluginSourcePageUrl mappings<br
}</span><span style=3D"color:black"><br
<br
This is because PluginManager
(WebAdmin) only needs <i>pluginName</i> ("nam=
e") and
<i>pluginSourcePageUrl</i> ("url") during startup, when creating
plugin ifr=
ame. But this can be changed :)<br
<br
Plugin "version" makes
sense, plus the plugin configuration object ("config=
") can be useful directly on the client. Let me explain:<br
<br
Originally, plugin configuration was
supposed to be passed to actual plugin=
code (through immediately-invoked-function-expression, or IIFE), just like=
this:<br
</span><span
style=3D"font-family:"Courier New";color:black"><br
(function (pluginApi, pluginConfig) { // JavaScript
IIFE<br
// ... actual
plugin code ...<br
})(<br
parent.pluginApi, /* reference to global
pluginApi object */<br=
{"a":1, "b":2,
"c":3} /* embedded plugin configuration as JavaS=
cript object */<br
);</span><span
style=3D"color:black"><br
<br
The whole purpose of
<i>PluginSourcePageServlet</i> was to "wrap" actual pl=
ugin code into HTML, so that users don't need to write HTML pages for their=
plugins manually.
<i>PluginSourcePageServlet</i> 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=
.
<i><pluginName>-config.json</i>, so that users could change the
defau=
lt plugin configuration to suit their needs.<br
<br
Inspired by your patch, rather than
reading/embedding plugin configuration =
when serving plugin HTML page (<i>PluginSourcePageServlet</i>), it's even
b=
etter to have the plugin configuration embedded directly into WebAdmin host=
page, along with introducing new
<i>pluginApi</i> function to retrieve the plugin configuration
object.<br
<br
Based on
this, I suggest following modifications to the original concept:<b=
r
<br
- modify original
<i>pluginDefinitions</i> structure, from <i>pluginName -&=
gt; pluginSourcePageUrl</i>, to
<i>pluginName -> pluginDefObject</i><br
-
<i>pluginDefObject</i> is basically a subset of physical plugin definitio=
n (<i>test.json</i>, see below), suitable for use on the client<br
- add following attributes to
<i>pluginDefObject</i>: <i>version</i>, <i>ur=
l</i>,
<i>config</i><br
* note #1:
<i>name</i> is not needed, since it's already the ke=
y of <i>pluginName -> pluginDefObject</i> mapping<br
* note #2: <i>path</i> is not
needed on the client (more on thi=
s below)<br
- introduce
<i>pluginApi.config(pluginName)</i> function for plugins to ret=
rieve their configuration object, and remove
<i>pluginConfig</i> parameter from main IIFE (as shown above)<br
<br
[a] Physical plugin definition file
(JSON) might be located at oVirt "DataD=
ir", e.g.
<i>/usr/share/ovirt-engine/ui-plugins/test.json</i>, for example:<br
</span><span
style=3D"font-family:"Courier New";color:black"><br
{<br
"name": "test",<br
"version":
"1.0",<br
"url":
"/webadmin/webadmin/plugin/test/start.html",<br
"path": "/tmp",<br
"config":
"test-config.json"<br
}</span><span
style=3D"color:black"><br
<br
[b] Plugin configuration file (JSON)
might be located at oVirt "ConfigDir",=
e.g. <i
/etc/ovirt-engine/ui-plugins/test-config.json</i>, for example:<br
</span><span
style=3D"font-family:"Courier New";color:black"><br
{<br
"a":1,
"b":2, "c":3<br
}</span><span style=3D"color:black"><br
<br
[c] Finally, plugin static resources
(plugin source page, actual plugin cod=
e, plugin dependencies, CSS/images, etc.) would be located at
<i>/tmp</i> (as shown in [a]), for example:<br
</span><span style=3D"font-family:"Courier
New";color:black"><br
/tmp/start.html -> plugin source page, used to load actual plugin code<b=
r
/tmp/test.js -> actual plugin code<br
/tmp/deps/jquery-min.js -> simulate 3rd party plugin
dependency</span><s=
pan style=3D"color:black"><br
<br
For example:<br
"/webadmin/webadmin/plugin/test/start.html" will be
mapped to <i>/tmp/start=
.html</i><br
"/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to
<i>/t=
mp/deps/jquery-min.js</i><br
<br
This approach has some pros and
cons:<br
(+) plugin static resources can be
served through <i>PluginSourcePageServle=
t</i> (pretty much like oVirt documentation resources, served through oVirt=
Engine root war's
<i>FileServlet</i>)<br
(+)
plugin author has complete control over plugin source page<br
(-) plugin author actually needs to write plugin source
page<br
<br
Overall,
I think this approach is better than the previous one (where <i>Pl=
uginSourcePageServlet</i> took care of rendering plugin source page, but sa=
crificed some flexibility).<br
<br
By the
way, here's what would happen behind the scenes:</span></p
<ol start=3D"1" type=3D"1"
<li class=3D"MsoNormal"
style=3D"color:black;mso-margin-top-alt:auto;margin=
-bottom:12.0pt;mso-list:l0 level1 lfo1"
user
requests WebAdmin host page, <i>WebadminDynamicHostingServlet</i> load=
s and caches all plugin definitions [a] + plugin configurations [b] and con=
structs/embeds appropriate
<i>pluginDefinitions</i> JavaScript object</li><li
class=3D"MsoNormal" styl=
e=3D"color:black;mso-margin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 l=
evel1 lfo1"
during WebAdmin startup,
<i>PluginManager</i> registers the plugin (name/ve=
rsion/url/config), and creates/attaches the iframe to fetch plugin source p=
age ansynchronously</li><li class=3D"MsoNormal"
style=3D"color:black;mso-ma=
rgin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 level1 lfo1"
<i>PluginSourcePageServlet</i> handles plugin
source page request, resolves=
the correct path [c] and just streams the file content back to client</li>=
</ol
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black">> 1. The plugin configuration files should probably have
an=
"enabled" field and an "apiVersion" field that should be examined to
deter=
mine whether or not to use the plugin.<br
<br
Sounds good, we can implement these
later on :)<br
<br
>
2. I suspect the way I've modified PluginSourcePage makes it vul=
nerable to directory climbing attacks.<br
<br
Yes, but we can defend against
these, restricting access only to plugin's "=
path" and its sub-directories.<br
<br
> 3. Is
/usr/share/ovirt-engine the right place for the plugin con=
fig files?<br
<br
I suppose
you mean plugin definition files [a], cannot tell for sure, but w=
e can change this anytime :)<br
<br
<br
Chris, please let me know what you
think, and again - many thanks for sendi=
ng the patch!<br
<br
<br
Regards,<br
Vojtech<br
<br
</span></p
<div class=3D"MsoNormal"
style=3D"text-align:center" align=3D"center"><span=
style=3D"color:black"
<hr id=3D"zwchr"
size=3D"2" width=3D"100%" align=3D"center"
</span></div
<p
class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span
style=3D"color:=
black"><br
From: "Chris Frantz"
<<a href=3D"mailto:Chris.Frantz@hp.com" target=3D"_=
blank">Chris.Frantz(a)hp.com</a>&gt;<br
To: <a
href=3D"mailto:vszocs@redhat.com"
target=3D"_blank">vszocs(a)redhat.co=
m</a><br
Sent: Wednesday, August 22, 2012
7:56:45 PM<br
Subject: UI Plugins
configuration<br
<br
Vojtech,<br
<br
I decided
to work on making the plugin patch a bit more configurable, follo=
wing some of the ideas expressed by Itamar and others in the meeting yester=
day. The attached patch is a simple first-attempt.<br
<br
Plugin configurations are stored in
/usr/share/ovirt-engine/ui-plugins/*.js=
on.<br
<br
Example:<br
{<br
"name":
"test",<br
"version":
"1.0",<br
"url":
"/webadmin/webadmin/=
plugin/test/foo.html",<br
"path":
"/tmp",<br
"config":
{"a":1, "b":2, "c=
": 3}<br
}<br
<br
The engine reads all of the *.json
files in that directory to build the lis=
t of known plugins and gives that list to the webadmin.<br
<br
When webadmin loads a plugin, it
requests the URL given in the plugin confi=
g file. The "plugin" URL is mapped to PluginSourcePage, which will
tr=
anslate 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").<br
<br
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 ser=
ve those resources. By just serving
files through PluginSourcePage, we don't need any other servlets to provid=
e those resources.<br
<br
There is
still a bit of work to do:<br
<br
1.
The plugin configuration files should probably have an "enabled" f=
ield and an "apiVersion" field that should be examined to determine whether=
or not to use the plugin.<br
<br
2.
I suspect the way I've modified PluginSourcePage makes it vulnerab=
le to directory climbing attacks.<br
<br
3. Is
/usr/share/ovirt-engine the right place for the plugin config f=
iles?<br
<br
Let me
know what you think,<br
--Chris</span></p
</div
</div
</div><br></div></body></html
------=_Part_14076039_700554763.1346074851578--