Noam Slomianko has uploaded a new change for review. Change subject: Convert to pass IDs ......................................................................
Convert to pass IDs Moved from passing Xml to passing ID lists Changed tests to work accordingly Signed-off-by: Noam Slomianko <[email protected]> Change-Id: I8643456cf785bb2fc37d4ff1707de9290f330d0c --- M plugins/dummy.py M src/oschedproxyd.py M src/request_handler.py M src/runner.py M src/runner_test.py M tests/java/src/main/java/org/ovirt/schedulerproxy/SchedulerProxy.java M tests/java/src/test/java/org/ovirt/schedulerproxy/SchedulerProxyTest.java 7 files changed, 214 insertions(+), 153 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-scheduler-proxy refs/changes/23/17523/1 diff --git a/plugins/dummy.py b/plugins/dummy.py index 4b9fc15..e745074 100755 --- a/plugins/dummy.py +++ b/plugins/dummy.py @@ -27,6 +27,7 @@ from ovirtsdk.xml import params import ovirtsdk.infrastructure.brokers + class SampleFilter(): def __init__(self): @@ -34,14 +35,15 @@ def filter(self, hosts, vm, args): - my_hosts = params.parseString(hosts) + #use hosts IDs and VM ID to call the Rest API and make a depiction - acceptedHostsIDs =[] - for host in my_hosts.host: + acceptedHostsIDs = [] + for hostID in hosts: #Do work - acceptedHostsIDs.append(host.id) + acceptedHostsIDs.append(hostID) return acceptedHostsIDs + # Notice: plugin filters are going to run in process that will be created and destroyed # per request, you cannot save state in memory @@ -59,19 +61,29 @@ def score(self, hosts, vm, args): - my_hosts = params.parseString(hosts) - - hostScores =[] - for host in my_hosts.host: + hostScores = [] + #use hosts IDs and VM ID to call the Rest API and make a depiction + for hostID in hosts: #Do work - hostScores.append((host.id,50)) + hostScores.append((hostID, 50)) return hostScores + def scoreFunction(hosts, vm, args): scoreClassInstance = SampleScore() print scoreClassInstance.score(hosts, vm, args) +class SampleBalance(): + def __init__(self): + pass + + def balance(self, hosts, args): + #use hosts IDs to call the Rest API and make a depiction + return ['33333333-3333-3333-3333-333333333333'] + + def balanceFunction(hosts, args): - print ['guid'] \ No newline at end of file + balanceInstance = SampleBalance() + print balanceInstance.balance(hosts, args) \ No newline at end of file diff --git a/src/oschedproxyd.py b/src/oschedproxyd.py index ae72c72..b13b49f 100644 --- a/src/oschedproxyd.py +++ b/src/oschedproxyd.py @@ -68,8 +68,8 @@ # TODO make by config logging.info("Loading modules") self._handler = RequestHandler( - os.path.join(os.getcwd() + '/../', "plugins"), - os.getcwd()) + os.path.join(os.getcwd(), "plugins"), + os.path.join(os.getcwd(), "src")) def run(self): logging.info("Loading modules") diff --git a/src/request_handler.py b/src/request_handler.py index 3defcaf..c552917 100644 --- a/src/request_handler.py +++ b/src/request_handler.py @@ -85,7 +85,7 @@ "scores": list(self._scores), "balance": list(self._balancers)} - def run_filters(self, filters, hostsXml, vmXml, properties_map): + def run_filters(self, filters, hostIDs, vmID, properties_map): #Intersects the results from the filters def aggregateResults(filterRunners): resultSet = None @@ -108,7 +108,7 @@ self._pluginDir, f, self._utils.FILTER, - (hostsXml, vmXml, properties_map)) + (hostIDs, vmID, properties_map)) filterRunners.append(runner) for runner in filterRunners: @@ -121,8 +121,8 @@ def run_cost_functions(self, cost_functions, - hostsXml, - vmXml, + hostIDs, + vmID, properties_map): #accumalate the results def aggregateResults(scoreRunners): @@ -150,7 +150,7 @@ self._pluginDir, name, self._utils.SCORE, - (hostsXml, vmXml, properties_map)) + (hostIDs, vmID, properties_map)) scoreRunners.append(runner) weights.append(weight) @@ -161,7 +161,7 @@ return aggregateResults(zip(scoreRunners, weights)) - def run_load_balancing(self, balance, hostsXml, properties_map): + def run_load_balancing(self, balance, hostIDs, properties_map): if balance not in self._balancers: #log? return @@ -169,7 +169,7 @@ runner = PythonMethodRunner(self._pluginDir, balance, self._utils.BALANCE, - (hostsXml, properties_map)) + (hostIDs, properties_map)) runner.start() runner.join(30) diff --git a/src/runner.py b/src/runner.py index ec80cf2..1ee9591 100755 --- a/src/runner.py +++ b/src/runner.py @@ -58,4 +58,4 @@ module + ";" + module + "." + method + self._utils.createFunctionStringArgs(args)) - return ["python", "-c", commandString] + return ["/usr/bin/python", "-c", commandString] diff --git a/src/runner_test.py b/src/runner_test.py index a84b216..12d679a 100644 --- a/src/runner_test.py +++ b/src/runner_test.py @@ -31,11 +31,11 @@ runner = PythonMethodRunner(scriptpath, 'dummy', 'filterFunction', - ['<hosts><host></host></hosts>', - '<vm></vm>', + [['11111111-1111-1111-1111-111111111111', '22222222-2222-2222-2222-222222222222'], + '33333333-3333-3333-3333-333333333333', '']) runner.start() - runner.join() + runner.join(5) result = runner.getResults() assert result is not None pass diff --git a/tests/java/src/main/java/org/ovirt/schedulerproxy/SchedulerProxy.java b/tests/java/src/main/java/org/ovirt/schedulerproxy/SchedulerProxy.java index 6859ae0..a473b38 100644 --- a/tests/java/src/main/java/org/ovirt/schedulerproxy/SchedulerProxy.java +++ b/tests/java/src/main/java/org/ovirt/schedulerproxy/SchedulerProxy.java @@ -1,5 +1,8 @@ package org.ovirt.schedulerproxy; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.net.MalformedURLException; import java.net.URL; @@ -8,110 +11,131 @@ import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; public class SchedulerProxy { - final XmlRpcClient client; + final XmlRpcClient client; - static String HOSTS_EXAMPLE = - "<hosts><host href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d\" id=\"ce270744-6fb8-4c0c-8e3b-7ded018ee45d\"> <actions> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/deactivate\" rel=\"deactivate\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/approve\" rel=\"approve\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/iscsilogin\" rel=\"iscsilogin\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/iscsidiscover\" rel=\"iscsidiscover\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/commitnetconfig\" rel=\"commitnetconfig\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/fence\" rel=\"fence\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/install\" rel=\"install\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/activate\" rel=\"activate\"/> ! </actions> <name>test</name> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/storage\" rel=\"storage\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/nics\" rel=\"nics\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/tags\" rel=\"tags\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/permissions\" rel=\"permissions\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/statistics\" rel=\"statistics\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/hooks\" rel=\"hooks\"/> <address>10.35.1.183</address> <certificate> <organization>oVirt</organization> <subject>O=oVirt,CN=10.35.1.183</subject> </certificate> <status> <state>up</state> </status> <cluster href=\"/api/clusters/9c3fa7e5-bd04-4aad-9b9e-8ce8a737de1b\" id=\"9c3fa7e5-bd04-4aad-9b9e-8ce8a737de1b\"/> <port! >54321</port> <type>rhel</type> <storage_manager >priority=\"5\">true</storage_manager> <version major=\"4\" minor=\"9\" >build=\"6\" revision=\"0\" full_version=\"vdsm-4.9.6-44.3.el6_3\"/> ><hardware_information/> <power_management type=\"alom\"> ><enabled>false</enabled> <options/> </power_management> > <ksm> <enabled>true</enabled> </ksm> ><transparent_hugepages> <enabled>true</enabled> ></transparent_hugepages> <iscsi> ><initiator>iqn.1994-05.com.redhat:e03bd23e99a</initiator> </iscsi> > <cpu> <topology sockets=\"1\" cores=\"4\"/> ><name>Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz</name> ><speed>1600</speed> </cpu> <memory>16601055232</memory> ><max_scheduling_memory>16196304896</max_scheduling_memory> <summary> > <active>0</active> <migrating>0</migrating> <total>0</total> </summary> <os type=\"RHEL\"> ! <version full_version=\"6Server - 6.4.0.4.el6\"/> </os> <libvirt_version major=\"0\" minor=\"10\" build=\"2\" revision=\"0\" full_version=\"libvirt-0.10.2-18.el6_4.3\"/> </host><host href=\"/api/hosts/11111111-6fb8-4c0c-8e3b-7ded018ee45d\" id=\"11111111-6fb8-4c0c-8e3b-7ded018ee45d\"> <actions> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/deactivate\" rel=\"deactivate\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/approve\" rel=\"approve\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/iscsilogin\" rel=\"iscsilogin\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/iscsidiscover\" rel=\"iscsidiscover\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/commitnetconfig\" rel=\"commitnetconfig\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/fence\" rel=\"fence\"/> <link href=\"/api! /hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/install\" rel=\"install\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/activate\" rel=\"activate\"/> </actions> <name>test</name> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/storage\" rel=\"storage\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/nics\" rel=\"nics\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/tags\" rel=\"tags\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/permissions\" rel=\"permissions\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/statistics\" rel=\"statistics\"/> <link href=\"/api/hosts/ce270744-6fb8-4c0c-8e3b-7ded018ee45d/hooks\" rel=\"hooks\"/> <address>10.35.1.183</address> <certificate> <organization>oVirt</organization> <subject>O=oVirt,CN=10.35.1.183</subject> </certificate> <status> <state>up</state> </status> <cluster href=\"/ap! i/clusters/9c3fa7e5-bd04-4aad-9b9e-8ce8a737de1b\" id=\"9c3fa7e5-bd04-4aad-9b9e-8ce8a737de1b\"/> <port>54321</port> <type>rhel</type> <storage_manager priority=\"5\">true</storage_manager> <version major=\"4\" minor=\"9\" build=\"6\" revision=\"0\" full_version=\"vdsm-4.9.6-44.3.el6_3\"/> <hardware_information/> <power_management type=\"alom\"> <enabled>false</enabled> <options/> </power_management> <ksm> <enabled>true</enabled> </ksm> <transparent_hugepages> <enabled>true</enabled> </transparent_hugepages> <iscsi> <initiator>iqn.1994-05.com.redhat:e03bd23e99a</initiator> </iscsi> <cpu> <topology sockets=\"1\" cores=\"4\"/> <name>Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz</name> <speed>1600</speed> </cpu> <memory>16601055232</memory> <max_scheduling_memory>16196304896</max_s! cheduling_memory> <summary> <active>0</active> <migrating>0</migrating> <total>0</total> </summary> <os type=\"RHEL\"> <version full_version=\"6Server - 6.4.0.4.el6\"/> </os> <libvirt_version major=\"0\" minor=\"10\" build=\"2\" revision=\"0\" full_version=\"libvirt-0.10.2-18.el6_4.3\"/> </host></hosts>"; - static String VM_EXAMPLE = "<vm/>"; - static String FILE_NAME = "dummy"; + public SchedulerProxy(String url) throws MalformedURLException { + XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); + config.setServerURL(new URL(url)); + client = new XmlRpcClient(); + client.setConfig(config); + } - public SchedulerProxy(String url) throws MalformedURLException { - XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); - config.setServerURL(new URL(url)); - client = new XmlRpcClient(); - client.setConfig(config); - } - - public void discover() throws XmlRpcException { - Object execute = client.execute("discover", new Object[] {}); - System.out.println(execute); - } - - public void filter() throws XmlRpcException { - Object[] sentObject = new Object[4]; - // filters name - sentObject[0] = new Object[] { FILE_NAME }; - // hosts xml - sentObject[1] = HOSTS_EXAMPLE; - // vm xml - sentObject[2] = VM_EXAMPLE; - // additional args - sentObject[3] = ""; - - Object execute = client.execute("runFilters", sentObject); - System.out.println(parseFilterResult(execute)); - } - - private String parseFilterResult(Object result) { - if (result == null || !(result instanceof Object[])) { - System.out.println("Filter error"); - } - String retValue = "Got filtered hosts:\n"; - // Its a list of host IDs - for (Object hostID : (Object[]) result) { - retValue += hostID.toString() + "\n"; - } - return retValue; - } - - public void score() throws XmlRpcException { - Object[] sentObject = new Object[4]; - // score name + weight pairs - sentObject[0] = new Object[] { new Object[] { FILE_NAME, 2 } }; - // hosts xml - sentObject[1] = HOSTS_EXAMPLE; - // vm xml - sentObject[2] = VM_EXAMPLE; - // additional args - sentObject[3] = ""; - - Object execute = client.execute("runCostFunctions", sentObject); - System.out.println(parseScoreResults(execute)); - } - - private String parseScoreResults(Object result) { - if (result == null || !(result instanceof Object[])) { - System.out.println("Score error"); - } - String retValue = "Got scored hosts:\n"; - // Its a list of (hostID,score) pairs - for (Object hostsIDAndScore : (Object[]) result) { - if (!(hostsIDAndScore instanceof Object[]) - || ((Object[]) hostsIDAndScore).length != 2) { - // some kind of error - System.out.println("Got bad score"); - continue; - } - Object[] castedHostsIDAndScore = (Object[]) hostsIDAndScore; - retValue += castedHostsIDAndScore[0].toString() + " score " - + castedHostsIDAndScore[1].toString() + "\n"; - } - return retValue; - } - - public void balance() throws XmlRpcException { - Object[] sentObject = new Object[3]; - // balance name - sentObject[0] = FILE_NAME; - // hosts xml - sentObject[1] = HOSTS_EXAMPLE; - // additional args - sentObject[2] = ""; - - Object execute = client.execute("runLoadBalancing", sentObject); - System.out.println(parseBalanceResults(execute)); - } - - private String parseBalanceResults(Object result) { - if (result == null || !(result instanceof Object[])) { - System.out.println("balance error"); - } - Object[] castedResult = (Object[]) result; - if (castedResult.length != 1) { - // is it an error to get more then one vm to balance? - System.out.println("got more then one vm to balance"); - } - String retValue = "Got balance vm:\n" + castedResult[0].toString(); - return retValue; - } -} + public HashMap<String, List<String>> discover() throws XmlRpcException { + Object execute = client.execute("discover", new Object[] {}); + return parseDiscover(execute); + } + + private HashMap<String, List<String>> parseDiscover(Object result){ + if (result == null || ! (result instanceof HashMap)){ + System.out.println("discover error"); + return null; + } + HashMap<String, Object[]> castedResult = (HashMap<String, Object[]>)result; + //Its a list of host IDs + HashMap<String, List<String>> retValue = new HashMap<String, List<String>>(); + for (String key : castedResult.keySet()) { + List<String> values = new LinkedList<String>(); + for (Object o : castedResult.get(key)) { + values.add((String)o); + } + retValue.put(key, values); + } + return retValue; + } + + public List<String> filter(String[] filterNames, String[] HostID, String vmID, String args) throws XmlRpcException { + Object[] sentObject = new Object[4]; + //filters name + sentObject[0] = filterNames; + //hosts xml + sentObject[1] = HostID; + //vm xml + sentObject[2] = vmID; + //additional args + sentObject[3] = args; + + Object execute = client.execute("runFilters", sentObject); + return parseFilterResult(execute); + } + + private List<String> parseFilterResult(Object result){ + if (result == null || ! (result instanceof Object[])){ + System.out.println("Filter error"); + return null; + } + //Its a list of host IDs + List<String> retValue = new LinkedList<String>(); + for (Object hostID : (Object[])result) { + retValue.add(hostID.toString()); + } + return retValue; + } + + public HashMap<String, Integer> score(String[] scoreNames, Integer[] weights, String[] HostID, String vmID, String args) throws XmlRpcException { + Object[] sentObject = new Object[4]; + + if(scoreNames == null || weights == null || scoreNames.length != weights.length){ + return null; + } + + Object[] pairs = new Object[scoreNames.length]; + + for (int i = 0; i < pairs.length; i++) { + pairs[i] = new Object[] { scoreNames[i], weights[i] }; + } + //score name + weight pairs + sentObject[0] = pairs; + //hosts xml + sentObject[1] = HostID; + //vm xml + sentObject[2] = vmID; + //additional args + sentObject[3] = args; + + Object execute = client.execute("runCostFunctions", sentObject); + return parseScoreResults(execute); + } + + private HashMap<String, Integer> parseScoreResults(Object result){ + if (result == null || ! (result instanceof Object[])){ + System.out.println("Score error"); + } + HashMap<String, Integer> retValue = new HashMap<String, Integer>(); + //Its a list of (hostID,score) pairs + for (Object hostsIDAndScore : (Object[])result) { + if( ! (hostsIDAndScore instanceof Object[]) || ((Object[])hostsIDAndScore).length != 2 ){ + //some kind of error + System.out.println("Got bad score"); + return null; + } + Object[] castedHostsIDAndScore = (Object[])hostsIDAndScore; + retValue.put(castedHostsIDAndScore[0].toString(), (Integer)castedHostsIDAndScore[1]); + } + return retValue; + } + + public String balance(String balanceName, String[] HostID, String args) throws XmlRpcException { + Object[] sentObject = new Object[3]; + //balance name + sentObject[0] = balanceName; + //hosts xml + sentObject[1] = HostID; + //additional args + sentObject[2] = args; + + Object execute = client.execute("runLoadBalancing", sentObject); + return parseBalanceResults(execute); + } + + private String parseBalanceResults(Object result){ + if (result == null || ! (result instanceof Object[])){ + System.out.println("balance error"); + } + Object[] castedResult = (Object[]) result; + if (castedResult.length != 1){ + //is it an error to get more then one vm to balance? + System.out.println("got more then one vm to balance"); + } + return castedResult[0].toString(); + } +} \ No newline at end of file diff --git a/tests/java/src/test/java/org/ovirt/schedulerproxy/SchedulerProxyTest.java b/tests/java/src/test/java/org/ovirt/schedulerproxy/SchedulerProxyTest.java index e122bec..a0608a9 100644 --- a/tests/java/src/test/java/org/ovirt/schedulerproxy/SchedulerProxyTest.java +++ b/tests/java/src/test/java/org/ovirt/schedulerproxy/SchedulerProxyTest.java @@ -1,37 +1,62 @@ package org.ovirt.schedulerproxy; + +import static org.junit.Assert.assertTrue; import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.List; import org.apache.xmlrpc.XmlRpcException; import org.junit.Before; import org.junit.Test; public class SchedulerProxyTest { + + static String FILE_NAME = "dummy"; + static String HOST_ID1 = "11111111-1111-1111-1111-111111111111"; + static String HOST_ID2 = "22222222-2222-2222-2222-222222222222"; + static String[] HOST_ARRAY = new String[] { HOST_ID1, HOST_ID2 }; + static String VM_ID = "33333333-3333-3333-3333-333333333333"; + static String BALANCE_RESULT = "33333333-3333-3333-3333-333333333333"; - SchedulerProxy proxy; + SchedulerProxy proxy; - @Before - public void setUp() throws MalformedURLException { - proxy = new SchedulerProxy("http://localhost:18781/"); - } + @Before + public void setUp() throws MalformedURLException { + proxy = new SchedulerProxy("http://localhost:18781/"); + } - @Test - public void testDiscover() throws XmlRpcException { - proxy.discover(); - } - - @Test - public void testFilter() throws XmlRpcException { - proxy.filter(); - } - - @Test - public void testScore() throws XmlRpcException { - proxy.score(); - } - - @Test - public void testBalance() throws XmlRpcException { - proxy.balance(); - } -} + @Test + public void testDiscover() throws XmlRpcException { + HashMap<String, List<String>> result = proxy.discover(); + assertTrue(result.containsKey("filters")); + assertTrue(result.get("filters").contains(FILE_NAME)); + assertTrue(result.containsKey("scores")); + assertTrue(result.get("scores").contains(FILE_NAME)); + assertTrue(result.containsKey("filters")); + assertTrue(result.get("balance").contains(FILE_NAME)); + + } + + @Test + public void testFilter() throws XmlRpcException { + List<String> result = proxy.filter(new String[] { FILE_NAME }, HOST_ARRAY, VM_ID, ""); + assertTrue(result.size() == 2); + assertTrue(result.contains(HOST_ID1)); + assertTrue(result.contains(HOST_ID2)); + } + + @Test + public void testScore() throws XmlRpcException { + HashMap<String,Integer> result = proxy.score(new String[] { FILE_NAME }, new Integer[] { 2 }, HOST_ARRAY, VM_ID, ""); + assertTrue(result.size() == 2); + assertTrue(result.get(HOST_ID1) == 100); + assertTrue(result.get(HOST_ID2) == 100); + } + + @Test + public void testBalance() throws XmlRpcException { + String result = proxy.balance(FILE_NAME, HOST_ARRAY, ""); + assertTrue(result.equals(BALANCE_RESULT)); + } +} \ No newline at end of file -- To view, visit http://gerrit.ovirt.org/17523 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8643456cf785bb2fc37d4ff1707de9290f330d0c Gerrit-PatchSet: 1 Gerrit-Project: ovirt-scheduler-proxy Gerrit-Branch: master Gerrit-Owner: Noam Slomianko <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
