1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

Merge branch 'feature-3028'

This commit is contained in:
Ruben S. Montero 2015-08-26 14:35:01 +02:00
commit 2fff41d8d0
27 changed files with 1172 additions and 177 deletions

View File

@ -379,13 +379,15 @@ public:
* @param cpu needed by the VM (percentage)
* @param mem needed by the VM (in KB)
* @param disk needed by the VM
* @param pci devices needed by th VM
* @return 0 on success
*/
void add_capacity(int vm_id, long long cpu, long long mem, long long disk)
void add_capacity(int vm_id, long long cpu, long long mem, long long disk,
vector<Attribute *> pci)
{
if ( vm_collection.add_collection_id(vm_id) == 0 )
{
host_share.add(cpu,mem,disk);
host_share.add(vm_id, cpu, mem, disk, pci);
}
else
{
@ -404,13 +406,15 @@ public:
* @param cpu used by the VM (percentage)
* @param mem used by the VM (in KB)
* @param disk used by the VM
* @param pci devices needed by th VM
* @return 0 on success
*/
void del_capacity(int vm_id, long long cpu, long long mem, long long disk)
void del_capacity(int vm_id, long long cpu, long long mem, long long disk,
vector<Attribute *> pci)
{
if ( vm_collection.del_collection_id(vm_id) == 0 )
{
host_share.del(cpu,mem,disk);
host_share.del(cpu, mem, disk, pci);
}
else
{
@ -440,11 +444,14 @@ public:
* @param cpu needed by the VM (percentage)
* @param mem needed by the VM (in Kb)
* @param disk needed by the VM
* @param pci devices needed by the VM
* @param error Returns the error reason, if any
* @return true if the share can host the VM
*/
bool test_capacity(long long cpu, long long mem, long long disk)
bool test_capacity(long long cpu, long long mem, long long disk,
vector<Attribute *> &pci, string& error)
{
return host_share.test(cpu, mem, disk);
return host_share.test(cpu, mem, disk, pci, error);
}
/**

View File

@ -123,17 +123,19 @@ public:
* @param cpu amount of CPU, in percentage
* @param mem amount of main memory, in KB
* @param disk amount of disk
* @param pci devices requested by the VM
*
* @return 0 on success -1 in case of failure
*/
int add_capacity(int oid, int vm_id, int cpu, int mem, int disk)
int add_capacity(int oid, int vm_id, int cpu, int mem, int disk,
vector<Attribute *> pci)
{
int rc = 0;
Host * host = get(oid, true);
if ( host != 0 )
{
host->add_capacity(vm_id, cpu, mem, disk);
host->add_capacity(vm_id, cpu, mem, disk, pci);
update(host);
@ -154,14 +156,16 @@ public:
* @param cpu amount of CPU
* @param mem amount of main memory
* @param disk amount of disk
* @param pci devices requested by the VM
*/
void del_capacity(int oid, int vm_id, int cpu, int mem, int disk)
void del_capacity(int oid, int vm_id, int cpu, int mem, int disk,
vector<Attribute *> pci)
{
Host * host = get(oid, true);
if ( host != 0 )
{
host->del_capacity(vm_id, cpu, mem, disk);
host->del_capacity(vm_id, cpu, mem, disk, pci);
update(host);

View File

@ -20,22 +20,179 @@
#include "ObjectXML.h"
#include "Template.h"
#include <time.h>
using namespace std;
#include <set>
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
class HostShareTemplate : public Template
class HostShareDatastore : public Template
{
public:
HostShareTemplate() : Template(false,'=',"DATASTORES"){};
HostShareDatastore() : Template(false, '=', "DATASTORES"){};
~HostShareTemplate(){};
virtual ~HostShareDatastore(){};
};
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/**
* This class represents a PCI DEVICE list for the host. The list is in the
* form:
* <PCI>
* <DOMAIN> PCI address domain
* <BUS> PCI address bus
* <SLOT> PCI address slot
* <FUNCTION> PCI address function
* <ADDRESS> PCI address, bus, slot and function
* <VENDOR> ID of PCI device vendor
* <DEVICE> ID of PCI device
* <CLASS> ID of PCI device class
* <VMID> ID using this device, -1 if free
*
* The monitor probe may report additional information such as VENDOR_NAME,
* DEVICE_NAME, CLASS_NAME...
*/
class HostSharePCI : public Template
{
public:
HostSharePCI() : Template(false, '=', "PCI_DEVICES"){};
virtual ~HostSharePCI()
{
map<string, PCIDevice *>::iterator it;
for (it=pci_devices.begin(); it != pci_devices.end(); it++)
{
delete it->second;
};
};
/**
* Builds the devices list from its XML representation. This function
* is used when importing it from the DB.
* @param node xmlNode for the template
* @return 0 on success
*/
int from_xml_node(const xmlNodePtr node);
/**
* Test whether this PCI device set has the requested devices available.
* @param devs list of requested devices by the VM.
* @return true if all the devices are available.
*/
bool test(vector<Attribute *> &devs) const;
/**
* Assign the requested devices to the given VM. The assigned devices will
* be labeled with the VM and the PCI attribute of the VM extended with
* the address of the assigned devices.
* @param devs list of requested PCI devices, will include address of
* assigned devices.
* @param vmid of the VM
*/
void add(vector<Attribute *> &devs, int vmid)
{
test_set(devs, vmid);
}
/**
* Remove the VM assignment from the PCI device list
*/
void del(const vector<Attribute *> &devs);
/**
* Updates the PCI list with monitor data, it will create or
* remove PCIDevices as needed.
*/
void set_monitorization(vector<Attribute*> &pci_att);
/**
* Prints the PCI device list to an output stream. This function is used
* for logging purposes and *not* for generating DB content.
*/
friend ostream& operator<<(ostream& o, const HostSharePCI& p);
private:
/**
* Sets the internal class structures from the template
*/
int init();
/**
* Test if a PCIDevice matches the vendor, device and class request spec
* and can be assigned. If free, it is stored in the assigned set
* @param vendor_id id in uint form 0 means *
* @param device_id id in uint form 0 means *
* @param class_id id in uint form 0 means *
* @param pci requested pci device
* @param vmid if not -1 it will also assign the PCI device to the VM,
* and the pci attribute will be extended with device information.
* @param assigned set of addresses already assigned devices, it will
* include the selected device if found; useful to iterate.
*
* @return true if a device was found.
*/
bool test(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, const VectorAttribute *pci,
std::set<string> &assigned) const;
/**
* Test if a PCIDevice matches the vendor, device and class request spec
* and can be assigned. It will assign it if requested.
* @param vendor_id id in uint form 0 means *
* @param device_id id in uint form 0 means *
* @param class_id id in uint form 0 means *
* @param pci requested pci device
* @param vmid if not -1 it will also assign the PCI device to the VM,
* and the pci attribute will be extended with device information.
* @param assigned set of addresses already assigned devices, it will
* include the selected device if found; useful to iterate.
*
* @return true if a device was found.
*/
bool test_set(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, VectorAttribute *pci, int vmid,
std::set<string> &assigned) const;
/**
* Test if the given list of PCIDevices can be assigned to the VM
* @param devs, list of PCI devices
* @param vmid if not -1 it will assign the devices to the VM
*
* @return true if the PCIDevice list can be assigned.
*/
bool test_set(vector<Attribute *> &devs, int vmid) const;
/**
* Gets a 4 hex digits value from attribute
* @param name of the attribute
* @pci_device VectorAttribute representing the device
* @return the value as unsigned int or 0 if was not found
*/
static unsigned int get_pci_value(const char * name,
const VectorAttribute * pci_device);
/**
* Internal structure to represent PCI devices for fast look up and
* update
*/
struct PCIDevice
{
PCIDevice(VectorAttribute * _attrs);
~PCIDevice(){};
unsigned int vendor_id;
unsigned int device_id;
unsigned int class_id;
int vmid;
string address;
VectorAttribute * attrs;
};
map <string, PCIDevice *> pci_devices;
};
/**
* The HostShare class. It represents a logical partition of a host...
@ -53,16 +210,21 @@ public:
/**
* Add a new VM to this share
* @param vmid of the VM
* @param cpu requested by the VM, in percentage
* @param mem requested by the VM, in KB
* @param disk requested by the VM
* @param pci_devs requested by the VM
*/
void add(long long cpu, long long mem, long long disk)
void add(int vmid, long long cpu, long long mem, long long disk,
vector<Attribute *> pci_devs)
{
cpu_usage += cpu;
mem_usage += mem;
disk_usage += disk;
pci.add(pci_devs, vmid);
running_vms++;
}
@ -84,13 +246,16 @@ public:
* @param cpu requested by the VM
* @param mem requested by the VM
* @param disk requested by the VM
* @param pci_devs requested by the VM
*/
void del(long long cpu, long long mem, long long disk)
void del(long long cpu, long long mem, long long disk, vector<Attribute *> pci_devs)
{
cpu_usage -= cpu;
mem_usage -= mem;
disk_usage -= disk;
pci.del(pci_devs);
running_vms--;
}
@ -99,15 +264,35 @@ public:
* @param cpu requested by the VM
* @param mem requested by the VM
* @param disk requested by the VM
* @param pci_devs requested by the VM
* @param error Returns the error reason, if any
*
* @return true if the share can host the VM or it is the only one
* configured
*/
bool test(long long cpu, long long mem, long long disk) const
bool test(long long cpu, long long mem, long long disk,
vector<Attribute *>& pci_devs, string& error) const
{
return (((max_cpu - cpu_usage ) >= cpu) &&
((max_mem - mem_usage ) >= mem) &&
((max_disk - disk_usage) >= disk));
bool pci_fits = pci.test(pci_devs);
bool fits = (((max_cpu - cpu_usage ) >= cpu) &&
((max_mem - mem_usage ) >= mem) &&
((max_disk - disk_usage) >= disk)&&
pci_fits);
if (!fits)
{
if ( pci_fits )
{
error = "Not enough capacity.";
}
else
{
error = "Unavailable PCI device.";
}
}
return fits;
}
/**
@ -125,6 +310,11 @@ public:
void set_ds_monitorization(const vector<Attribute*> &ds_att);
void set_pci_monitorization(vector<Attribute*> &pci_att)
{
pci.set_monitorization(pci_att);
}
private:
long long disk_usage; /**< Disk allocated to VMs (in MB). */
@ -145,7 +335,8 @@ private:
long long running_vms;/**< Number of running VMs in this Host */
HostShareTemplate ds_template;
HostShareDatastore ds;
HostSharePCI pci;
// ----------------------------------------
// Friends

View File

@ -90,10 +90,9 @@ protected:
string& tm_mad,
RequestAttributes& att);
bool check_host(int hid,
int cpu,
int mem,
int disk,
bool check_host(int hid,
bool enforce,
VirtualMachine* vm,
string& error);
int add_history(VirtualMachine * vm,

View File

@ -1222,8 +1222,10 @@ public:
* @param cpu
* @param memory
* @param disk
* @param pci_dev
*/
void get_requirements (int& cpu, int& memory, int& disk);
void get_requirements (int& cpu, int& memory, int& disk,
vector<Attribute *>& pci_dev);
/**
* Checks if the resize parameters are valid

View File

@ -847,6 +847,7 @@ IM_PROBES_KVM_PROBES_FILES="src/im_mad/remotes/kvm-probes.d/kvm.rb \
src/im_mad/remotes/kvm-probes.d/cpu.sh \
src/im_mad/remotes/kvm-probes.d/poll.sh \
src/im_mad/remotes/kvm-probes.d/name.sh \
src/im_mad/remotes/kvm-probes.d/pci.rb \
src/im_mad/remotes/common.d/monitor_ds.sh \
src/im_mad/remotes/common.d/version.sh \
src/im_mad/remotes/common.d/collectd-client-shepherd.sh"

View File

@ -413,11 +413,22 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
wilds = host.wilds
begin
pcis = [host.to_hash['HOST']['HOST_SHARE']['PCI_DEVICES']['PCI']]
pcis = pcis.flatten.compact
rescue
pcis = nil
end
host.delete_element("TEMPLATE/VM")
host.delete_element("TEMPLATE_WILDS")
puts host.template_str
if pcis && !pcis.empty?
print_pcis(pcis)
end
puts
CLIHelper.print_header("WILD VIRTUAL MACHINES", false)
puts
@ -457,4 +468,43 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
onevm_helper.client=@client
onevm_helper.list_pool({:filter=>["HOST=#{host.name}"]}, false)
end
def print_pcis(pcis)
puts
CLIHelper.print_header("PCI DEVICES", false)
puts
table=CLIHelper::ShowTable.new(nil, self) do
column :VM, "Used by VM", :size => 4, :left => false do |d|
if d["VMID"] == "-1"
""
else
d["VMID"]
end
end
column :ADDR, "PCI Address", :size => 7, :left => true do |d|
d["SHORT_ADDRESS"]
end
column :TYPE, "Type", :size => 14, :left => true do |d|
d["TYPE"]
end
column :CLASS, "Class", :size => 12, :left => true do |d|
d["CLASS_NAME"]
end
column :NAME, "Name", :size => 30, :left => true do |d|
d["DEVICE_NAME"]
end
column :VENDOR, "Vendor", :size => 8, :left => true do |d|
d["VENDOR_NAME"]
end
end
table.show(pcis)
end
end

View File

@ -92,10 +92,11 @@ int DispatchManager::import (
time_t the_time = time(0);
int cpu, mem, disk;
vector<Attribute *> pci;
vm->get_requirements(cpu, mem, disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
vm->set_state(VirtualMachine::ACTIVE);
@ -771,6 +772,8 @@ int DispatchManager::finalize(
Host * host;
ostringstream oss;
vector<Attribute *> pci;
VirtualMachine::VmState state;
bool is_public_host = false;
int host_id = -1;
@ -809,8 +812,8 @@ int DispatchManager::finalize(
case VirtualMachine::POWEROFF:
int cpu, mem, disk;
vm->get_requirements(cpu,mem,disk);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_hid(),vm->get_oid(),cpu,mem,disk,pci);
if (is_public_host)
{

View File

@ -256,6 +256,7 @@ int Host::update_info(Template &tmpl,
vector<Attribute*>::iterator it;
vector<Attribute*> vm_att;
vector<Attribute*> ds_att;
vector<Attribute*> pci_att;
vector<Attribute*> local_ds_att;
int rc;
@ -465,6 +466,10 @@ int Host::update_info(Template &tmpl,
host_share.set_ds_monitorization(local_ds_att);
obj_template->remove("PCI", pci_att);
host_share.set_pci_monitorization(pci_att);
return 0;
}

View File

@ -15,14 +15,330 @@
/* ------------------------------------------------------------------------*/
#include <limits.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <stdexcept>
#include <iomanip>
#include "HostShare.h"
using namespace std;
/* ************************************************************************ */
/* HostSharePCI */
/* ************************************************************************ */
int HostSharePCI::from_xml_node(const xmlNodePtr node)
{
int rc = Template::from_xml_node(node);
if (rc != 0)
{
return -1;
}
return init();
}
int HostSharePCI::init()
{
vector<Attribute *> devices;
int num_devs = get("PCI", devices);
for (int i=0; i < num_devs; i++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(devices[i]);
if (pci == 0)
{
return -1;
}
PCIDevice * pcidev = new PCIDevice(pci);
pci_devices.insert(make_pair(pcidev->address, pcidev));
}
return 0;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, const VectorAttribute * devreq,
std::set<string>& assigned) const
{
map<string, PCIDevice *>::const_iterator it;
for (it=pci_devices.begin(); it!=pci_devices.end(); it++)
{
PCIDevice * dev = it->second;
if ((class_id == 0 || dev->class_id == class_id) &&
(vendor_id == 0 || dev->vendor_id == vendor_id) &&
(device_id == 0 || dev->device_id == device_id) &&
dev->vmid == -1 &&
assigned.find(dev->address) == assigned.end())
{
assigned.insert(dev->address);
return true;
}
}
return false;
}
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test(vector<Attribute *> &devs) const
{
vector<Attribute *>::iterator it;
std::set<string> assigned;
unsigned int vendor_id, device_id, class_id;
for ( it=devs.begin(); it!= devs.end(); it++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);
if ( pci == 0 )
{
return false;
}
vendor_id = get_pci_value("VENDOR", pci);
device_id = get_pci_value("DEVICE", pci);
class_id = get_pci_value("CLASS", pci);
if (!test(vendor_id, device_id, class_id, pci, assigned))
{
return false;
}
}
return true;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test_set(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, VectorAttribute * devreq, int vmid,
std::set<string>& assigned) const
{
map<string, PCIDevice *>::const_iterator it;
for (it=pci_devices.begin(); it!=pci_devices.end(); it++)
{
PCIDevice * dev = it->second;
if ((class_id == 0 || dev->class_id == class_id) &&
(vendor_id == 0 || dev->vendor_id == vendor_id) &&
(device_id == 0 || dev->device_id == device_id) &&
dev->vmid == -1 &&
assigned.find(dev->address) == assigned.end())
{
assigned.insert(dev->address);
if (vmid != -1)
{
dev->vmid = vmid;
dev->attrs->replace("VMID", vmid);
devreq->replace("DOMAIN",dev->attrs->vector_value("DOMAIN"));
devreq->replace("BUS",dev->attrs->vector_value("BUS"));
devreq->replace("SLOT",dev->attrs->vector_value("SLOT"));
devreq->replace("FUNCTION",dev->attrs->vector_value("FUNCTION"));
devreq->replace("ADDRESS",dev->attrs->vector_value("ADDRESS"));
}
return true;
}
}
return false;
}
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test_set(vector<Attribute *> &devs, int vmid) const
{
vector<Attribute *>::iterator it;
std::set<string> assigned;
unsigned int vendor_id, device_id, class_id;
for ( it=devs.begin(); it!= devs.end(); it++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);
if ( pci == 0 )
{
return false;
}
vendor_id = get_pci_value("VENDOR", pci);
device_id = get_pci_value("DEVICE", pci);
class_id = get_pci_value("CLASS", pci);
if (!test_set(vendor_id, device_id, class_id, pci, vmid, assigned))
{
return false;
}
}
return true;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
void HostSharePCI::del(const vector<Attribute *> &devs)
{
vector<Attribute *>::const_iterator it;
map<string, PCIDevice *>::iterator pci_it;
for ( it=devs.begin(); it!= devs.end(); it++)
{
const VectorAttribute * pci = dynamic_cast<const VectorAttribute *>(*it);
if ( pci == 0 )
{
continue;
}
pci_it = pci_devices.find(pci->vector_value("ADDRESS"));
if (pci_it != pci_devices.end())
{
pci_it->second->vmid = -1;
pci_it->second->attrs->replace("VMID",-1);
}
}
};
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
void HostSharePCI::set_monitorization(vector<Attribute*> &pci_att)
{
vector<Attribute*>::iterator it;
map<string, PCIDevice*>::iterator pci_it;
string address;
for (it = pci_att.begin(); it != pci_att.end(); it++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);
if ( pci == 0 )
{
continue;
}
address = pci->vector_value("ADDRESS");
if (address.empty())
{
delete pci;
continue;
}
pci_it = pci_devices.find(address);
if (pci_it != pci_devices.end())
{
delete pci;
continue;
}
PCIDevice * dev = new PCIDevice(pci);
pci_devices.insert(make_pair(address, dev));
set(pci);
}
};
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
unsigned int HostSharePCI::get_pci_value(const char * name,
const VectorAttribute * pci_device)
{
string temp;
temp = pci_device->vector_value(name);
if (temp.empty())
{
return 0;
}
unsigned int pci_value;
istringstream iss(temp);
iss >> hex >> pci_value;
if (iss.fail() || !iss.eof())
{
return 0;
}
return pci_value;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
HostSharePCI::PCIDevice::PCIDevice(VectorAttribute * _attrs)
: vmid(-1), attrs(_attrs)
{
vendor_id = get_pci_value("VENDOR", attrs);
device_id = get_pci_value("DEVICE", attrs);
class_id = get_pci_value("CLASS", attrs);
if (attrs->vector_value("VMID", vmid) == -1)
{
attrs->replace("VMID", -1);
}
attrs->vector_value("ADDRESS", address);
};
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
ostream& operator<<(ostream& os, const HostSharePCI& pci)
{
map<string, HostSharePCI::PCIDevice *>::const_iterator it;
os << right << setw(15)<< "PCI ADDRESS"<< " "
<< right << setw(8) << "CLASS" << " "
<< right << setw(8) << "VENDOR" << " "
<< right << setw(8) << "DEVICE" << " "
<< right << setw(8) << "VMID" << " "
<< endl << setw(55) << setfill('-') << "-" << setfill(' ') << endl;
for (it=pci.pci_devices.begin(); it!=pci.pci_devices.end(); it++)
{
HostSharePCI::PCIDevice * dev = it->second;
os << right << setw(15)<< dev->address << " "
<< right << setw(8) << dev->class_id << " "
<< right << setw(8) << dev->vendor_id << " "
<< right << setw(8) << dev->device_id << " "
<< right << setw(8) << dev->vmid << " " << endl;
}
return os;
}
/* ************************************************************************ */
/* HostShare :: Constructor/Destructor */
/* ************************************************************************ */
@ -57,7 +373,7 @@ ostream& operator<<(ostream& os, HostShare& hs)
string& HostShare::to_xml(string& xml) const
{
string template_xml;
string ds_xml, pci_xml;
ostringstream oss;
oss << "<HOST_SHARE>"
@ -74,7 +390,8 @@ string& HostShare::to_xml(string& xml) const
<< "<USED_MEM>" << used_mem << "</USED_MEM>"
<< "<USED_CPU>" << used_cpu << "</USED_CPU>"
<< "<RUNNING_VMS>"<<running_vms <<"</RUNNING_VMS>"
<< ds_template.to_xml(template_xml)
<< ds.to_xml(ds_xml)
<< pci.to_xml(pci_xml)
<< "</HOST_SHARE>";
xml = oss.str();
@ -111,7 +428,7 @@ int HostShare::from_xml_node(const xmlNodePtr node)
rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1);
// ------------ DS Template ---------------
// ------------ Datastores ---------------
ObjectXML::get_nodes("/HOST_SHARE/DATASTORES", content);
@ -120,7 +437,27 @@ int HostShare::from_xml_node(const xmlNodePtr node)
return -1;
}
rc += ds_template.from_xml_node( content[0] );
rc += ds.from_xml_node( content[0] );
ObjectXML::free_nodes(content);
content.clear();
if (rc != 0)
{
return -1;
}
// ------------ PCI Devices ---------------
ObjectXML::get_nodes("/HOST_SHARE/PCI_DEVICES", content);
if( content.empty())
{
return -1;
}
rc += pci.from_xml_node( content[0] );
ObjectXML::free_nodes(content);
@ -134,14 +471,22 @@ int HostShare::from_xml_node(const xmlNodePtr node)
return 0;
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void HostShare::set_ds_monitorization(const vector<Attribute*> &ds_att)
{
vector<Attribute*>::const_iterator it;
ds_template.erase("DS");
ds.erase("DS");
for (it = ds_att.begin(); it != ds_att.end(); it++)
{
ds_template.set(*it);
ds.set(*it);
}
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

View File

@ -69,6 +69,52 @@ class DummyInformationManager < OpenNebulaDriver
results << "DS_LOCATION_TOTAL_MB=20480\n"
results << "DS_LOCATION_FREE_MB=20480\n"
results << "PCI = [
ADDRESS = \"0000:02:00:0\",\n
BUS = \"02\",\n
CLASS = \"0300\",\n
CLASS_NAME = \"VGA compatible controller\",\n
DEVICE = \"0863\",\n
DEVICE_NAME = \"C79 [GeForce 9400M]\",\n
DOMAIN = \"0000\",\n
FUNCTION = \"0\",\n
SHORT_ADDRESS = \"02:00.0\",\n
SLOT = \"00\",\n
TYPE = \"10de:0863:0300\",\n
VENDOR = \"10de\",\n
VENDOR_NAME = \"NVIDIA Corporation\"\n
]\n
PCI = [
ADDRESS = \"0000:00:06:0\",\n
BUS = \"00\",\n
CLASS = \"0c03\",\n
CLASS_NAME = \"USB controller\",\n
DEVICE = \"0aa7\",\n
DEVICE_NAME = \"MCP79 OHCI USB 1.1 Controller\",\n
DOMAIN = \"0000\",\n
FUNCTION = \"0\",\n
SHORT_ADDRESS = \"00:06.0\",\n
SLOT = \"06\",\n
TYPE = \"10de:0aa7:0c03\",\n
VENDOR = \"10de\",\n
VENDOR_NAME = \"NVIDIA Corporation\"\n
]\n
PCI = [
ADDRESS = \"0000:00:06:1\",\n
BUS = \"00\",\n
CLASS = \"0c03\",\n
CLASS_NAME = \"USB controller\",\n
DEVICE = \"0aa9\",\n
DEVICE_NAME = \"MCP79 EHCI USB 2.0 Controller\",\n
DOMAIN = \"0000\",\n
FUNCTION = \"1\",\n
SHORT_ADDRESS = \"00:06.1\",\n
SLOT = \"06\",\n
TYPE = \"10de:0aa9:0c03\",\n
VENDOR = \"10de\",\n
VENDOR_NAME = \"NVIDIA Corporation\"\n
]\n"
results = Base64::encode64(results).strip.delete("\n")
send_message("MONITOR", RESULT[:success], number, results)

View File

@ -0,0 +1,114 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs #
# #
# 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. #
#--------------------------------------------------------------------------- #
# This variable contains the filters for PCI card monitoring. The format
# is the same as lspci and several filters can be added separated by commas.
# A nil filter will retrieve all PCI cards.
#
# From lspci help:
# -d [<vendor>]:[<device>][:<class>]
#
# For example
#
# FILTER = '::0300' # all VGA cards
# FILTER = '10de::0300' # all NVIDIA VGA cards
# FILTER = '10de:11bf:0300' # only GK104GL [GRID K2]
# FILTER = '8086::0300,::0106' # all Intel VGA cards and any SATA controller
FILTER = nil
require 'shellwords'
def get_pci(filter=nil)
command = "lspci -mmnn"
command << " -d #{filter}" if filter
text = %x(#{command})
text.split("\n").map {|l| Shellwords.split(l) }
end
def get_name_and_id(text)
m = text.match(/^(.*) \[(....)\]$/)
return m[1], m[2]
end
def parse_pci(pci)
card = {}
card[:short_address] = pci[0]
card[:libvirt_address] =
"pci_0000_#{card[:short_address].gsub(/[:.]/, '_')}"
card[:address] = "0000:#{card[:short_address].gsub(/[:.]/, ':')}"
card[:class_name], card[:class] = get_name_and_id(pci[1])
card[:vendor_name], card[:vendor] = get_name_and_id(pci[2])
card[:device_name], card[:device] = get_name_and_id(pci[3])
card[:bus], card[:slot], card[:function] = pci[0].split(/[:.]/)
card[:type] = [card[:vendor], card[:device], card[:class]].join(':')
card
end
def get_devices(filter=nil)
if filter
filter = filter.split(',')
else
filter = [nil]
end
filter.map do |f|
get_pci(f).map {|pci| parse_pci(pci) }
end.flatten
end
filter = FILTER
devices = get_devices(filter)
def pval(name, value)
%Q( #{name} = "#{value}")
end
devices.each do |dev|
puts "PCI = ["
values = [
pval('TYPE', dev[:type]),
pval('VENDOR', dev[:vendor]),
pval('VENDOR_NAME', dev[:vendor_name]),
pval('DEVICE', dev[:device]),
pval('DEVICE_NAME', dev[:device_name]),
pval('CLASS', dev[:class]),
pval('CLASS_NAME', dev[:class_name]),
pval('ADDRESS', dev[:address]),
pval('SHORT_ADDRESS', dev[:short_address]),
pval('DOMAIN', '0000'),
pval('BUS', dev[:bus]),
pval('SLOT', dev[:slot]),
pval('FUNCTION', dev[:function])
]
puts values.join(",\n")
puts "]"
end

View File

@ -35,6 +35,7 @@ void LifeCycleManager::deploy_action(int vid)
{
time_t thetime = time(0);
int cpu,mem,disk;
vector<Attribute *> pci;
VirtualMachine::LcmState vm_state;
TransferManager::Actions tm_action;
@ -43,7 +44,7 @@ void LifeCycleManager::deploy_action(int vid)
// PROLOG STATE
//----------------------------------------------------
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
vm_state = VirtualMachine::PROLOG;
tm_action = TransferManager::PROLOG;
@ -75,7 +76,7 @@ void LifeCycleManager::deploy_action(int vid)
//----------------------------------------------------
if (hpool->add_capacity(vm->get_hid(),vm->get_oid(),cpu,mem,disk) == -1)
if (hpool->add_capacity(vm->get_hid(),vm->get_oid(),cpu,mem,disk,pci) == -1)
{
//The host has been deleted, move VM to FAILURE
this->trigger(LifeCycleManager::PROLOG_FAILURE, vid);
@ -211,6 +212,8 @@ void LifeCycleManager::migrate_action(int vid)
VirtualMachine * vm;
int cpu, mem, disk;
vector<Attribute *> pci;
time_t the_time = time(0);
vm = vmpool->get(vid,true);
@ -239,9 +242,9 @@ void LifeCycleManager::migrate_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
//----------------------------------------------------
@ -278,11 +281,12 @@ void LifeCycleManager::migrate_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem,
disk, pci);
//----------------------------------------------------
@ -321,11 +325,12 @@ void LifeCycleManager::migrate_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem,
disk, pci);
//----------------------------------------------------
@ -359,7 +364,8 @@ void LifeCycleManager::live_migrate_action(int vid)
if (vm->get_state() == VirtualMachine::ACTIVE &&
vm->get_lcm_state() == VirtualMachine::RUNNING)
{
int cpu,mem,disk;
int cpu, mem, disk;
vector<Attribute *> pci;
//----------------------------------------------------
// MIGRATE STATE
@ -377,9 +383,9 @@ void LifeCycleManager::live_migrate_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
//----------------------------------------------------
@ -845,6 +851,7 @@ void LifeCycleManager::clean_action(int vid)
void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& image_id)
{
int cpu, mem, disk;
vector<Attribute *> pci;
time_t the_time = time(0);
VirtualMachine::LcmState state = vm->get_lcm_state();
@ -873,8 +880,8 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag
vm->set_vm_info();
vm->set_reason(History::USER);
vm->get_requirements(cpu,mem,disk);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
switch (state)
{
@ -1005,7 +1012,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag
vmpool->update_previous_history(vm);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu,
mem, disk);
mem, disk, pci);
vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid);
vmm->trigger(VirtualMachineManager::CLEANUP_BOTH,vid);
@ -1031,7 +1038,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag
vmpool->update_previous_history(vm);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu,
mem, disk);
mem, disk, pci);
vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid);
vmm->trigger(VirtualMachineManager::CLEANUP_PREVIOUS,vid);

View File

@ -37,8 +37,10 @@ void LifeCycleManager::save_success_action(int vid)
if ( vm->get_lcm_state() == VirtualMachine::SAVE_MIGRATE )
{
int cpu,mem,disk;
time_t the_time = time(0);
int cpu, mem, disk;
vector<Attribute *> pci;
time_t the_time = time(0);
//----------------------------------------------------
// PROLOG_MIGRATE STATE
@ -66,9 +68,9 @@ void LifeCycleManager::save_success_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_previous_hid(),vm->get_oid(),cpu,mem,disk,pci);
//----------------------------------------------------
@ -154,8 +156,10 @@ void LifeCycleManager::save_failure_action(int vid)
if ( vm->get_lcm_state() == VirtualMachine::SAVE_MIGRATE )
{
int cpu,mem,disk;
time_t the_time = time(0);
int cpu, mem, disk;
vector<Attribute *> pci;
time_t the_time = time(0);
//----------------------------------------------------
// RUNNING STATE FROM SAVE_MIGRATE
@ -171,9 +175,9 @@ void LifeCycleManager::save_failure_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
vm->set_previous_etime(the_time);
@ -256,8 +260,10 @@ void LifeCycleManager::deploy_success_action(int vid)
if ( vm->get_lcm_state() == VirtualMachine::MIGRATE )
{
int cpu,mem,disk;
time_t the_time = time(0);
int cpu,mem,disk;
vector<Attribute *> pci;
time_t the_time = time(0);
vm->set_running_stime(the_time);
@ -275,9 +281,9 @@ void LifeCycleManager::deploy_success_action(int vid)
vmpool->update_previous_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_previous_hid(),vm->get_oid(),cpu,mem,disk,pci);
vm->set_state(VirtualMachine::RUNNING);
@ -328,8 +334,10 @@ void LifeCycleManager::deploy_failure_action(int vid)
if ( vm->get_lcm_state() == VirtualMachine::MIGRATE )
{
int cpu,mem,disk;
time_t the_time = time(0);
int cpu, mem, disk;
vector<Attribute *> pci;
time_t the_time = time(0);
//----------------------------------------------------
// RUNNING STATE FROM MIGRATE
@ -357,9 +365,9 @@ void LifeCycleManager::deploy_failure_action(int vid)
vmpool->update_previous_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
// --- Add new record by copying the previous one
@ -789,8 +797,10 @@ void LifeCycleManager::prolog_failure_action(int vid)
void LifeCycleManager::epilog_success_action(int vid)
{
VirtualMachine * vm;
time_t the_time = time(0);
int cpu,mem,disk;
vector<Attribute *> pci;
time_t the_time = time(0);
int cpu,mem,disk;
VirtualMachine::LcmState state;
DispatchManager::Actions action;
@ -859,9 +869,9 @@ void LifeCycleManager::epilog_success_action(int vid)
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
vm->get_requirements(cpu, mem, disk, pci);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk);
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
//----------------------------------------------------

View File

@ -938,7 +938,7 @@ EOT
# Calculate the host's xml and write them to host_pool_new
@db.transaction do
@db[:host_pool].each do |row|
host_doc = Document.new(row[:body])
host_doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
hid = row[:oid]
@ -949,54 +949,67 @@ EOT
mem_usage = counters_host[:memory]*1024
# rewrite running_vms
host_doc.root.each_element("HOST_SHARE/RUNNING_VMS") {|e|
host_doc.root.xpath("HOST_SHARE/RUNNING_VMS").each {|e|
if e.text != rvms.to_s
log_error(
"Host #{hid} RUNNING_VMS has #{e.text} \tis\t#{rvms}")
e.text = rvms
e.content = rvms
end
}
# re-do list of VM IDs
vms_elem = host_doc.root.elements.delete("VMS")
vms_elem = host_doc.root.at_xpath("VMS").remove
vms_new_elem = host_doc.root.add_element("VMS")
vms_new_elem = host_doc.create_element("VMS")
host_doc.root.add_child(vms_new_elem)
counters_host[:rvms].each do |id|
id_elem = vms_elem.elements.delete("ID[.=#{id}]")
id_elem = vms_elem.at_xpath("ID[.=#{id}]")
if id_elem.nil?
log_error(
"VM #{id} is missing from Host #{hid} VM id list")
else
id_elem.remove
end
vms_new_elem.add_element("ID").text = id.to_s
vms_new_elem.add_child(host_doc.create_element("ID")).content = id.to_s
end
vms_elem.each_element("ID") do |id_elem|
vms_elem.xpath("ID").each do |id_elem|
log_error(
"VM #{id_elem.text} is in Host #{hid} VM id list, "<<
"but it should not")
end
host_doc.root.xpath("HOST_SHARE/PCI_DEVICES/PCI").each do |pci|
if !pci.at_xpath("VMID").nil?
vmid = pci.at_xpath("VMID").text.to_i
if vmid != -1 && !counters_host[:rvms].include?(vmid)
log_error("VM #{vmid} has a PCI device assigned in host #{hid}, but it should not. Device: #{pci.at_xpath('DEVICE_NAME').text}")
pci.at_xpath("VMID").content = "-1"
end
end
end
# rewrite cpu
host_doc.root.each_element("HOST_SHARE/CPU_USAGE") {|e|
host_doc.root.xpath("HOST_SHARE/CPU_USAGE").each {|e|
if e.text != cpu_usage.to_s
log_error(
"Host #{hid} CPU_USAGE has #{e.text} "<<
"\tis\t#{cpu_usage}")
e.text = cpu_usage
e.content = cpu_usage
end
}
# rewrite memory
host_doc.root.each_element("HOST_SHARE/MEM_USAGE") {|e|
host_doc.root.xpath("HOST_SHARE/MEM_USAGE").each {|e|
if e.text != mem_usage.to_s
log_error("Host #{hid} MEM_USAGE has #{e.text} "<<
"\tis\t#{mem_usage}")
e.text = mem_usage
e.content = mem_usage
end
}

View File

@ -113,6 +113,34 @@ module Migrator
log_time()
@db.run "ALTER TABLE host_pool RENAME TO old_host_pool;"
@db.run "CREATE TABLE host_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, state INTEGER, last_mon_time INTEGER, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, cid INTEGER, UNIQUE(name));"
@db.transaction do
@db.fetch("SELECT * FROM old_host_pool") do |row|
doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
doc.root.at_xpath("HOST_SHARE").add_child(doc.create_element("PCI_DEVICES"))
@db[:host_pool].insert(
:oid => row[:oid],
:name => row[:name],
:body => doc.root.to_s,
:state => row[:state],
:last_mon_time => row[:last_mon_time],
:uid => row[:uid],
:gid => row[:gid],
:owner_u => row[:owner_u],
:group_u => row[:group_u],
:other_u => row[:other_u],
:cid => row[:cid])
end
end
@db.run "DROP TABLE old_host_pool;"
log_time()
return true
end

View File

@ -375,17 +375,20 @@ int RequestManagerVirtualMachine::get_host_information(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool RequestManagerVirtualMachine::check_host(int hid,
int cpu,
int mem,
int disk,
string& error)
bool RequestManagerVirtualMachine::check_host(
int hid, bool enforce, VirtualMachine* vm, string& error)
{
Nebula& nd = Nebula::instance();
HostPool * hpool = nd.get_hpool();
Host * host;
bool test;
string capacity_error;
int cpu, mem, disk;
vector<Attribute *> pci;
vm->get_requirements(cpu, mem, disk, pci);
host = hpool->get(hid, true);
@ -395,14 +398,22 @@ bool RequestManagerVirtualMachine::check_host(int hid,
return false;
}
test = host->test_capacity(cpu, mem, disk);
if (!enforce)
{
cpu = 0;
mem = 0;
disk = 0;
}
test = host->test_capacity(cpu, mem, disk, pci, capacity_error);
if (!test)
{
ostringstream oss;
oss << object_name(PoolObjectSQL::HOST)
<< " " << hid << " does not have enough capacity.";
oss << object_name(PoolObjectSQL::VM) << " [" << vm->get_oid()
<< "] does not fit in " << object_name(PoolObjectSQL::HOST)
<< " [" << hid << "]. " << capacity_error;
error = oss.str();
}
@ -662,6 +673,8 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
bool auth = false;
string error;
// ------------------------------------------------------------------------
// Get request parameters and information about the target host
// ------------------------------------------------------------------------
@ -814,25 +827,12 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
return;
}
if (enforce)
if (check_host(hid, enforce, vm, error) == false)
{
int cpu, mem, disk;
string error;
vm->get_requirements(cpu, mem, disk);
vm->unlock();
if (check_host(hid, cpu, mem, disk, error) == false)
{
failure_response(ACTION, request_error(error,""), att);
return;
}
if ((vm = get_vm(id, att)) == 0)
{
return;
}
failure_response(ACTION, request_error(error,""), att);
return;
}
// ------------------------------------------------------------------------
@ -897,6 +897,8 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList
bool auth = false;
string error;
// ------------------------------------------------------------------------
// Get request parameters and information about the target host
// ------------------------------------------------------------------------
@ -1031,26 +1033,16 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList
}
// Check the host has enough capacity
if (enforce)
{
int cpu, mem, disk;
string error;
vm->get_requirements(cpu, mem, disk);
vm->unlock();
if (check_host(hid, cpu, mem, disk, error) == false)
{
failure_response(ACTION, request_error(error,""), att);
return;
}
}
else
if (check_host(hid, enforce, vm, error) == false)
{
vm->unlock();
failure_response(ACTION, request_error(error,""), att);
return;
}
vm->unlock();
// Check we are in the same cluster
Host * host = nd.get_hpool()->get(c_hid, true);
@ -1831,6 +1823,9 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
int dcpu_host = (int) (dcpu * 100);//now in 100%
int dmem_host = dmemory * 1024; //now in Kilobytes
vector<Attribute *> empty_pci;
string error;
host = hpool->get(hid, true);
if (host == 0)
@ -1844,7 +1839,7 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
return;
}
if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0) == false)
if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0, empty_pci, error) == false)
{
ostringstream oss;

View File

@ -20,6 +20,7 @@
#include <map>
#include "ObjectXML.h"
#include "HostShare.h"
using namespace std;
@ -50,21 +51,24 @@ public:
* Tests whether a new VM can be hosted by the host or not
* @param cpu needed by the VM (percentage)
* @param mem needed by the VM (in KB)
* @param pci devices needed by the VM
* @param error error message
* @return true if the share can host the VM
*/
bool test_capacity(long long cpu, long long mem, string & error) const;
bool test_capacity(long long cpu, long long mem, vector<Attribute *> &pci,
string & error);
/**
* Tests whether a new VM can be hosted by the host or not
* @param cpu needed by the VM (percentage)
* @param mem needed by the VM (in KB)
* @param pci devices needed by the VM
* @return true if the share can host the VM
*/
bool test_capacity(long long cpu, long long mem) const
bool test_capacity(long long cpu,long long mem,vector<Attribute *> &p)
{
string tmp_st;
return test_capacity(cpu, mem, tmp_st);
return test_capacity(cpu, mem, p, tmp_st);
};
/**
@ -74,11 +78,14 @@ public:
* @param mem needed by the VM (in KB)
* @return 0 on success
*/
void add_capacity(long long cpu, long long mem)
void add_capacity(int vmid, long long cpu, long long mem,
vector<Attribute *> &p)
{
cpu_usage += cpu;
mem_usage += mem;
pci.add(p, vmid);
running_vms++;
};
@ -131,6 +138,12 @@ public:
return public_cloud;
}
/**
* Prints the Host information to an output stream. This function is used
* for logging purposes.
*/
friend ostream& operator<<(ostream& o, const HostXML& p);
private:
int oid;
int cluster_id;
@ -150,6 +163,8 @@ private:
bool public_cloud;
HostSharePCI pci;
// Configuration attributes
static const char *host_paths[]; /**< paths for search function */

View File

@ -116,7 +116,8 @@ public:
return ds_requirements;
}
void get_requirements (int& cpu, int& memory, long long& disk);
void get_requirements (int& cpu, int& memory, long long& disk,
vector<Attribute *> &pci);
map<int,long long> get_storage_usage();

View File

@ -29,11 +29,13 @@ int HostPoolXML::set_up()
{
oss << "Discovered Hosts (enabled):" << endl;
map<int,ObjectXML*>::iterator it;
map<int, ObjectXML*>::iterator it;
for (it=objects.begin();it!=objects.end();it++)
{
oss << " " << it->first;
HostXML * h = dynamic_cast<HostXML *>(it->second);
oss << *h << endl;
}
}
else

View File

@ -16,6 +16,8 @@
#include <math.h>
#include <sstream>
#include <stdexcept>
#include <iomanip>
#include "HostXML.h"
#include "NebulaUtil.h"
@ -36,36 +38,50 @@ const char *HostXML::host_paths[] = {
void HostXML::init_attributes()
{
xpath(oid, "/HOST/ID", -1);
xpath(cluster_id, "/HOST/CLUSTER_ID", -1);
xpath(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0);
xpath(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0);
xpath(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0);
xpath(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0);
xpath(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0);
xpath(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0);
xpath(oid, "/HOST/ID", -1);
xpath(cluster_id, "/HOST/CLUSTER_ID", -1);
xpath(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0);
xpath(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0);
xpath(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0);
xpath(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0);
xpath(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0);
xpath(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0);
string public_cloud_st;
xpath(public_cloud_st, "/HOST/TEMPLATE/PUBLIC_CLOUD", "");
public_cloud = (one_util::toupper(public_cloud_st) == "YES");
vector<string> ds_ids = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/ID"];
vector<string> ds_free_mb = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB"];
//-------------------- HostShare Datastores ------------------------------
vector<string> ds_ids = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/ID"];
vector<string> ds_free = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB"];
int id;
long long disk;
for (size_t i = 0; i < ds_ids.size() && i < ds_free_mb.size(); i++)
for (size_t i = 0; i < ds_ids.size() && i < ds_free.size(); i++)
{
id = atoi(ds_ids[i].c_str());
disk = atoll(ds_free_mb[i].c_str());
disk = atoll(ds_free[i].c_str());
ds_free_disk[id] = disk;
}
//Init search xpath routes
//-------------------- HostShare PCI Devices ------------------------------
vector<xmlNodePtr> content;
get_nodes("/HOST/HOST_SHARE/PCI_DEVICES", content);
if( !content.empty())
{
pci.from_xml_node(content[0]);
free_nodes(content);
content.clear();
}
//-------------------- Init search xpath routes ---------------------------
ObjectXML::paths = host_paths;
ObjectXML::num_paths = host_num_paths;
}
@ -111,30 +127,46 @@ int HostXML::search(const char *name, int& value)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool HostXML::test_capacity(long long cpu, long long mem, string & error) const
bool HostXML::test_capacity(long long cpu, long long mem,
vector<Attribute *>& p, string & error)
{
bool fits = (((max_cpu - cpu_usage ) >= cpu) &&
((max_mem - mem_usage ) >= mem));
bool pci_fits = pci.test(p);
bool fits = ((max_cpu - cpu_usage ) >= cpu) &&
((max_mem - mem_usage ) >= mem) &&
pci_fits;
if (!fits)
{
if (NebulaLog::log_level() >= Log::DDEBUG)
{
ostringstream oss;
if ( pci_fits )
{
ostringstream oss;
oss << "Not enough capacity. "
<< "Requested: "
<< cpu << " CPU, "
<< mem << " KB MEM; "
<< "Available: "
<< (max_cpu - cpu_usage ) << " CPU, "
<< (max_mem - mem_usage ) << " KB MEM";
oss << "Not enough capacity. "
<< "Requested: "
<< cpu << " CPU, "
<< mem << " KB MEM; "
<< "Available: "
<< (max_cpu - cpu_usage ) << " CPU, "
<< (max_mem - mem_usage ) << " KB MEM";
error = oss.str();
error = oss.str();
}
else
{
error = "Unavailable PCI device.";
}
}
else
{
error = "Not enough capacity.";
if ( pci_fits )
{
error = "Not enough capacity.";
}
else
{
error = "Unavailable PCI device.";
}
}
}
@ -169,3 +201,33 @@ void HostXML::add_ds_capacity(int dsid, long long vm_disk_mb)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ostream& operator<<(ostream& o, const HostXML& p)
{
map<int, long long>::const_iterator it;
o << "ID : " << p.oid << endl;
o << "CLUSTER_ID : " << p.cluster_id << endl;
o << "MEM_USAGE : " << p.mem_usage << endl;
o << "CPU_USAGE : " << p.cpu_usage << endl;
o << "MAX_MEM : " << p.max_mem << endl;
o << "MAX_CPU : " << p.max_cpu << endl;
o << "FREE_DISK : " << p.free_disk << endl;
o << "RUNNING_VMS : " << p.running_vms << endl;
o << "PUBLIC : " << p.public_cloud << endl;
o << endl
<< right << setw(5) << "DSID" << " "
<< right << setw(15) << "FREE_MB" << " "
<< endl << setw(30) << setfill('-') << "-" << setfill (' ') << endl;
for (it = p.ds_free_disk.begin() ; it != p.ds_free_disk.end() ; it++)
{
o << right << setw(5) << it->first << " "
<< right << setw(15)<< it->second<< " " << endl;
}
o << endl << p.pci;
return o;
}

View File

@ -39,6 +39,7 @@ int VirtualMachinePoolXML::set_up()
<< right << setw(8) << "VM" << " "
<< right << setw(4) << "CPU" << " "
<< right << setw(11) << "Memory" << " "
<< right << setw(3) << "PCI" << " "
<< right << setw(11) << "System DS" << " "
<< " Image DS"
<< endl << setw(60) << setfill('-') << "-" << setfill(' ');
@ -47,11 +48,13 @@ int VirtualMachinePoolXML::set_up()
{
int cpu, mem;
long long disk;
vector<Attribute *> pci;
string action = "DEPLOY";
VirtualMachineXML * vm = static_cast<VirtualMachineXML *>(it->second);
vm->get_requirements(cpu, mem, disk);
vm->get_requirements(cpu, mem, disk, pci);
if (vm->is_resched())
{
@ -67,6 +70,7 @@ int VirtualMachinePoolXML::set_up()
<< right << setw(8) << it->first << " "
<< right << setw(4) << cpu << " "
<< right << setw(11) << mem << " "
<< right << setw(3) << pci.size() << " "
<< right << setw(11) << disk << " ";
map<int,long long> ds_usage = vm->get_storage_usage();

View File

@ -202,8 +202,16 @@ ostream& operator<<(ostream& os, VirtualMachineXML& vm)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineXML::get_requirements (int& cpu, int& memory, long long& disk)
void VirtualMachineXML::get_requirements (int& cpu, int& memory,
long long& disk, vector<Attribute *> &pci)
{
pci.clear();
if (vm_template != 0)
{
vm_template->get("PCI", pci);
}
if (this->memory == 0 || this->cpu == 0)
{
cpu = 0;

View File

@ -39,6 +39,7 @@ sched_env.Prepend(LIBS=[
'nebula_core',
'nebula_template',
'nebula_vm',
'nebula_host',
'crypto',
'xml2'
])

View File

@ -502,6 +502,7 @@ int Scheduler::set_up_pools()
* @param vm the virtual machine
* @param vm_memory vm requirement
* @param vm_cpu vm requirement
* @param vm_pci vm requirement
* @param host to evaluate vm assgiment
* @param n_auth number of hosts authorized for the user, incremented if needed
* @param n_error number of requirement errors, incremented if needed
@ -511,8 +512,8 @@ int Scheduler::set_up_pools()
* @return true for a positive match
*/
static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu,
HostXML * host, int &n_auth, int& n_error, int &n_fits, int &n_matched,
string &error)
vector<Attribute *>& vpci, HostXML * host, int &n_auth, int& n_error,
int &n_fits, int &n_matched, string &error)
{
// -------------------------------------------------------------------------
// Filter current Hosts for resched VMs
@ -560,7 +561,7 @@ static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu,
// -------------------------------------------------------------------------
// Check host capacity
// -------------------------------------------------------------------------
if (host->test_capacity(vcpu,vmem,error) != true)
if (host->test_capacity(vcpu, vmem, vpci, error) != true)
{
return false;
}
@ -720,6 +721,7 @@ void Scheduler::match_schedule()
int vm_memory;
int vm_cpu;
long long vm_disk;
vector<Attribute *> vm_pci;
int n_resources;
int n_matched;
@ -750,7 +752,7 @@ void Scheduler::match_schedule()
{
vm = static_cast<VirtualMachineXML*>(vm_it->second);
vm->get_requirements(vm_cpu,vm_memory,vm_disk);
vm->get_requirements(vm_cpu, vm_memory, vm_disk, vm_pci);
n_resources = 0;
n_fits = 0;
@ -790,8 +792,8 @@ void Scheduler::match_schedule()
{
host = static_cast<HostXML *>(h_it->second);
if (match_host(acls, vm, vm_memory, vm_cpu, host, n_auth, n_error,
n_fits, n_matched, m_error))
if (match_host(acls, vm, vm_memory, vm_cpu, vm_pci, host, n_auth,
n_error, n_fits, n_matched, m_error))
{
vm->add_match_host(host->get_hid());
@ -1026,6 +1028,8 @@ void Scheduler::dispatch()
int cpu, mem;
long long dsk;
vector<Attribute *> pci;
int hid, dsid, cid;
bool test_cap_result;
@ -1074,7 +1078,7 @@ void Scheduler::dispatch()
}
}
vm->get_requirements(cpu,mem,dsk);
vm->get_requirements(cpu, mem, dsk, pci);
//----------------------------------------------------------------------
// Get the highest ranked host and best System DS for it
@ -1094,7 +1098,7 @@ void Scheduler::dispatch()
//------------------------------------------------------------------
// Test host capacity
//------------------------------------------------------------------
if (host->test_capacity(cpu,mem) != true)
if (host->test_capacity(cpu, mem, pci) != true)
{
continue;
}
@ -1224,7 +1228,7 @@ void Scheduler::dispatch()
vm->add_image_datastore_capacity(img_dspool);
}
host->add_capacity(cpu,mem);
host->add_capacity(vm->get_oid(), cpu, mem, pci);
host_vms[hid]++;

View File

@ -281,6 +281,8 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
ostringstream oss;
vector<Attribute *> pci;
// ------------------------------------------------------------------------
// Set a name if the VM has not got one and VM_ID
// ------------------------------------------------------------------------
@ -442,6 +444,26 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
goto error_leases_rollback;
}
// ------------------------------------------------------------------------
// PCI Devices
// ------------------------------------------------------------------------
user_obj_template->remove("PCI", pci);
for (vector<Attribute *>::iterator it = pci.begin(); it !=pci.end(); )
{
if ( (*it)->type() != Attribute::VECTOR )
{
delete *it;
it = pci.erase(it);
}
else
{
obj_template->set(*it);
++it;
}
}
// -------------------------------------------------------------------------
// Parse the context & requirements
// -------------------------------------------------------------------------
@ -1649,11 +1671,14 @@ void VirtualMachine::cp_previous_history()
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk,
vector<Attribute *>& pci_devs)
{
istringstream iss;
float fcpu;
pci_devs.clear();
if ((get_template_attribute("MEMORY",memory) == false) ||
(get_template_attribute("CPU",fcpu) == false))
{
@ -1668,6 +1693,8 @@ void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
memory = memory * 1024; //now in Kilobytes
disk = 0;
obj_template->get("PCI", pci_devs);
return;
}

View File

@ -173,6 +173,13 @@ int LibVirtDriver::deployment_description_kvm(
const VectorAttribute * input;
const VectorAttribute * pci;
string domain = "";
/* bus is already defined for disks */
string slot = "";
string func = "";
const VectorAttribute * features;
bool pae = false;
@ -949,6 +956,50 @@ int LibVirtDriver::deployment_description_kvm(
attrs.clear();
// ------------------------------------------------------------------------
// PCI Passthrough
// ------------------------------------------------------------------------
num = vm->get_template_attribute("PCI",attrs);
for (int i=0; i < num ;i++)
{
pci = dynamic_cast<const VectorAttribute *>(attrs[i]);
if ( pci == 0 )
{
continue;
}
domain = pci->vector_value("DOMAIN");
bus = pci->vector_value("BUS");
slot = pci->vector_value("SLOT");
func = pci->vector_value("FUNCTION");
if ( domain.empty() || bus.empty() || slot.empty() || func.empty() )
{
vm->log("VMM", Log::WARNING,
"DOMAIN, BUS, SLOT and FUNC must be defined for PCI "
"passthrough. Ignored.");
continue;
}
file << "\t\t<hostdev mode='subsystem' type='pci' managed='yes'>";
file << endl;
file << "\t\t\t<source>" << endl;
file << "\t\t\t\t<address ";
file << "domain='0x" << domain << "' ";
file << "bus='0x" << bus << "' ";
file << "slot='0x" << slot << "' ";
file << "function='0x" << func << "'/>" << endl;
file << "\t\t\t</source>" << endl;
file << "\t\t</hostdev>" << endl;
}
attrs.clear();
file << "\t</devices>" << endl;
// ------------------------------------------------------------------------