1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-12 08:58:17 +03:00

feature #206: Initial refactor of Scheduler code

This commit is contained in:
Carlos Martin and Ruben S. Montero 2010-05-13 23:05:28 +02:00 committed by Ruben S. Montero
parent a156dca7e3
commit e059b35d55
16 changed files with 407 additions and 953 deletions

View File

@ -1,185 +0,0 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef OBJECT_XML_H_
#define OBJECT_XML_H_
#include <string>
#include <vector>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
using namespace std;
class ObjectXML
{
public:
ObjectXML(const string &xml_doc):xml(0),ctx(0)
{
xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());
if (xml == 0)
{
throw("Error parsing XML Document");
}
ctx = xmlXPathNewContext(xml);
if (ctx == 0)
{
xmlFreeDoc(xml);
throw("Unable to create new XPath context");
}
};
ObjectXML(const xmlNodePtr node):xml(0),ctx(0)
{
xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));
if (xml == 0)
{
throw("Error allocating XML Document");
}
ctx = xmlXPathNewContext(xml);
if (ctx == 0)
{
xmlFreeDoc(xml);
throw("Unable to create new XPath context");
}
xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);
if (root_node == 0)
{
xmlXPathFreeContext(ctx);
xmlFreeDoc(xml);
throw("Unable to allocate node");
}
xmlDocSetRootElement(xml, root_node);
};
virtual ~ObjectXML()
{
if (xml != 0)
{
xmlFreeDoc(xml);
}
if ( ctx != 0)
{
xmlXPathFreeContext(ctx);
}
};
vector<string> operator[] (const char * xpath_expr)
{
xmlXPathObjectPtr obj;
vector<string> content;
obj = xmlXPathEvalExpression(
reinterpret_cast<const xmlChar *>(xpath_expr), ctx);
if (obj == 0 || obj->nodesetval == 0)
{
return content;
}
xmlNodeSetPtr ns = obj->nodesetval;
int size = ns->nodeNr;
xmlNodePtr cur;
xmlChar * str_ptr;
for(int i = 0; i < size; ++i)
{
cur = ns->nodeTab[i];
if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
{
continue;
}
str_ptr = xmlNodeGetContent(cur);
if (str_ptr != 0)
{
string element_content = reinterpret_cast<char *>(str_ptr);
content.push_back(element_content);
xmlFree(str_ptr);
}
}
xmlXPathFreeObject(obj);
return content;
};
int get_nodes (const char * xpath_expr, vector<xmlNodePtr>& content)
{
xmlXPathObjectPtr obj;
obj = xmlXPathEvalExpression(
reinterpret_cast<const xmlChar *>(xpath_expr), ctx);
if (obj == 0 || obj->nodesetval == 0)
{
return 0;
}
xmlNodeSetPtr ns = obj->nodesetval;
int size = ns->nodeNr;
int num_nodes = 0;
xmlNodePtr cur;
for(int i = 0; i < size; ++i)
{
cur = ns->nodeTab[i];
if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
{
continue;
}
content.push_back(cur);
num_nodes++;
}
xmlXPathFreeObject(obj);
return num_nodes;
};
private:
/**
* XML representation of the Object
*/
xmlDocPtr xml;
/**
* XPath Context to access Object elements
*/
xmlXPathContextPtr ctx;
};
#endif /*OBJECT_XML_H_*/

View File

@ -34,7 +34,12 @@ add_bison(main_env)
# Include dirs
main_env.Append(CPPPATH=[
cwd+'./',
cwd+'/include/',
])
# Library dirs
main_env.Append(LIBPATH=[
cwd+'/src/xml',
])
# Compile flags
@ -79,55 +84,14 @@ else:
main_env.ParseConfig('xml2-config --libs --cflags')
################################################################################
# SCONS scripts to build
################################################################################
Import('env')
cwd=os.getcwd()
env.Append(LIBPATH=cwd)
lib_name='nebula_scheduler'
# Sources to generate the library
source_files=[
'Scheduler.cc',
'SchedulerHost.cc',
'SchedulerVirtualMachine.cc',
build_scripts=[
'src/xml/SConstruct',
]
scheduler_names=[
'mm_sched'
]
# Build library
env.StaticLibrary(lib_name, source_files)
env.Append(LIBS=[
lib_name,
'nebula_core',
'nebula_host',
'nebula_vm',
'nebula_vnm',
'nebula_pool',
'nebula_template',
'nebula_common',
'nebula_um',
'sqlite3',
'crypto',
])
if not env.GetOption('clean'):
env.ParseConfig('../../share/scons/get_xmlrpc_config client')
# Build tests
for sched in scheduler_names:
env.Program(sched, sched+'.cc')
for script in build_scripts:
env=main_env.Clone()
SConscript(script, exports='env')

View File

@ -1,177 +0,0 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include <limits.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include "SchedulerHost.h"
#include "Scheduler.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void SchedulerHost::get_capacity(int& cpu, int& memory, int threshold)
{
int total_cpu;
memory = get_share_free_mem();
cpu = get_share_free_cpu();
total_cpu = get_share_max_cpu();
/* eg. 96.7 >= 0.9 * 100, We need to round */
if ( cpu >= threshold * total_cpu )
{
cpu = (int) ceil((float)cpu/100.0) * 100;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerHost::insert(SqliteDB *db)
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not insert hosts in database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerHost::update(SqliteDB *db)
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not update hosts in database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerHost::drop(SqliteDB *db)
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not delete hosts from database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerHostPool::allocate(
PoolObjectSQL *objsql)
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not allocate hosts in database");
return -1;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void SchedulerHostPool::bootstrap()
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not bootstrap database");
}
/* ************************************************************************** */
/* SchedulerHostPool */
/* ************************************************************************** */
extern "C"
{
static int set_up_cb (
void * _hids,
int num,
char ** values,
char ** names)
{
vector<int> * hids;
hids = static_cast<vector<int> *>(_hids);
if ((hids==0)||(num<=0)||(values[0]==0))
{
return -1;
}
hids->push_back(atoi(values[0]));
return 0;
};
}
/* -------------------------------------------------------------------------- */
int SchedulerHostPool::set_up()
{
ostringstream oss;
int rc;
// -------------------------------------------------------------------------
// Clean the pool to get updated data from db
// -------------------------------------------------------------------------
clean();
hids.clear();
// -------------------------------------------------------------------------
// Load the ids (to get an updated list of hosts)
// -------------------------------------------------------------------------
lock();
oss << "SELECT oid FROM " << Host::table
<< " WHERE state != " << Host::DISABLED
<< " AND state != " << Host::ERROR;
rc = db->exec(oss,set_up_cb,(void *) &hids);
if ( rc != 0 )
{
unlock();
return -1;
}
oss.str("");
oss << "Discovered Hosts (enabled):";
for (unsigned int i=0 ; i < hids.size() ; i++)
{
oss << " " << hids[i];
}
Scheduler::log("HOST",Log::DEBUG,oss);
unlock();
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -1,140 +0,0 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef SCHEDULER_HOST_H_
#define SCHEDULER_HOST_H_
#include "Host.h"
using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The SchedulerHost class. It represents the scheduler version of the host,
* only read operations to the pool are allowed for the SchedulerHost class
*/
class SchedulerHost : public Host
{
public:
SchedulerHost(){};
~SchedulerHost(){};
/**
* Gets the current host capacity
* @param cpu the host free cpu, scaled according to a given threshold
* @param memory the host free memory
* @param threshold to consider the host totally free
*/
void get_capacity(int& cpu, int& memory, int threshold);
private:
// ----------------------------------------
// Friends
// ----------------------------------------
friend class SchedulerHostPool;
// ----------------------------------------
// SQL functions do not modify the DB!
// ----------------------------------------
int insert(SqliteDB *db);
int update(SqliteDB *db);
int drop(SqliteDB *db);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The SchedulerHost class. It represents the scheduler version of the host,
* read only operation to the pool are allowed for the SchedulerHost class
*/
class SchedulerHostPool : public PoolSQL
{
public:
//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
SchedulerHostPool(SqliteDB *db):PoolSQL(db){};
~SchedulerHostPool(){};
/**
* Implements the Pool interface, just prints an error message. This
* class DOES NOT modify the database.
*/
int allocate(
PoolObjectSQL *objsql);
/**
* Gets an ScheulerHost from the pool (if needed the object is loaded from
* the database).
* @param oid the object unique identifier
* @param lock locks the object if true
*
* @return a pointer to the object, 0 in case of failure
*/
SchedulerHost * get(
int oid,
bool lock)
{
return static_cast<SchedulerHost *>(PoolSQL::get(oid,lock));
};
/**
* Set ups the host pool by performing the following actions:
* - All the objects stored in the pool are flushed
* - The ids of the hosts in the database are loaded
* @return 0 on success
*/
int set_up();
private:
friend class Scheduler;
/**
* Hosts ids
*/
vector<int> hids;
/**
* Factory method for the PoolSQL class
* @return a pointer to a new SchedulerHost object
*/
PoolObjectSQL * create()
{
return new SchedulerHost;
};
/**
* Bootstrap method from the PoolSQL interface. It just prints
* an error message as this class MUST not modify the DB.
*/
void bootstrap();
};
#endif /*SCHEDULER_HOST_H_*/

View File

@ -1,206 +0,0 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include <limits.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include "SchedulerHost.h"
#include "Scheduler.h"
/* ************************************************************************** */
/* SchedulerVirtualMachine */
/* ************************************************************************** */
int SchedulerVirtualMachine::insert(SqliteDB *db)
{
Scheduler::log("VM",Log::ERROR,
"Scheduler can not insert VMs in database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerVirtualMachine::update(SqliteDB *db)
{
Scheduler::log("VM",Log::ERROR,
"Scheduler can not update VMs in database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerVirtualMachine::drop(SqliteDB *db)
{
Scheduler::log("VM",Log::ERROR,
"Scheduler can not delete VMs in database");
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void SchedulerVirtualMachine::set_priorities(vector<float>& total)
{
if ( hosts.size() != total.size() )
{
Scheduler::log("VM",Log::ERROR,"Wrong size for priority vector");
return;
}
for (unsigned int i=0; i<hosts.size(); i++)
{
hosts[i]->priority = total[i];
}
//Sort the shares using the priority
sort(hosts.begin(),hosts.end(),SchedulerVirtualMachine::host_cmp);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerVirtualMachine::get_host(
int& hid,
SchedulerHostPool * hpool)
{
vector<SchedulerVirtualMachine::Host *>::reverse_iterator i;
vector<int>::iterator j;
SchedulerHost * host;
int cpu;
int mem;
int dsk;
get_requirements(cpu,mem,dsk);
for (i=hosts.rbegin();i!=hosts.rend();i++)
{
host = hpool->get((*i)->hid,false);
if ( host == 0 )
{
continue;
}
if (host->test_capacity(cpu,mem,dsk)==true)
{
host->add_capacity(cpu,mem,dsk);
hid = (*i)->hid;
return 0;
}
}
hid = -1;
return -1;
}
/* ************************************************************************** */
/* Scheuler Virtual Machine :: Misc */
/* ************************************************************************** */
ostream& operator<<(ostream& os, SchedulerVirtualMachine& vm)
{
vector<SchedulerVirtualMachine::Host *>::reverse_iterator i;
vector<int>::iterator j;
for (i=vm.hosts.rbegin();i!=vm.hosts.rend();i++)
{
os << "\t" << (*i)->priority << "\t" << (*i)->hid << endl;
}
return os;
};
/* ************************************************************************** */
/* SchedulerVirtualMachinePool */
/* ************************************************************************** */
int SchedulerVirtualMachinePool::allocate(
PoolObjectSQL *objsql)
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not allocate VMs in database");
return -1;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void SchedulerVirtualMachinePool::bootstrap()
{
Scheduler::log("HOST",Log::ERROR,
"Scheduler can not bootstrap database");
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int SchedulerVirtualMachinePool::set_up()
{
ostringstream oss;
string where;
int rc;
// -------------------------------------------------------------------------
// Clean the pool to get updated data from db
// -------------------------------------------------------------------------
clean();
pending_vms.clear();
// -------------------------------------------------------------------------
// Load an updated list of pending VMs
// -------------------------------------------------------------------------
oss << "state == " << VirtualMachine::PENDING;
where = oss.str();
rc = PoolSQL::search(
pending_vms,
VirtualMachine::table,
where);
oss.str("");
oss << "Pending virtual machines :";
for (unsigned int i=0 ; i < pending_vms.size() ; i++)
{
oss << " " << pending_vms[i];
}
Scheduler::log("VM",Log::DEBUG,oss);
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -1,190 +0,0 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef SCHEDULER_VIRTUAL_MACHINE_H_
#define SCHEDULER_VIRTUAL_MACHINE_H_
#include "VirtualMachine.h"
#include "SchedulerHost.h"
using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The SchedulerHost class. It represents the scheduler version of the host,
* only read operations to the pool are allowed for the SchedulerHost class
*/
class SchedulerVirtualMachine : public VirtualMachine
{
public:
SchedulerVirtualMachine(){};
~SchedulerVirtualMachine()
{
vector<SchedulerVirtualMachine::Host *>::iterator jt;
for (jt=hosts.begin();jt!=hosts.end();jt++)
{
delete *jt;
}
};
/**
* Adds a new share to the map of suitable shares to start this VM
* @param hid of the selected host
* @param hsid of the selected host share
*/
void add_host(int hid)
{
SchedulerVirtualMachine::Host * ss;
ss = new SchedulerVirtualMachine::Host(hid);
hosts.push_back(ss);
};
/**
* Gets the matching hosts ids
* @param mh vector with the hids of the matching hosts
*/
void get_matching_hosts(vector<int>& mh)
{
vector<SchedulerVirtualMachine::Host *>::iterator i;
for(i=hosts.begin();i!=hosts.end();i++)
{
mh.push_back((*i)->hid);
}
};
/**
* Sets the priorities for each matching host
*/
void set_priorities(vector<float>& total);
/**
*
*/
int get_host(int& hid, SchedulerHostPool * hpool);
/**
* Function to write a Virtual Machine in an output stream
*/
friend ostream& operator<<(ostream& os, SchedulerVirtualMachine& vm);
private:
// -------------------------------------------------------------------------
// Friends
// -------------------------------------------------------------------------
friend class SchedulerVirtualMachinePool;
//--------------------------------------------------------------------------
struct Host
{
int hid;
float priority;
Host(int _hid):
hid(_hid),
priority(0){};
~Host(){};
bool operator<(const Host& b) const { //Sort by priority
return priority < b.priority;
}
};
static bool host_cmp (const Host * a, const Host * b )
{
return (*a < *b );
};
//--------------------------------------------------------------------------
/**
* Matching hosts
*/
vector<SchedulerVirtualMachine::Host *> hosts;
// -------------------------------------------------------------------------
// SQL functions do not modify the DB!
// -------------------------------------------------------------------------
int insert(SqliteDB *db);
int update(SqliteDB *db);
int drop(SqliteDB *db);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The SchedulerHost class. It represents the scheduler version of the host,
* read only operation to the pool are allowed for the SchedulerHost class
*/
class SchedulerVirtualMachinePool : public PoolSQL
{
public:
SchedulerVirtualMachinePool(SqliteDB * db):PoolSQL(db){};
~SchedulerVirtualMachinePool(){};
int allocate(
PoolObjectSQL *objsql);
SchedulerVirtualMachine * get(
int oid,
bool lock)
{
return static_cast<SchedulerVirtualMachine *>(PoolSQL::get(oid,lock));
};
/**
* Set ups the VM pool by performing the following actions:
* - All the objects stored in the pool are flushed
* - The ids of the pendings VMs in the database are loaded
* @return 0 on success
*/
int set_up();
private:
friend class Scheduler;
/**
* The ids of the pending VMs
*/
vector<int> pending_vms;
PoolObjectSQL * create()
{
return new SchedulerVirtualMachine;
};
void bootstrap();
};
#endif /*SCHEDULER_VIRTUAL_MACHINE_H_*/

View File

@ -0,0 +1,96 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef OBJECT_XML_H_
#define OBJECT_XML_H_
#include <string>
#include <vector>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
using namespace std;
/**
* This class represents a generic Object supported by a xml document.
* The class provides basic methods to query attributes, and get xml nodes
*/
class ObjectXML
{
public:
// ---------------------- Constructors ------------------------------------
ObjectXML():xml(0),ctx(0){};
/**
* Constructs an object using a XML document
*/
ObjectXML(const string &xml_doc);
/**
* Constructs an object using a XML Node. The node is copied to the new
* object
*/
ObjectXML(const xmlNodePtr node);
virtual ~ObjectXML();
/**
* Access Object elements using Xpath
* @param xpath_expr the Xpath of the element
* @return a vector with the elements
*/
vector<string> operator[] (const char * xpath_expr);
/**
* Get xml nodes by Xpath
* @param xpath_expr the Xpath for the elements
* @param content nodes for the given Xpath expression. The nodes are
* returned as pointers to the object nodes.
* @return the number of nodes found
*/
int get_nodes (const char * xpath_expr, vector<xmlNodePtr>& content);
/**
* Updates the object representation with a new XML document. Previous
* XML resources are freed
* @param xml_doc the new xml document
*/
int update(const string &xml_doc);
private:
/**
* XML representation of the Object
*/
xmlDocPtr xml;
/**
* XPath Context to access Object elements
*/
xmlXPathContextPtr ctx;
/**
* Parse a XML documents and initializes XPath contexts
*/
void xml_parse(const string &xml_doc);
};
#endif /*OBJECT_XML_H_*/

View File

@ -0,0 +1,214 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include <ObjectXML.h>
#include <stdexcept>
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ObjectXML::ObjectXML(const string &xml_doc):xml(0),ctx(0)
{
try
{
xml_parse(xml_doc);
}
catch(runtime_error& re)
{
throw;
}
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ObjectXML::ObjectXML(const xmlNodePtr node):xml(0),ctx(0)
{
xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));
if (xml == 0)
{
throw("Error allocating XML Document");
}
ctx = xmlXPathNewContext(xml);
if (ctx == 0)
{
xmlFreeDoc(xml);
throw("Unable to create new XPath context");
}
xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);
if (root_node == 0)
{
xmlXPathFreeContext(ctx);
xmlFreeDoc(xml);
throw("Unable to allocate node");
}
xmlDocSetRootElement(xml, root_node);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ObjectXML::~ObjectXML()
{
if (xml != 0)
{
xmlFreeDoc(xml);
}
if ( ctx != 0)
{
xmlXPathFreeContext(ctx);
}
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
vector<string> ObjectXML::operator[] (const char * xpath_expr)
{
xmlXPathObjectPtr obj;
vector<string> content;
obj = xmlXPathEvalExpression(
reinterpret_cast<const xmlChar *>(xpath_expr), ctx);
if (obj == 0 || obj->nodesetval == 0)
{
return content;
}
xmlNodeSetPtr ns = obj->nodesetval;
int size = ns->nodeNr;
xmlNodePtr cur;
xmlChar * str_ptr;
for(int i = 0; i < size; ++i)
{
cur = ns->nodeTab[i];
if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
{
continue;
}
str_ptr = xmlNodeGetContent(cur);
if (str_ptr != 0)
{
string element_content = reinterpret_cast<char *>(str_ptr);
content.push_back(element_content);
xmlFree(str_ptr);
}
}
xmlXPathFreeObject(obj);
return content;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ObjectXML::get_nodes (const char * xpath_expr, vector<xmlNodePtr>& content)
{
xmlXPathObjectPtr obj;
obj = xmlXPathEvalExpression(
reinterpret_cast<const xmlChar *>(xpath_expr), ctx);
if (obj == 0 || obj->nodesetval == 0)
{
return 0;
}
xmlNodeSetPtr ns = obj->nodesetval;
int size = ns->nodeNr;
int num_nodes = 0;
xmlNodePtr cur;
for(int i = 0; i < size; ++i)
{
cur = ns->nodeTab[i];
if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
{
continue;
}
content.push_back(cur);
num_nodes++;
}
xmlXPathFreeObject(obj);
return num_nodes;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ObjectXML::update(const string &xml_doc)
{
if (xml != 0)
{
xmlFreeDoc(xml);
}
if ( ctx != 0)
{
xmlXPathFreeContext(ctx);
}
try
{
xml_parse(xml_doc);
}
catch(runtime_error& re)
{
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ObjectXML::xml_parse(const string &xml_doc)
{
xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());
if (xml == 0)
{
throw("Error parsing XML Document");
}
ctx = xmlXPathNewContext(xml);
if (ctx == 0)
{
xmlFreeDoc(xml);
throw("Unable to create new XPath context");
}
}

View File

@ -0,0 +1,26 @@
# SConstruct for src/pool
# -------------------------------------------------------------------------- #
# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
Import('env')
lib_name='scheduler_xml'
source_files=['ObjectXML.cc']
# Build library
env.StaticLibrary(lib_name, source_files)

View File

@ -39,6 +39,7 @@ class ObjectXMLTest : public CppUnit::TestFixture
CPPUNIT_TEST( xpath_access );
CPPUNIT_TEST( node_constructor );
CPPUNIT_TEST( doc_update );
CPPUNIT_TEST_SUITE_END ();
@ -57,7 +58,6 @@ public:
~ObjectXMLTest(){};
/* ********************************************************************* */
/* ********************************************************************* */
@ -118,7 +118,36 @@ public:
}
};
void doc_update()
{
try
{
ObjectXML obj(xml_history_dump);
vector<string> hostnames;
hostnames = obj["/VM_POOL/VM/HISTORY/HOSTNAME"];
CPPUNIT_ASSERT(hostnames.size() == 2);
CPPUNIT_ASSERT(hostnames[0] == "A_hostname");
CPPUNIT_ASSERT(hostnames[1] == "C_hostname");
obj.update(xml_history_dump2);
hostnames = obj["/VM_POOL/VM/HISTORY/HOSTNAME"];
CPPUNIT_ASSERT(hostnames.size() == 2);
CPPUNIT_ASSERT(hostnames[0] == "0_hostname");
CPPUNIT_ASSERT(hostnames[1] == "1_hostname");
}
catch(runtime_error& re)
{
cerr << re.what() << endl;
CPPUNIT_ASSERT(1 == 0);
}
};
static const string xml_history_dump;
static const string xml_history_dump2;
};
/* ************************************************************************* */
@ -155,4 +184,26 @@ const string ObjectXMLTest::xml_history_dump =
"</SEQ><HOSTNAME>C_hostname</HOSTNAME><HID>2</HID><STIME>0</STIME><ETIME>0"
"</ETIME><PSTIME>0</PSTIME><PETIME>0</PETIME><RSTIME>0</RSTIME><RETIME>0"
"</RETIME><ESTIME>0</ESTIME><EETIME>0</EETIME><REASON>0</REASON></HISTORY>"
"</VM></VM_POOL>";
const string ObjectXMLTest::xml_history_dump2 =
"<VM_POOL><VM><ID>0</ID><UID>0</UID><USERNAME>one_user_test</USERNAME>"
"<NAME>VM one</NAME><LAST_POLL>0</LAST_POLL><STATE>1</STATE><LCM_STATE>"
"0</LCM_STATE><STIME>0000000000</STIME><ETIME>0</ETIME><DEPLOY_ID>"
"</DEPLOY_ID><MEMORY>0</MEMORY><CPU>0</CPU><NET_TX>0</NET_TX><NET_RX>"
"0</NET_RX></VM><VM><ID>1</ID><UID>0</UID><USERNAME>"
"one_user_test</USERNAME><NAME>Second VM</NAME><LAST_POLL>0</LAST_POLL>"
"<STATE>2</STATE><LCM_STATE>0</LCM_STATE><STIME>0000000000</STIME>"
"<ETIME>0</ETIME><DEPLOY_ID></DEPLOY_ID><MEMORY>0</MEMORY><CPU>0</CPU>"
"<NET_TX>0</NET_TX><NET_RX>0</NET_RX><HISTORY><SEQ>0</SEQ><HOSTNAME>"
"0_hostname</HOSTNAME><HID>0</HID><STIME>0</STIME><ETIME>0</ETIME><PSTIME>"
"0</PSTIME><PETIME>0</PETIME><RSTIME>0</RSTIME><RETIME>0</RETIME><ESTIME>"
"0</ESTIME><EETIME>0</EETIME><REASON>0</REASON></HISTORY></VM><VM><ID>2"
"</ID><UID>0</UID><USERNAME>one_user_test</USERNAME><NAME>VM one</NAME>"
"<LAST_POLL>0</LAST_POLL><STATE>2</STATE><LCM_STATE>0</LCM_STATE><STIME>"
"0000000000</STIME><ETIME>0</ETIME><DEPLOY_ID></DEPLOY_ID><MEMORY>0"
"</MEMORY><CPU>0</CPU><NET_TX>0</NET_TX><NET_RX>0</NET_RX><HISTORY><SEQ>1"
"</SEQ><HOSTNAME>1_hostname</HOSTNAME><HID>2</HID><STIME>0</STIME><ETIME>0"
"</ETIME><PSTIME>0</PSTIME><PETIME>0</PETIME><RSTIME>0</RSTIME><RETIME>0"
"</RETIME><ESTIME>0</ESTIME><EETIME>0</EETIME><REASON>0</REASON></HISTORY>"
"</VM></VM_POOL>";

View File

@ -17,7 +17,7 @@
import os
import sys
import shutil
sys.path.append("../../../share/scons")
sys.path.append("../../../../../share/scons")
# This is the absolute path where the project is located
cwd=os.getcwd()
@ -28,7 +28,7 @@ main_env['ENV']['PATH']=os.environ['PATH']
# Include dirs
main_env.Append(CPPPATH=[
cwd+'/../',
cwd+'/../../../include',
'/usr/include/cppunit/'
])
@ -48,7 +48,8 @@ main_env.Append(LDFLAGS=["-g"])
# Libraries
main_env.Append(LIBS=[
'cppunit'
'cppunit',
'scheduler_xml'
])
main_env.Program('test_xml','ObjectXMLTest.cc')
@ -67,7 +68,7 @@ if xmlrpc_dir!='none':
main_env.Append(LIBPATH=[xmlrpc_dir+"/lib"])
main_env.Append(CPPPATH=[xmlrpc_dir+"/include"])
main_env.ParseConfig('../../../share/scons/get_xmlrpc_config client')
main_env.ParseConfig('../../../../../share/scons/get_xmlrpc_config client')
#-------------------------------------------------------------------------------
# build lex/bison