mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-28 14:50:08 +03:00
F #3256: Support for NUMA topology, Hugepages and CPU pinning.
This commit is contained in:
parent
b75c5fc02a
commit
3b9ace0577
@ -280,97 +280,55 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new VM to the given share by incrementing the cpu, mem and disk
|
||||
* counters
|
||||
* @param vm_id id of the vm to add to the host
|
||||
* @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
|
||||
* Adds a new VM to the host share by incrementing usage counters
|
||||
* @param sr the capacity request of the VM
|
||||
* @return 0 on success
|
||||
*/
|
||||
void add_capacity(int vm_id, long long cpu, long long mem, long long disk,
|
||||
vector<VectorAttribute *> pci)
|
||||
void add_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
if ( vm_collection.add(vm_id) == 0 )
|
||||
if ( vm_collection.add(sr.vmid) == 0 )
|
||||
{
|
||||
host_share.add(vm_id, cpu, mem, disk, pci);
|
||||
host_share.add(sr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Trying to add VM " << vm_id
|
||||
<< ", that it is already associated to host " << oid << ".";
|
||||
oss << "VM " << sr.vmid << " is already in host " << oid << ".";
|
||||
|
||||
NebulaLog::log("ONE", Log::ERROR, oss);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a new VM from the given share by decrementing the cpu,mem and
|
||||
* disk counters
|
||||
* @param vm_id id of the vm to delete from the host
|
||||
* @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
|
||||
* Deletes a new VM to the host share by incrementing usage counters
|
||||
* @param sr the capacity request of the VM
|
||||
* @return 0 on success
|
||||
*/
|
||||
void del_capacity(int vm_id, long long cpu, long long mem, long long disk,
|
||||
const vector<VectorAttribute *>& pci)
|
||||
void del_capacity(HostShareCapacity& sr)
|
||||
{
|
||||
if ( vm_collection.del(vm_id) == 0 )
|
||||
if ( vm_collection.del(sr.vmid) == 0 )
|
||||
{
|
||||
host_share.del(cpu, mem, disk, pci);
|
||||
host_share.del(sr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Trying to remove VM " << vm_id
|
||||
<< ", that it is not associated to host " << oid << ".";
|
||||
oss << "VM " << sr.vmid << " is not in host " << oid << ".";
|
||||
|
||||
NebulaLog::log("ONE", Log::ERROR, oss);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the capacity used in a host when a VM is resized
|
||||
* counters
|
||||
* @param cpu increment of cpu requested by the VM
|
||||
* @param mem increment of memory requested by the VM
|
||||
* @param disk not used
|
||||
* @return 0 on success
|
||||
*/
|
||||
void update_capacity(int cpu, long int mem, int disk)
|
||||
{
|
||||
host_share.update(cpu,mem,disk);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 disk needed by the VM
|
||||
* @param pci devices needed by the VM
|
||||
* @param error Returns the error reason, if any
|
||||
* Tests whether a VM device capacity can be allocated in the host
|
||||
* @param sr capacity requested 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,
|
||||
vector<VectorAttribute *> &pci, string& error) const
|
||||
bool test_capacity(HostShareCapacity &sr, string& error)
|
||||
{
|
||||
return host_share.test(cpu, mem, disk, pci, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a new VM can be hosted by the host or not, checking the
|
||||
* PCI devices only.
|
||||
* @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(vector<VectorAttribute *> &pci, string& error) const
|
||||
{
|
||||
return host_share.test(pci, error);
|
||||
return host_share.test(sr, error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,15 +211,14 @@ public:
|
||||
*
|
||||
* @return 0 on success -1 in case of failure
|
||||
*/
|
||||
int add_capacity(int oid, int vm_id, int cpu, int mem, int disk,
|
||||
vector<VectorAttribute *> pci)
|
||||
int add_capacity(int oid, HostShareCapacity &sr)
|
||||
{
|
||||
int rc = 0;
|
||||
Host * host = get(oid);
|
||||
|
||||
if ( host != 0 )
|
||||
{
|
||||
host->add_capacity(vm_id, cpu, mem, disk, pci);
|
||||
host->add_capacity(sr);
|
||||
|
||||
update(host);
|
||||
|
||||
@ -242,14 +241,13 @@ public:
|
||||
* @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,
|
||||
vector<VectorAttribute *> pci)
|
||||
void del_capacity(int oid, HostShareCapacity &sr)
|
||||
{
|
||||
Host * host = get(oid);
|
||||
|
||||
if ( host != 0 )
|
||||
{
|
||||
host->del_capacity(vm_id, cpu, mem, disk, pci);
|
||||
host->del_capacity(sr);
|
||||
|
||||
update(host);
|
||||
|
||||
|
@ -21,10 +21,51 @@
|
||||
#include "Template.h"
|
||||
#include <time.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
//Forward declarations
|
||||
class Host;
|
||||
class HostShareNUMA;
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* This class represents a HostShare capacity allocation from a VM. The following
|
||||
* attributes are updated with the final allocation in the Host:
|
||||
* - topology, number of sockets, cores and threads
|
||||
* - pci, with device address
|
||||
* - nodes with the numa nodes configured for the VM
|
||||
*
|
||||
* NUMA node requests are described by an attribute:
|
||||
*
|
||||
* NUMA_NODE = [ TOTAL_CPUS=, MEMORY="...", CPUS="...", NODE_ID="...",
|
||||
* MEMORY_NODE_ID="..." ]
|
||||
*
|
||||
* CPUS: list of CPU IDs to pin the vCPUs in this host
|
||||
* NODE_ID: the ID of the numa node in the host to pin this virtual node
|
||||
* MEMORY_NODE_ID: the ID of the node to allocate memory for this virtual node
|
||||
*/
|
||||
struct HostShareCapacity
|
||||
{
|
||||
int vmid;
|
||||
|
||||
unsigned int vcpu;
|
||||
|
||||
long long cpu;
|
||||
long long mem;
|
||||
long long disk;
|
||||
|
||||
vector<VectorAttribute *> pci;
|
||||
|
||||
VectorAttribute * topology;
|
||||
|
||||
vector<VectorAttribute *> nodes;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
class HostShareDatastore : public Template
|
||||
{
|
||||
public:
|
||||
@ -33,6 +74,9 @@ public:
|
||||
virtual ~HostShareDatastore(){};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This class represents a PCI DEVICE list for the host. The list is in the
|
||||
* form:
|
||||
@ -161,7 +205,391 @@ private:
|
||||
map <string, PCIDevice *> pci_devices;
|
||||
};
|
||||
|
||||
class Host;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This class represents the NUMA nodes in a hypervisor for the following attr:
|
||||
* NODE_ID = 0
|
||||
* HUGEPAGE = [ SIZE = "2048", PAGES = "0", FREE = "0"]
|
||||
* HUGEPAGE = [ SIZE = "1048576", PAGES = "0", FREE = "0"]
|
||||
* CORE = [ ID = "3", CPUS = "3:-1,7:-1", FREE = 2]
|
||||
* CORE = [ ID = "1", CPUS = "1:23,5:-1", FREE = 0 ]
|
||||
* CORE = [ ID = "2", CPUS = "2:47,6:-1", FREE = 1]
|
||||
* CORE = [ ID = "0", CPUS = "0:23,4:-1", FREE = 0]
|
||||
* MEMORY = [ TOTAL = "66806708", FREE = "390568", USED = "66416140",
|
||||
* DISTANCE = "0 1", USAGE = "8388608" ]
|
||||
*
|
||||
* - NODE_ID
|
||||
* - HUGEPAGE is the total PAGES and FREE hugepages of a given SIZE in the node
|
||||
* - CORE is a CPU core with its ID and sibling CPUs for HT architectures
|
||||
*/
|
||||
class HostShareNode : public Template
|
||||
{
|
||||
public:
|
||||
HostShareNode() : Template(false, '=', "NODE"){};
|
||||
|
||||
HostShareNode(unsigned int i) : Template(false, '=', "NODE"), node_id(i)
|
||||
{
|
||||
replace("NODE_ID", i);
|
||||
};
|
||||
|
||||
virtual ~HostShareNode(){};
|
||||
|
||||
/**
|
||||
* Builds the node from its XML representation. This function is used when
|
||||
* loading the host from the DB.
|
||||
* @param node xmlNode for the template
|
||||
* @return 0 on success
|
||||
*/
|
||||
int from_xml_node(const xmlNodePtr &node);
|
||||
|
||||
/**
|
||||
* Get free capacity of the node
|
||||
* @param fcpus number of free virtual cores
|
||||
* @param memory free in the node
|
||||
* @param threads_core per virtual core
|
||||
*/
|
||||
void free_capacity(unsigned int &fcpus, long long &memory, unsigned int tc);
|
||||
|
||||
void free_dedicated_capacity(unsigned int &fcpus, long long &memory);
|
||||
|
||||
/**
|
||||
* Allocate tcpus with a dedicated policy
|
||||
* @param id of the VM allocating the CPUs
|
||||
* @param tcpus total number of cpus
|
||||
* @param c_s the resulting allocation string CPUS="0,4,2,6"
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int allocate_dedicated_cpus(int id, unsigned int tcpus, std::string &c_s);
|
||||
|
||||
/**
|
||||
* Allocate tcpus with a HT policy
|
||||
* @param id of the VM allocating the CPUs
|
||||
* @param tcpus total number of cpus
|
||||
* @param tc allocate cpus in tc (threads/core) chunks
|
||||
* @param c_s the resulting allocation string CPUS="0,4,2,6"
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int allocate_ht_cpus(int id, unsigned int tcpus, unsigned int tc,
|
||||
std::string &c_s);
|
||||
|
||||
/**
|
||||
* Remove allocation for the given CPUs
|
||||
* @param cpu_ids list of cpu ids to free, comma separated
|
||||
*/
|
||||
void del_cpu(const std::string &cpu_ids);
|
||||
|
||||
/**
|
||||
* Remove memory allocation
|
||||
* @param memory to free
|
||||
*/
|
||||
void del_memory(long long memory)
|
||||
{
|
||||
mem_usage -= memory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the NUMA node to an output stream.
|
||||
*/
|
||||
friend ostream& operator<<(ostream& o, const HostShareNode& n);
|
||||
|
||||
private:
|
||||
friend class HostShareNUMA;
|
||||
|
||||
//This stuct represents a core and its allocation status
|
||||
struct Core
|
||||
{
|
||||
/**
|
||||
* Initializes the structure from the CORE attributes:
|
||||
* @param _i ID of core
|
||||
* @param _c CPUS list <cpu_id>:<vm_id>
|
||||
* @param _f FREE cpus in core. If -1 it will be derived from CPUS
|
||||
*/
|
||||
Core(unsigned int _i, const std::string& _c, int _f);
|
||||
|
||||
/**
|
||||
* ID of this CPU CORE
|
||||
*/
|
||||
unsigned int id;
|
||||
|
||||
/**
|
||||
* Number of free cpus in the core. A VM can use one thread but
|
||||
* reserve all the cpus in the core when using the dedicated policy.
|
||||
*/
|
||||
unsigned int free_cpus;
|
||||
|
||||
/**
|
||||
* cpu_id - vm_id map. represents assigment status of the
|
||||
* cpu thread, (-1) means the VM is free.
|
||||
*/
|
||||
std::map<unsigned int, int> cpus;
|
||||
|
||||
/**
|
||||
* @return a VectorAttribute representing this core in the form:
|
||||
* CORE = [ ID = "3", CPUS = "3:-1,7:-1", FREE = 2]
|
||||
*/
|
||||
VectorAttribute * to_attribute();
|
||||
};
|
||||
|
||||
//This stuct represents the hugepages available in the node
|
||||
struct HugePage
|
||||
{
|
||||
unsigned long size_kb;
|
||||
|
||||
unsigned int nr;
|
||||
unsigned int free;
|
||||
|
||||
unsigned long usage;
|
||||
unsigned long allocated;
|
||||
|
||||
/**
|
||||
* @return a VectorAttribute representing this core in the form:
|
||||
* HUGEPAGE = [ SIZE = "1048576", PAGES = "200", FREE = "100",
|
||||
* USAGE = "100"]
|
||||
*/
|
||||
VectorAttribute * to_attribute();
|
||||
};
|
||||
|
||||
/**
|
||||
* ID of this node as reported by the Host
|
||||
*/
|
||||
unsigned int node_id;
|
||||
|
||||
/**
|
||||
* Threads per core in this node
|
||||
*/
|
||||
unsigned int threads_core = 1;
|
||||
|
||||
/**
|
||||
* CPU Cores in this node
|
||||
*/
|
||||
std::map<unsigned int, struct Core> cores;
|
||||
|
||||
/**
|
||||
* Huge pages configured in this node
|
||||
*/
|
||||
std::map<unsigned long, struct HugePage> pages;
|
||||
|
||||
/**
|
||||
* Memory information for this node:
|
||||
* - total, free and used memory as reported by IM (meminfo file)
|
||||
* - mem_used memory allocated to VMs by oned in this node
|
||||
* - distance sorted list of nodes, first is the closest (this one)
|
||||
*/
|
||||
long long total_mem = 0;
|
||||
long long free_mem = 0;
|
||||
long long used_mem = 0;
|
||||
|
||||
long long mem_usage = 0;
|
||||
|
||||
std::vector<unsigned int> distance;
|
||||
|
||||
/**
|
||||
* Temporal allocation on the node. This is used by the scheduling
|
||||
*/
|
||||
unsigned int allocated_cpus = 0;
|
||||
long long allocated_memory = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new Core element and associates it to this node. If the
|
||||
* core already exists this function does nothing
|
||||
* @param id of core
|
||||
* @param cpus string representing the cpu_id and allocation
|
||||
* @param free cpus in core -1 to derive them from cpus string
|
||||
* @param update if true also adds the core to the object Template
|
||||
*/
|
||||
void set_core(unsigned int id, std::string& cpus, int free, bool update);
|
||||
|
||||
/**
|
||||
* Regenerate the template representation of the CORES for this node.
|
||||
*/
|
||||
void update_cores();
|
||||
|
||||
/**
|
||||
* Regenerate the template representation of the HUGEPAGES for this node.
|
||||
*/
|
||||
void update_hugepages();
|
||||
|
||||
/**
|
||||
* Creates a new HugePage element and associates it to this node. If a
|
||||
* hugepage of the same size already exists this function does nothing
|
||||
* @param size in kb of the page
|
||||
* @param nr number of pages
|
||||
* @param free pages
|
||||
* @param update if true also adds the page to the object Template
|
||||
*/
|
||||
void set_hugepage(unsigned long size, unsigned int nr, unsigned int fr,
|
||||
unsigned long usage, bool update);
|
||||
|
||||
void update_hugepage(unsigned long size);
|
||||
|
||||
/**
|
||||
* Adds a new memory attribute based on the moniroting attributes and
|
||||
* current mem usage.
|
||||
*/
|
||||
void set_memory();
|
||||
|
||||
/**
|
||||
* Updates the memory usage for the node in the template representation
|
||||
*/
|
||||
void update_memory();
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This class includes a list of all NUMA nodes in the host. And structure as
|
||||
* follows:
|
||||
*
|
||||
* <NUMA_NODES>
|
||||
* <NODE>
|
||||
* <ID>0</ID>
|
||||
* <HUGEPAGE>
|
||||
* <SIZE>2048</SIZE>
|
||||
* <PAGES>0</PAGES>
|
||||
* <FREE>0</FREE>
|
||||
* </HUGEPAGE>
|
||||
* ...
|
||||
* <CORE>
|
||||
* <ID>3</ID>
|
||||
* <CPUS>3,7</CPUS>
|
||||
* </CORE>
|
||||
* ...
|
||||
* </NODE>
|
||||
* <NODE>
|
||||
* <ID>1</ID>
|
||||
* ...
|
||||
* </NODE>
|
||||
* </NUMA_NODES>
|
||||
*/
|
||||
class HostShareNUMA
|
||||
{
|
||||
public:
|
||||
HostShareNUMA():threads_core(1){};
|
||||
|
||||
virtual ~HostShareNUMA()
|
||||
{
|
||||
for (auto it = nodes.begin(); it != nodes.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the NUMA nodes from its XML representation. This function is used
|
||||
* when loading the host from the DB.
|
||||
* @param node xmlNode for the template
|
||||
* @return 0 on success
|
||||
*/
|
||||
int from_xml_node(const vector<xmlNodePtr> &ns);
|
||||
|
||||
/**
|
||||
* Updates the NUMA node information with monitor data
|
||||
* @param ht template with the information returned by monitor probes.
|
||||
*/
|
||||
void set_monitorization(Template &ht);
|
||||
|
||||
/**
|
||||
* @param idx of the node
|
||||
* @return the NUMA node for the the fiven index. If the node does not
|
||||
* exit it is created
|
||||
*/
|
||||
HostShareNode& get_node(unsigned int idx);
|
||||
|
||||
/**
|
||||
* Function to print the HostShare object into a string in
|
||||
* XML format
|
||||
* @param xml the resulting XML string
|
||||
* @return a reference to the generated string
|
||||
*/
|
||||
string& to_xml(string& xml) const;
|
||||
|
||||
/**
|
||||
* Test if the virtual nodes and topology request fits in the host.
|
||||
* @param sr the share request with the node/topology
|
||||
* @return true if the nodes fit in the host, false otherwise
|
||||
*/
|
||||
bool test(HostShareCapacity &sr)
|
||||
{
|
||||
return make_topology(sr, -1, false) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the requested nodes to the host.
|
||||
* @param sr the share request with the node/topology
|
||||
* @param vmid of the VM
|
||||
*/
|
||||
void add(HostShareCapacity &sr)
|
||||
{
|
||||
make_topology(sr, sr.vmid, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the VM assignment from the NUMA nodes
|
||||
*/
|
||||
void del(HostShareCapacity &sr);
|
||||
|
||||
/**
|
||||
* Prints the NUMA nodes to an output stream.
|
||||
*/
|
||||
friend ostream& operator<<(ostream& o, const HostShareNUMA& n);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Number of threads per core of the host
|
||||
*/
|
||||
unsigned int threads_core;
|
||||
|
||||
std::map<unsigned int, HostShareNode *> nodes;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/**
|
||||
* Computes the virtual topology for this VM in this host based on:
|
||||
* - user preferences TOPOLOGY/[SOCKETS, CORES, THREADS].
|
||||
* - Architecture of the Host core_threads
|
||||
* - allocation policy
|
||||
*
|
||||
* @param sr the resource allocation request
|
||||
* @param vm_id of the VM making the request
|
||||
* @param do_alloc actually allocate the nodes (true) or just test (false)
|
||||
* @return 0 success (vm was allocated) -1 otherwise
|
||||
*/
|
||||
int make_topology(HostShareCapacity &sr, int vm_id, bool do_alloc);
|
||||
|
||||
/**
|
||||
* This is an internal structure to represent a virtual node allocation
|
||||
* request and the resulting schedule
|
||||
*/
|
||||
struct NUMANodeRequest
|
||||
{
|
||||
VectorAttribute * attr;
|
||||
|
||||
unsigned int total_cpus;
|
||||
long long memory;
|
||||
|
||||
//NUMA node to allocate CPU cores from
|
||||
int node_id;
|
||||
std::string cpu_ids;
|
||||
|
||||
//NUMA node to allocate memory from
|
||||
int mem_node_id;
|
||||
};
|
||||
|
||||
bool schedule_nodes(NUMANodeRequest &nr, unsigned int thr, bool dedicated,
|
||||
unsigned long hpsz_kb, std::set<unsigned int> &pci, bool do_alloc);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The HostShare class. It represents a logical partition of a host...
|
||||
@ -170,13 +598,23 @@ class HostShare : public ObjectXML
|
||||
{
|
||||
public:
|
||||
|
||||
HostShare(
|
||||
long long _max_disk=0,
|
||||
long long _max_mem=0,
|
||||
long long _max_cpu=0);
|
||||
HostShare();
|
||||
|
||||
~HostShare(){};
|
||||
|
||||
/**
|
||||
* Pin policy for the host
|
||||
*/
|
||||
enum PinPolicy
|
||||
{
|
||||
PP_NONE = 0, /**< No pin. Default. */
|
||||
PP_CORE = 1, /**< vCPUs are assigned to host cores exclusively */
|
||||
PP_THREAD = 2, /**< vCPUS are assigned to host threads */
|
||||
PP_SHARED = 3 /**< vCPUs are assigned to a set of host threads */
|
||||
};
|
||||
|
||||
static PinPolicy str_to_pin_policy(std::string& pp_s);
|
||||
|
||||
/**
|
||||
* Rebuilds the object from an xml node
|
||||
* @param node The xml node pointer
|
||||
@ -186,53 +624,35 @@ public:
|
||||
int from_xml_node(const xmlNodePtr node);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Add a VM capacity to this share
|
||||
* @param sr requested capacity by the VM
|
||||
*/
|
||||
void add(int vmid, long long cpu, long long mem, long long disk,
|
||||
vector<VectorAttribute *> pci_devs)
|
||||
void add(HostShareCapacity &sr)
|
||||
{
|
||||
cpu_usage += cpu;
|
||||
mem_usage += mem;
|
||||
disk_usage += disk;
|
||||
cpu_usage += sr.cpu;
|
||||
mem_usage += sr.mem;
|
||||
disk_usage += sr.disk;
|
||||
|
||||
pci.add(pci_devs, vmid);
|
||||
pci.add(sr.pci, sr.vmid);
|
||||
|
||||
numa.add(sr);
|
||||
|
||||
running_vms++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the capacity of VM in this share
|
||||
* @param cpu increment
|
||||
* @param mem increment
|
||||
* @param disk increment
|
||||
* Delete VM capacity from this share
|
||||
* @param sr requested capacity by the VM
|
||||
*/
|
||||
void update(int cpu, int mem, int disk)
|
||||
void del(HostShareCapacity &sr)
|
||||
{
|
||||
cpu_usage += cpu;
|
||||
mem_usage += mem;
|
||||
disk_usage += disk;
|
||||
}
|
||||
cpu_usage -= sr.cpu;
|
||||
mem_usage -= sr.mem;
|
||||
disk_usage -= sr.disk;
|
||||
|
||||
/**
|
||||
* Delete a VM from this share
|
||||
* @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,
|
||||
const vector<VectorAttribute *>& pci_devs)
|
||||
{
|
||||
cpu_usage -= cpu;
|
||||
mem_usage -= mem;
|
||||
disk_usage -= disk;
|
||||
pci.del(sr.pci);
|
||||
|
||||
pci.del(pci_devs);
|
||||
numa.del(sr);
|
||||
|
||||
running_vms--;
|
||||
}
|
||||
@ -248,49 +668,24 @@ public:
|
||||
* @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,
|
||||
vector<VectorAttribute *>& pci_devs, string& error) const
|
||||
bool test(HostShareCapacity& sr, string& error)
|
||||
{
|
||||
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 ( !test_compute(sr.cpu, sr.mem, error) )
|
||||
{
|
||||
if ( pci_fits )
|
||||
{
|
||||
error = "Not enough capacity.";
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Unavailable PCI device.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return fits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this share can host a VM, testing only the PCI devices.
|
||||
* @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(vector<VectorAttribute *>& pci_devs, string& error) const
|
||||
{
|
||||
bool fits = pci.test(pci_devs);
|
||||
|
||||
if (!fits)
|
||||
if ( !test_pci(sr.pci, error) )
|
||||
{
|
||||
error = "Unavailable PCI device.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return fits;
|
||||
if ( !test_numa(sr, error) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,6 +701,10 @@ public:
|
||||
*/
|
||||
string& to_xml(string& xml) const;
|
||||
|
||||
/**
|
||||
* Set host information based on the monitorinzation attributes
|
||||
* sent by the probes.
|
||||
*/
|
||||
void set_ds_monitorization(const vector<VectorAttribute*> &ds_att);
|
||||
|
||||
void set_pci_monitorization(vector<VectorAttribute*> &pci_att)
|
||||
@ -313,6 +712,11 @@ public:
|
||||
pci.set_monitorization(pci_att);
|
||||
}
|
||||
|
||||
void set_numa_monitorization(Template &ht)
|
||||
{
|
||||
numa.set_monitorization(ht);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets capaity values of the share
|
||||
*/
|
||||
@ -385,6 +789,61 @@ private:
|
||||
|
||||
HostShareDatastore ds;
|
||||
HostSharePCI pci;
|
||||
HostShareNUMA numa;
|
||||
|
||||
/**
|
||||
* Check if this share can host a VM, testing only the PCI devices.
|
||||
* @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_compute(int cpu, long long mem, std::string &error) const
|
||||
{
|
||||
bool cpu_fit = (max_cpu - cpu_usage ) >= cpu;
|
||||
bool mem_fit = (max_mem - mem_usage ) >= mem;
|
||||
|
||||
bool fits = cpu_fit && mem_fit;
|
||||
|
||||
if ( fits )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
if (!cpu_fit)
|
||||
{
|
||||
oss << "Not enough CPU: " << cpu << "/" << max_cpu - cpu_usage;
|
||||
}
|
||||
else if (!mem_fit)
|
||||
{
|
||||
oss << "Not enough memory: " << mem << "/" << max_mem - mem_usage;
|
||||
}
|
||||
|
||||
error = oss.str();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test_pci(vector<VectorAttribute *>& pci_devs, string& error) const
|
||||
{
|
||||
bool fits = pci.test(pci_devs);
|
||||
|
||||
error = "Unavailable PCI device.";
|
||||
|
||||
return fits;
|
||||
}
|
||||
|
||||
bool test_numa(HostShareCapacity &sr, string& error)
|
||||
{
|
||||
bool fits = numa.test(sr);
|
||||
|
||||
error = "Cannot allocate NUMA topology";
|
||||
|
||||
return fits;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*HOST_SHARE_H_*/
|
||||
|
@ -99,9 +99,35 @@ namespace one_util
|
||||
*
|
||||
* @return a vector containing the resulting substrings
|
||||
*/
|
||||
std::vector<std::string> split(
|
||||
const std::string& st,
|
||||
char delim,
|
||||
template <class T>
|
||||
void split(const std::string &st, char delim, std::vector<T> &parts)
|
||||
{
|
||||
std::string part;
|
||||
|
||||
std::stringstream ss(st);
|
||||
|
||||
while (getline(ss, part, delim))
|
||||
{
|
||||
if (part.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::istringstream iss(part);
|
||||
T part_t;
|
||||
|
||||
iss >> part_t;
|
||||
|
||||
if ( iss.fail() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
parts.push_back(part_t);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& st, char delim,
|
||||
bool clean_empty=true);
|
||||
|
||||
/**
|
||||
|
@ -240,15 +240,15 @@ public:
|
||||
oss << value;
|
||||
|
||||
set(new SingleAttribute(name, oss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
void add(const string& name, const string& value)
|
||||
{
|
||||
set(new SingleAttribute(name, value));
|
||||
}
|
||||
void add(const string& name, const string& value)
|
||||
{
|
||||
set(new SingleAttribute(name, value));
|
||||
}
|
||||
|
||||
void add(const string& name, bool value)
|
||||
{
|
||||
void add(const string& name, bool value)
|
||||
{
|
||||
if ( value )
|
||||
{
|
||||
set(new SingleAttribute(name, "YES"));
|
||||
@ -257,7 +257,7 @@ public:
|
||||
{
|
||||
set(new SingleAttribute(name, "NO"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an attribute from the template. The attributes are returned. The
|
||||
|
@ -37,6 +37,7 @@ using namespace std;
|
||||
|
||||
class AuthRequest;
|
||||
class Snapshots;
|
||||
class HostShareCapacity;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -1011,14 +1012,10 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the VM physical requirements for the host.
|
||||
* @param cpu
|
||||
* @param memory
|
||||
* @param disk
|
||||
* @param pci_dev
|
||||
* Get the VM physical capacity requirements for the host.
|
||||
* @param sr the HostShareCapacity to store the capacity request.
|
||||
*/
|
||||
void get_requirements(int& cpu, int& memory, int& disk,
|
||||
vector<VectorAttribute *>& pci_dev);
|
||||
void get_capacity(HostShareCapacity &sr);
|
||||
|
||||
/**
|
||||
* Adds automatic placement requirements: Datastore and Cluster
|
||||
@ -1033,27 +1030,27 @@ public:
|
||||
return automatic_requirements(cluster_ids, datastore_ids, error_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the resize parameters are valid
|
||||
* @param cpu New CPU. 0 means unchanged.
|
||||
* @param memory New MEMORY. 0 means unchanged.
|
||||
* @param vcpu New VCPU. 0 means unchanged.
|
||||
* @param error_str Error reason, if any
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int check_resize(float cpu, long int memory, int vcpu, string& error_str);
|
||||
|
||||
/**
|
||||
* Resize the VM capacity
|
||||
* @param cpu
|
||||
* @param memory
|
||||
* @param vcpu
|
||||
* @param error_str Error reason, if any
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int resize(float cpu, long int memory, int vcpu, string& error_str);
|
||||
int resize(float cpu, long int memory, unsigned int vcpu, string& error);
|
||||
|
||||
/**
|
||||
* Parse TOPOLOGY and NUMA_NODE
|
||||
* @param tmpl template of the virtual machine
|
||||
* @param error if any
|
||||
*
|
||||
* @return 0 on sucess
|
||||
*/
|
||||
static int parse_topology(Template * tmpl, std::string &error);
|
||||
|
||||
/**
|
||||
* @return true if the VM is being deployed with a pinned policy
|
||||
*/
|
||||
bool is_pinned();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Virtual Machine Disks
|
||||
|
@ -1026,6 +1026,7 @@ IM_PROBES_KVM_PROBES_FILES="src/im_mad/remotes/kvm-probes.d/kvm.rb \
|
||||
src/im_mad/remotes/kvm-probes.d/machines-models.rb \
|
||||
src/im_mad/remotes/kvm-probes.d/name.sh \
|
||||
src/im_mad/remotes/kvm-probes.d/pci.rb \
|
||||
src/im_mad/remotes/kvm-probes.d/numa.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"
|
||||
@ -1038,6 +1039,7 @@ IM_PROBES_LXD_PROBES_FILES="src/im_mad/remotes/lxd-probes.d/lxd.rb \
|
||||
src/im_mad/remotes/lxd-probes.d/poll.sh \
|
||||
src/im_mad/remotes/lxd-probes.d/name.sh \
|
||||
src/im_mad/remotes/lxd-probes.d/pci.rb \
|
||||
src/im_mad/remotes/lxd-probes.d/numa.rb \
|
||||
src/im_mad/remotes/lxd-probes.d/monitor_ds.sh \
|
||||
src/im_mad/remotes/lxd-probes.d/version.sh \
|
||||
src/im_mad/remotes/lxd-probes.d/profiles.sh \
|
||||
|
@ -636,6 +636,16 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
|
||||
print_pcis(pcis)
|
||||
end
|
||||
|
||||
begin
|
||||
numa_nodes = host.to_hash['HOST']['HOST_SHARE']['NUMA_NODES']['NODE']
|
||||
rescue StandardError
|
||||
numa_nodes = nil
|
||||
end
|
||||
|
||||
if numa_nodes && !numa_nodes.empty?
|
||||
print_numa_nodes(numa_nodes, str, str_h1)
|
||||
end
|
||||
|
||||
puts
|
||||
CLIHelper.print_header('WILD VIRTUAL MACHINES', false)
|
||||
puts
|
||||
@ -718,4 +728,180 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
|
||||
table.show(pcis)
|
||||
end
|
||||
|
||||
def print_numa_nodes(numa_nodes, str, str_h1)
|
||||
numa_nodes = get_numa_data(numa_nodes)
|
||||
|
||||
print_numa_cores(numa_nodes)
|
||||
print_numa_memory(numa_nodes)
|
||||
print_numa_hugepages(numa_nodes)
|
||||
end
|
||||
|
||||
def get_numa_data(numa_nodes)
|
||||
numa_nodes = [numa_nodes] if numa_nodes.class == Hash
|
||||
|
||||
numa_nodes.map! do |core|
|
||||
cores = core['CORE']
|
||||
|
||||
free, used, cores_str = get_numa_cores(cores)
|
||||
|
||||
core['CORE'] = {}
|
||||
core['CORE']['CORES'] = cores_str
|
||||
core['CORE']['FREE'] = free
|
||||
core['CORE']['USED'] = used
|
||||
|
||||
core
|
||||
end
|
||||
|
||||
numa_nodes
|
||||
end
|
||||
|
||||
def get_numa_cores(cores)
|
||||
ret = ''
|
||||
free = 0
|
||||
used = 0
|
||||
|
||||
cores.each do |info|
|
||||
core = info['CPUS'].split(',')
|
||||
|
||||
core.each do |c|
|
||||
c = c.split(':')
|
||||
|
||||
if c[1] == '-1'
|
||||
ret += '-'
|
||||
free += 1
|
||||
elsif c[1] != '-1' && info['FREE'] == '0'
|
||||
ret += 'X'
|
||||
used += 1
|
||||
else
|
||||
ret += 'x'
|
||||
used += 1
|
||||
end
|
||||
end
|
||||
|
||||
ret += ' '
|
||||
end
|
||||
|
||||
[free, used, ret]
|
||||
end
|
||||
|
||||
def print_numa_cores(numa_nodes)
|
||||
puts
|
||||
CLIHelper.print_header('NUMA NODES', false)
|
||||
puts
|
||||
|
||||
table = CLIHelper::ShowTable.new(nil, self) do
|
||||
column :ID, 'Node ID', :size => 4, :left => false do |d|
|
||||
d['NODE_ID']
|
||||
end
|
||||
|
||||
column :CORES, 'Cores usage', :size => 50, :left => true do |d|
|
||||
d['CORE']['CORES']
|
||||
end
|
||||
|
||||
column :USED, 'Used CPUs', :size => 4, :left => true do |d|
|
||||
d['CORE']['USED']
|
||||
end
|
||||
|
||||
column :FREE, 'Free CPUs', :size => 4, :left => true do |d|
|
||||
d['CORE']['FREE']
|
||||
end
|
||||
|
||||
default :ID, :CORES, :USED, :FREE
|
||||
end
|
||||
|
||||
table.show(numa_nodes)
|
||||
end
|
||||
|
||||
def print_numa_memory(numa_nodes)
|
||||
nodes = numa_nodes.clone
|
||||
|
||||
nodes.reject! do |node|
|
||||
node['MEMORY'].nil? || node['MEMORY'].empty?
|
||||
end
|
||||
|
||||
return if nodes.empty?
|
||||
|
||||
puts
|
||||
CLIHelper.print_header('NUMA MEMORY', false)
|
||||
puts
|
||||
|
||||
table = CLIHelper::ShowTable.new(nil, self) do
|
||||
column :NODE_ID, 'Node ID', :size => 8, :left => false do |d|
|
||||
d['NODE_ID']
|
||||
end
|
||||
|
||||
column :TOTAL, 'Total memory', :size => 8, :left => true do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['MEMORY']['TOTAL'].to_i, {})
|
||||
end
|
||||
|
||||
column :USED_REAL, 'Used memory', :size => 20, :left => true do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['MEMORY']['USED'].to_i, {})
|
||||
end
|
||||
|
||||
column :USED_ALLOCATED, 'U memory', :size => 20, :left => true do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['MEMORY']['USAGE'].to_i, {})
|
||||
end
|
||||
|
||||
column :FREE, 'Free memory', :size => 8, :left => true do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['MEMORY']['FREE'].to_i, {})
|
||||
end
|
||||
|
||||
default :NODE_ID, :TOTAL, :USED_REAL, :USED_ALLOCATED, :FREE
|
||||
end
|
||||
|
||||
table.show(nodes)
|
||||
end
|
||||
|
||||
def print_numa_hugepages(numa_nodes)
|
||||
nodes = numa_nodes.clone
|
||||
|
||||
nodes.reject! do |node|
|
||||
node['HUGEPAGE'].nil? || node['HUGEPAGE'].empty?
|
||||
end
|
||||
|
||||
return if nodes.empty?
|
||||
|
||||
puts
|
||||
CLIHelper.print_header('NUMA HUGEPAGES', false)
|
||||
puts
|
||||
|
||||
table = CLIHelper::ShowTable.new(nil, self) do
|
||||
column :NODE_ID, 'Node ID', :size => 8, :left => false do |d|
|
||||
d['NODE_ID']
|
||||
end
|
||||
|
||||
column :TOTAL, 'Total pages', :size => 8, :left => true do |d|
|
||||
d['HUGEPAGE']['PAGES']
|
||||
end
|
||||
|
||||
column :SIZE, 'Pages size', :size => 8, :left => true do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['HUGEPAGE']['SIZE'].to_i/1024, {}, "M")
|
||||
end
|
||||
|
||||
column :FREE, 'Free pages', :size => 8, :left => true do |d|
|
||||
d['HUGEPAGE']['FREE']
|
||||
end
|
||||
|
||||
column :USED, 'allocated pages', :size => 8, :left => true do |d|
|
||||
d['HUGEPAGE']['USAGE']
|
||||
end
|
||||
|
||||
default :NODE_ID, :SIZE, :TOTAL, :FREE, :USED
|
||||
end
|
||||
|
||||
hugepages = []
|
||||
|
||||
nodes.each do |node|
|
||||
node['HUGEPAGE'].each do |hugepage|
|
||||
h = {}
|
||||
h['NODE_ID'] = node['NODE_ID']
|
||||
h['HUGEPAGE'] = hugepage
|
||||
|
||||
hugepages << h
|
||||
end
|
||||
end
|
||||
|
||||
table.show(hugepages)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,3 +1,4 @@
|
||||
require 'pry'
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2019, OpenNebula Project, OpenNebula Systems #
|
||||
# #
|
||||
@ -1170,11 +1171,79 @@ in the frontend machine.
|
||||
puts vm.template_like_str('USER_TEMPLATE')
|
||||
end
|
||||
|
||||
if vm.has_elements?('/VM/TEMPLATE/NUMA_NODE')
|
||||
print_numa_nodes(vm.to_hash['VM']['TEMPLATE']['NUMA_NODE'])
|
||||
end
|
||||
|
||||
if vm.has_elements?('/VM/TEMPLATE/TOPOLOGY')
|
||||
print_topology([vm.to_hash['VM']['TEMPLATE']['TOPOLOGY']])
|
||||
end
|
||||
|
||||
while vm.has_elements?('/VM/TEMPLATE/NUMA_NODE')
|
||||
vm.delete_element('/VM/TEMPLATE/NUMA_NODE')
|
||||
end if !options[:all]
|
||||
|
||||
while vm.has_elements?('/VM/TEMPLATE/TOPOLOGY')
|
||||
vm.delete_element('/VM/TEMPLATE/TOPOLOGY')
|
||||
end if !options[:all]
|
||||
|
||||
puts
|
||||
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE TEMPLATE",false)
|
||||
puts vm.template_str
|
||||
end
|
||||
|
||||
def print_numa_nodes(numa_nodes)
|
||||
puts
|
||||
CLIHelper.print_header('NUMA NODES', false)
|
||||
puts
|
||||
|
||||
table = CLIHelper::ShowTable.new(nil, self) do
|
||||
column :ID, 'Node ID', :size => 4, :left => false do |d|
|
||||
d['NODE_ID']
|
||||
end
|
||||
|
||||
column :CPUS, 'Cpus used', :size => 6, :left => false do |d|
|
||||
d['CPUS']
|
||||
end
|
||||
|
||||
column :MEMORY, 'Memory used', :size => 10, :left => false do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['MEMORY'].to_i, {})
|
||||
end
|
||||
|
||||
column :TOTAL_CPUS, 'Total CPUs', :size => 10, :left => false do |d|
|
||||
d['TOTAL_CPUS']
|
||||
end
|
||||
|
||||
default :ID, :CPUS, :MEMORY, :TOTAL_CPUS
|
||||
end
|
||||
|
||||
table.show(numa_nodes)
|
||||
end
|
||||
|
||||
def print_topology(topology)
|
||||
puts
|
||||
CLIHelper.print_header('TOPOLOGY', false)
|
||||
puts
|
||||
|
||||
table = CLIHelper::ShowTable.new(nil, self) do
|
||||
column :CORES, 'Cores', :size => 6, :left => false do |d|
|
||||
d['CORES']
|
||||
end
|
||||
|
||||
column :SOCKETS, 'Sockets', :size => 8, :left => false do |d|
|
||||
d['SOCKETS']
|
||||
end
|
||||
|
||||
column :THREADS, 'Threads', :size => 8, :left => false do |d|
|
||||
d['THREADS']
|
||||
end
|
||||
|
||||
default :CORES, :SOCKETS, :THREADS
|
||||
end
|
||||
|
||||
table.show(topology)
|
||||
end
|
||||
|
||||
def format_history(vm)
|
||||
table=CLIHelper::ShowTable.new(nil, self) do
|
||||
column :SEQ, "Sequence number", :size=>3 do |d|
|
||||
|
@ -124,12 +124,11 @@ int DispatchManager::import(VirtualMachine * vm, const RequestAttributes& ra)
|
||||
}
|
||||
|
||||
time_t the_time = time(0);
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
import_state = vm->get_import_state();
|
||||
|
||||
@ -1078,8 +1077,7 @@ int DispatchManager::delete_vm(VirtualMachine * vm, const RequestAttributes& ra,
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
bool is_public_host = false;
|
||||
int host_id = -1;
|
||||
@ -1117,9 +1115,9 @@ int DispatchManager::delete_vm(VirtualMachine * vm, const RequestAttributes& ra,
|
||||
{
|
||||
case VirtualMachine::SUSPENDED:
|
||||
case VirtualMachine::POWEROFF:
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vid, cpu, mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
if (is_public_host)
|
||||
{
|
||||
@ -1277,14 +1275,11 @@ int DispatchManager::delete_recreate(VirtualMachine * vm,
|
||||
int DispatchManager::delete_vm_db(VirtualMachine * vm,
|
||||
const RequestAttributes& ra, string& error_str)
|
||||
{
|
||||
HostShareCapacity sr;
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
|
||||
int vid = vm->get_oid();
|
||||
|
||||
oss << "Deleting VM from DB " << vm->get_oid();
|
||||
|
||||
NebulaLog::log("DiM",Log::DEBUG,oss);
|
||||
|
||||
switch (vm->get_state())
|
||||
@ -1292,9 +1287,9 @@ int DispatchManager::delete_vm_db(VirtualMachine * vm,
|
||||
case VirtualMachine::SUSPENDED:
|
||||
case VirtualMachine::POWEROFF:
|
||||
case VirtualMachine::ACTIVE:
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vid, cpu, mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
case VirtualMachine::STOPPED:
|
||||
case VirtualMachine::UNDEPLOYED:
|
||||
|
@ -460,6 +460,8 @@ int Host::update_info(Template &tmpl,
|
||||
|
||||
host_share.set_pci_monitorization(pci_att);
|
||||
|
||||
host_share.set_numa_monitorization(*obj_template);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -82,7 +82,8 @@ class DummyInformationManager < OpenNebulaDriver
|
||||
SLOT = \"00\",\n
|
||||
TYPE = \"10de:0863:0300\",\n
|
||||
VENDOR = \"10de\",\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\"\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\",\n
|
||||
NUMA_NODE=\"1\"
|
||||
]\n
|
||||
PCI = [
|
||||
ADDRESS = \"0000:00:06:0\",\n
|
||||
@ -97,7 +98,8 @@ class DummyInformationManager < OpenNebulaDriver
|
||||
SLOT = \"06\",\n
|
||||
TYPE = \"10de:0aa7:0c03\",\n
|
||||
VENDOR = \"10de\",\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\"\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\",\n
|
||||
NUMA_NODE=\"1\"
|
||||
]\n
|
||||
PCI = [
|
||||
ADDRESS = \"0000:00:06:1\",\n
|
||||
@ -112,9 +114,12 @@ class DummyInformationManager < OpenNebulaDriver
|
||||
SLOT = \"06\",\n
|
||||
TYPE = \"10de:0aa9:0c03\",\n
|
||||
VENDOR = \"10de\",\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\"\n
|
||||
VENDOR_NAME = \"NVIDIA Corporation\"\n,
|
||||
NUMA_NODE=\"0\"
|
||||
]\n"
|
||||
|
||||
make_topology(results, 2, 8, [2048, 1048576], 4, 16777216)
|
||||
|
||||
results = Base64::encode64(results).strip.delete("\n")
|
||||
|
||||
send_message("MONITOR", RESULT[:success], number, results)
|
||||
@ -123,6 +128,45 @@ class DummyInformationManager < OpenNebulaDriver
|
||||
def stop_monitor(number, host)
|
||||
send_message("STOPMONITOR", RESULT[:success], number, nil)
|
||||
end
|
||||
|
||||
def make_topology(result, nodes, cores, pages, threads, mem)
|
||||
nodes.times do |i|
|
||||
cores.times do |j|
|
||||
core_id = j + ( i * cores)
|
||||
|
||||
core_str = "CORE = [ NODE_ID=\"#{i}\", ID=\"#{core_id}\", "\
|
||||
"CPUS=\""
|
||||
|
||||
threads.times do |k|
|
||||
cpu_id = core_id + k * ( cores * nodes )
|
||||
|
||||
core_str << "," if k != 0
|
||||
core_str << "#{cpu_id}"
|
||||
end
|
||||
|
||||
core_str << "\"]\n"
|
||||
|
||||
result << core_str
|
||||
end
|
||||
|
||||
pages.each do |p|
|
||||
result << "HUGEPAGE = [ SIZE = \"#{p}\", FREE = \"1024\", "\
|
||||
"PAGES = \"1024\", NODE_ID = \"#{i}\" ] "
|
||||
end
|
||||
|
||||
memn = mem.to_i/nodes
|
||||
|
||||
result << "MEMORY_NODE = [ NODE_ID = \"#{i}\", TOTAL = \"#{memn}\"" \
|
||||
", FREE = \"#{rand(memn)}\", USED = \"#{rand(memn)}\", " \
|
||||
"DISTANCE = \"#{i} "
|
||||
|
||||
nodes.times do |l|
|
||||
result << "#{l} " if l != i
|
||||
end
|
||||
|
||||
result << "\" ]\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
1
src/im_mad/remotes/kvm-probes.d/numa.rb
Symbolic link
1
src/im_mad/remotes/kvm-probes.d/numa.rb
Symbolic link
@ -0,0 +1 @@
|
||||
../node-probes.d/numa.rb
|
1
src/im_mad/remotes/lxd-probes.d/numa.rb
Symbolic link
1
src/im_mad/remotes/lxd-probes.d/numa.rb
Symbolic link
@ -0,0 +1 @@
|
||||
../node-probes.d/numa.rb
|
225
src/im_mad/remotes/node-probes.d/numa.rb
Executable file
225
src/im_mad/remotes/node-probes.d/numa.rb
Executable file
@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2019, OpenNebula Project, OpenNebula Systems #
|
||||
# #
|
||||
# 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 probe uses the sysfs interface to get information about the NUMA topology
|
||||
# of the host. References:
|
||||
# - https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-devices-node
|
||||
# - https://www.kernel.org/doc/Documentation/cputopology.txt
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
NODE_PATH = '/sys/bus/node/devices/'
|
||||
|
||||
# Print node information in OpenNebula Template format. Example:
|
||||
#
|
||||
# HUGEPAGE = [NODE_ID = "0", SIZE = "1048576", PAGES = "0", FREE = "0"]
|
||||
# HUGEPAGE = [NODE_ID = "0", SIZE = "2048", PAGES = "0", FREE = "0"]
|
||||
# CORE = [ NODE_ID = "0", ID = "0", CPUS = "0,2"]
|
||||
# CORE = [ NODE_ID = "0", ID = "1", CPUS = "1,3"]
|
||||
#
|
||||
# Corresponding Hash is:
|
||||
# {"hugepages"=>
|
||||
# [{"size"=>"2048", "free"=>"0", "nr"=>"0", "surplus"=>"0"},
|
||||
# {"size"=>"1048576", "free"=>"0", "nr"=>"0", "surplus"=>"0"}],
|
||||
# "cores"=>
|
||||
# [{"id"=>"3", "cpus"=>["3", "7"]},
|
||||
# {"id"=>"1", "cpus"=>["1", "5"]},
|
||||
# {"id"=>"2", "cpus"=>["2", "6"]},
|
||||
# {"id"=>"0", "cpus"=>["0", "4"]}],
|
||||
# "memory"=>
|
||||
# {"total"=>"7992880", "free"=>"2041004", "used"=>"5951876", "distance"=>"0"}}
|
||||
def node_to_template(node, nid)
|
||||
node_s = ''
|
||||
|
||||
node.each do |k, v|
|
||||
case k
|
||||
when 'hugepages'
|
||||
v.each do |h|
|
||||
node_s << "HUGEPAGE = [ NODE_ID = \"#{nid}\","
|
||||
node_s << " SIZE = \"#{h['size']}\","
|
||||
node_s << " PAGES = \"#{h['nr']}\","
|
||||
node_s << " FREE = \"#{h['free']}\" ]\n"
|
||||
end
|
||||
when 'cores'
|
||||
v.each do |c|
|
||||
node_s << "CORE = [ NODE_ID = \"#{nid}\","
|
||||
node_s << " ID = \"#{c['id']}\","
|
||||
node_s << " CPUS = \"#{c['cpus'].join(',')}\" ]\n"
|
||||
end
|
||||
when 'memory'
|
||||
node_s << "MEMORY_NODE = [ NODE_ID = \"#{nid}\","
|
||||
node_s << " TOTAL = \"#{v['total']}\","
|
||||
node_s << " FREE = \"#{v['free']}\","
|
||||
node_s << " USED = \"#{v['used']}\","
|
||||
node_s << " DISTANCE = \"#{v['distance']}\" ]\n"
|
||||
end
|
||||
end
|
||||
|
||||
node_s
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# hugepages information
|
||||
# ------------------------------------------------------------------------------
|
||||
# This function parses the HUGE_PAGES information for the node
|
||||
# @param [Hash] nodes the attributes of the NUMA nodes
|
||||
# @param [String] node name of the node
|
||||
# @param [String] node_id of the node
|
||||
#
|
||||
def huge_pages(nodes, node_id)
|
||||
nodes[node_id]['hugepages'] = []
|
||||
|
||||
hp_path = "#{NODE_PATH}/node#{node_id}/hugepages"
|
||||
|
||||
return unless Dir.exist?(hp_path)
|
||||
|
||||
Dir.foreach(hp_path) do |hp|
|
||||
/hugepages-(?<hp_size>\d+)kB/ =~ hp
|
||||
next unless hp_size
|
||||
|
||||
hpsz_path = "#{hp_path}/#{hp}"
|
||||
|
||||
hp_info = { 'size' => hp_size }
|
||||
|
||||
begin
|
||||
%w[free nr surplus].each do |var|
|
||||
var_path = "#{hpsz_path}/#{var}_hugepages"
|
||||
hp_info[var] = File.read(var_path).chomp
|
||||
end
|
||||
rescue StandardError
|
||||
next
|
||||
end
|
||||
|
||||
nodes[node_id]['hugepages'] << hp_info
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# CPU topology
|
||||
# ------------------------------------------------------------------------------
|
||||
# This function parses the CPU topology information for the node
|
||||
# @param [Hash] nodes the attributes of the NUMA nodes
|
||||
# @param [String] node name of the node
|
||||
# @param [String] node_id of the node
|
||||
#
|
||||
def cpu_topology(nodes, node_id)
|
||||
nodes[node_id]['cores'] = []
|
||||
cpu_visited = []
|
||||
|
||||
cpu_path = "#{NODE_PATH}/node#{node_id}/"
|
||||
|
||||
return unless Dir.exist?(cpu_path)
|
||||
|
||||
Dir.foreach(cpu_path) do |cp|
|
||||
/cpu(?<cpu_id>\d+)/ =~ cp
|
||||
next unless cpu_id
|
||||
next if cpu_visited.include? cpu_id
|
||||
|
||||
begin
|
||||
core_path = "#{cpu_path}/#{cp}/topology"
|
||||
|
||||
siblings = File.read("#{core_path}/thread_siblings_list").chomp
|
||||
siblings = siblings.split(',')
|
||||
|
||||
cpu_visited.concat(siblings)
|
||||
|
||||
core_id = File.read("#{core_path}/core_id").chomp
|
||||
|
||||
nodes[node_id]['cores'] << { 'id' => core_id, 'cpus' => siblings }
|
||||
rescue StandardError
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Memory
|
||||
# ------------------------------------------------------------------------------
|
||||
# This function parses the CPU topology information for the node
|
||||
# @param [Hash] nodes the attributes of the NUMA nodes
|
||||
# @param [String] node name of the node
|
||||
# @param [String] node_id of the node
|
||||
#
|
||||
def memory(nodes, node_id)
|
||||
meminfo_path = "#{NODE_PATH}/node#{node_id}/meminfo"
|
||||
|
||||
return unless File.exist?(meminfo_path)
|
||||
|
||||
bind = binding
|
||||
|
||||
mem_vars = %w[MemTotal MemFree MemUsed]
|
||||
|
||||
mem_vars.each {|var| bind.eval("#{var.downcase.to_sym} = 0") }
|
||||
|
||||
File.readlines(meminfo_path).each do |line|
|
||||
mem_vars.each do |metric|
|
||||
md = /Node #{node_id} #{metric}:\s+(?<value>\d+) k/.match(line)
|
||||
|
||||
bind.eval("#{metric.downcase.to_sym} = #{md[:value]}") if md
|
||||
break if md
|
||||
end
|
||||
end
|
||||
|
||||
nodes[node_id]['memory'] = {
|
||||
'total' => bind.eval("#{:memtotal}"),
|
||||
'free' => bind.eval("#{:memfree}"),
|
||||
'used' => bind.eval("#{:memused}")
|
||||
}
|
||||
|
||||
# Node distance to priotitize memory allocation
|
||||
distance_path = "#{NODE_PATH}/node#{node_id}/distance"
|
||||
|
||||
return unless File.exist?(distance_path)
|
||||
|
||||
distance = File.read(distance_path)
|
||||
distance_a = distance.split(' ')
|
||||
|
||||
distance_h = {}
|
||||
distance_a.each_with_index {|d, i| distance_h[d.to_i] = i }
|
||||
|
||||
distance_h = Hash[distance_h.sort_by {|k| k }]
|
||||
|
||||
closer = ''
|
||||
distance_h.each {|_, v| closer << v.to_s << ' ' }
|
||||
|
||||
nodes[node_id]['memory']['distance'] = closer.chop
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get information for each NUMA node.
|
||||
# ------------------------------------------------------------------------------
|
||||
nodes = {}
|
||||
|
||||
Dir.foreach(NODE_PATH) do |node|
|
||||
/node(?<node_id>\d+)/ =~ node
|
||||
next unless node_id
|
||||
|
||||
nodes[node_id] = {}
|
||||
|
||||
huge_pages(nodes, node_id)
|
||||
|
||||
cpu_topology(nodes, node_id)
|
||||
|
||||
memory(nodes, node_id)
|
||||
end
|
||||
|
||||
nodes_s = ''
|
||||
|
||||
nodes.each {|i, v| nodes_s << node_to_template(v, i) }
|
||||
|
||||
puts nodes_s
|
@ -56,6 +56,16 @@ def parse_pci(pci)
|
||||
"pci_0000_#{card[:short_address].gsub(/[:.]/, '_')}"
|
||||
card[:address] = "0000:#{card[:short_address].gsub(/[:.]/, ':')}"
|
||||
|
||||
begin
|
||||
numa_node = File.read("/sys/bus/pci/devices/0000:#{pci[0]}/numa_node").chomp
|
||||
rescue
|
||||
numa_node = '-'
|
||||
end
|
||||
|
||||
numa_node = '-' if numa_node.to_i < 0
|
||||
|
||||
card[:numa_node] = numa_node
|
||||
|
||||
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])
|
||||
@ -112,7 +122,8 @@ devices.each do |dev|
|
||||
pval('DOMAIN', '0000'),
|
||||
pval('BUS', dev[:bus]),
|
||||
pval('SLOT', dev[:slot]),
|
||||
pval('FUNCTION', dev[:function])
|
||||
pval('FUNCTION', dev[:function]),
|
||||
pval('NUMA_NODE', dev[:numa_node])
|
||||
]
|
||||
|
||||
puts values.join(",\n")
|
||||
|
@ -36,9 +36,10 @@ void LifeCycleManager::deploy_action(const LCMAction& la)
|
||||
|
||||
if ( vm->get_state() == VirtualMachine::ACTIVE )
|
||||
{
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t thetime = time(0);
|
||||
int cpu, mem, disk, rc;
|
||||
vector<VectorAttribute *> pci;
|
||||
int rc;
|
||||
|
||||
VirtualMachine::LcmState vm_state;
|
||||
TMAction::Actions tm_action;
|
||||
@ -47,7 +48,7 @@ void LifeCycleManager::deploy_action(const LCMAction& la)
|
||||
// PROLOG STATE
|
||||
//----------------------------------------------------
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
vm_state = VirtualMachine::PROLOG;
|
||||
tm_action = TMAction::PROLOG;
|
||||
@ -69,7 +70,7 @@ void LifeCycleManager::deploy_action(const LCMAction& la)
|
||||
|
||||
vm->set_state(vm_state);
|
||||
|
||||
rc = hpool->add_capacity(vm->get_hid(),vm->get_oid(),cpu,mem,disk,pci);
|
||||
rc = hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
vm->set_stime(thetime);
|
||||
|
||||
@ -214,8 +215,7 @@ void LifeCycleManager::stop_action(const LCMAction& la)
|
||||
|
||||
void LifeCycleManager::migrate_action(const LCMAction& la)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
|
||||
@ -254,9 +254,9 @@ void LifeCycleManager::migrate_action(const LCMAction& la)
|
||||
|
||||
vm->set_resched(false);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
vm->set_stime(the_time);
|
||||
|
||||
@ -334,14 +334,13 @@ void LifeCycleManager::migrate_action(const LCMAction& la)
|
||||
|
||||
vm->reset_info();
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
if ( vm->get_hid() != vm->get_previous_hid() )
|
||||
{
|
||||
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem,
|
||||
disk, pci);
|
||||
hpool->del_capacity(vm->get_previous_hid(), sr);
|
||||
}
|
||||
|
||||
vm->set_stime(the_time);
|
||||
@ -385,8 +384,7 @@ void LifeCycleManager::live_migrate_action(const LCMAction& la)
|
||||
if (vm->get_state() == VirtualMachine::ACTIVE &&
|
||||
vm->get_lcm_state() == VirtualMachine::RUNNING)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
//----------------------------------------------------
|
||||
// MIGRATE STATE
|
||||
@ -396,9 +394,9 @@ void LifeCycleManager::live_migrate_action(const LCMAction& la)
|
||||
|
||||
vm->set_resched(false);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->add_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
vm->set_stime(time(0));
|
||||
|
||||
@ -967,10 +965,10 @@ void LifeCycleManager::delete_recreate_action(const LCMAction& la)
|
||||
void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose,
|
||||
int& image_id, const LCMAction& la)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
HostShareCapacity sr;
|
||||
|
||||
unsigned int port;
|
||||
|
||||
vector<VectorAttribute *> pci;
|
||||
time_t the_time = time(0);
|
||||
|
||||
VirtualMachine::LcmState state = vm->get_lcm_state();
|
||||
@ -1000,9 +998,9 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose,
|
||||
vm->set_etime(the_time);
|
||||
vm->set_vm_info();
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
const VectorAttribute * graphics = vm->get_template_attribute("GRAPHICS");
|
||||
|
||||
@ -1139,8 +1137,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose,
|
||||
vm->set_previous_vm_info();
|
||||
vm->set_previous_running_etime(the_time);
|
||||
|
||||
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu,
|
||||
mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_previous_hid(), sr);
|
||||
|
||||
vmpool->update_previous_history(vm);
|
||||
|
||||
@ -1163,8 +1160,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose,
|
||||
vm->set_previous_vm_info();
|
||||
vm->set_previous_running_etime(the_time);
|
||||
|
||||
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu,
|
||||
mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_previous_hid(), sr);
|
||||
|
||||
vmpool->update_previous_history(vm);
|
||||
|
||||
|
@ -22,8 +22,7 @@
|
||||
|
||||
void LifeCycleManager::start_prolog_migrate(VirtualMachine* vm)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
|
||||
@ -52,12 +51,13 @@ void LifeCycleManager::start_prolog_migrate(VirtualMachine* vm)
|
||||
|
||||
vmpool->update_history(vm);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vmpool->update(vm);
|
||||
|
||||
vm->get_capacity(sr);
|
||||
|
||||
if ( vm->get_hid() != vm->get_previous_hid() )
|
||||
{
|
||||
hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem,
|
||||
disk, pci);
|
||||
hpool->del_capacity(vm->get_previous_hid(), sr);
|
||||
}
|
||||
|
||||
vmpool->update(vm);
|
||||
@ -69,58 +69,57 @@ void LifeCycleManager::start_prolog_migrate(VirtualMachine* vm)
|
||||
|
||||
void LifeCycleManager::revert_migrate_after_failure(VirtualMachine* vm)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
time_t the_time = time(0);
|
||||
|
||||
//----------------------------------------------------
|
||||
// RUNNING STATE FROM SAVE_MIGRATE
|
||||
//----------------------------------------------------
|
||||
//----------------------------------------------------
|
||||
// RUNNING STATE FROM SAVE_MIGRATE
|
||||
//----------------------------------------------------
|
||||
|
||||
vm->set_state(VirtualMachine::RUNNING);
|
||||
vm->set_state(VirtualMachine::RUNNING);
|
||||
|
||||
vm->set_etime(the_time);
|
||||
vm->set_etime(the_time);
|
||||
|
||||
vm->set_vm_info();
|
||||
vm->set_vm_info();
|
||||
|
||||
vmpool->update_history(vm);
|
||||
vmpool->update_history(vm);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
if ( vm->get_hid() != vm->get_previous_hid() )
|
||||
{
|
||||
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
}
|
||||
if ( vm->get_hid() != vm->get_previous_hid() )
|
||||
{
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
}
|
||||
|
||||
vm->set_previous_etime(the_time);
|
||||
vm->set_previous_etime(the_time);
|
||||
|
||||
vm->set_previous_vm_info();
|
||||
vm->set_previous_vm_info();
|
||||
|
||||
vm->set_previous_running_etime(the_time);
|
||||
vm->set_previous_running_etime(the_time);
|
||||
|
||||
vmpool->update_previous_history(vm);
|
||||
vmpool->update_previous_history(vm);
|
||||
|
||||
// --- Add new record by copying the previous one
|
||||
// --- Add new record by copying the previous one
|
||||
|
||||
vm->cp_previous_history();
|
||||
vm->cp_previous_history();
|
||||
|
||||
vm->set_stime(the_time);
|
||||
vm->set_stime(the_time);
|
||||
|
||||
vm->set_running_stime(the_time);
|
||||
vm->set_running_stime(the_time);
|
||||
|
||||
vm->set_last_poll(0);
|
||||
vm->set_last_poll(0);
|
||||
|
||||
vmpool->insert_history(vm);
|
||||
vmpool->insert_history(vm);
|
||||
|
||||
vmpool->update(vm);
|
||||
vmpool->update(vm);
|
||||
|
||||
vm->log("LCM", Log::INFO, "Fail to save VM state while migrating."
|
||||
" Assuming that the VM is still RUNNING (will poll VM).");
|
||||
vm->log("LCM", Log::INFO, "Fail to save VM state while migrating."
|
||||
" Assuming that the VM is still RUNNING (will poll VM).");
|
||||
|
||||
//----------------------------------------------------
|
||||
//----------------------------------------------------
|
||||
|
||||
vmm->trigger(VMMAction::POLL,vm->get_oid());
|
||||
vmm->trigger(VMMAction::POLL,vm->get_oid());
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -276,8 +275,7 @@ void LifeCycleManager::deploy_success_action(int vid)
|
||||
|
||||
if ( vm->get_lcm_state() == VirtualMachine::MIGRATE )
|
||||
{
|
||||
int cpu,mem,disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
|
||||
@ -295,9 +293,9 @@ void LifeCycleManager::deploy_success_action(int vid)
|
||||
|
||||
vmpool->update_previous_history(vm);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_previous_hid(),vm->get_oid(),cpu,mem,disk,pci);
|
||||
hpool->del_capacity(vm->get_previous_hid(), sr);
|
||||
|
||||
vm->set_state(VirtualMachine::RUNNING);
|
||||
|
||||
@ -355,8 +353,7 @@ void LifeCycleManager::deploy_failure_action(int vid)
|
||||
|
||||
if ( vm->get_lcm_state() == VirtualMachine::MIGRATE )
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
|
||||
@ -380,9 +377,9 @@ void LifeCycleManager::deploy_failure_action(int vid)
|
||||
|
||||
vmpool->update_previous_history(vm);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
// --- Add new record by copying the previous one
|
||||
|
||||
@ -765,8 +762,7 @@ void LifeCycleManager::prolog_success_action(int vid)
|
||||
|
||||
void LifeCycleManager::prolog_failure_action(int vid)
|
||||
{
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t t = time(0);
|
||||
|
||||
@ -846,9 +842,9 @@ void LifeCycleManager::prolog_failure_action(int vid)
|
||||
break;
|
||||
}
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu,mem,disk,pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
// Clone previous history record into a new one
|
||||
vm->cp_previous_history();
|
||||
@ -857,7 +853,7 @@ void LifeCycleManager::prolog_failure_action(int vid)
|
||||
vm->set_prolog_stime(t);
|
||||
vm->set_last_poll(0);
|
||||
|
||||
hpool->add_capacity(vm->get_hid(),vm->get_oid(),cpu,mem,disk,pci);
|
||||
hpool->add_capacity(vm->get_hid(), sr);
|
||||
|
||||
vmpool->insert_history(vm);
|
||||
|
||||
@ -886,11 +882,11 @@ void LifeCycleManager::prolog_failure_action(int vid)
|
||||
|
||||
void LifeCycleManager::epilog_success_action(int vid)
|
||||
{
|
||||
VirtualMachine * vm;
|
||||
vector<VectorAttribute *> pci;
|
||||
VirtualMachine * vm;
|
||||
|
||||
HostShareCapacity sr;
|
||||
|
||||
time_t the_time = time(0);
|
||||
int cpu,mem,disk;
|
||||
unsigned int port;
|
||||
|
||||
VirtualMachine::LcmState state;
|
||||
@ -971,9 +967,9 @@ void LifeCycleManager::epilog_success_action(int vid)
|
||||
|
||||
vmpool->update(vm);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
hpool->del_capacity(vm->get_hid(), vm->get_oid(), cpu, mem, disk, pci);
|
||||
hpool->del_capacity(vm->get_hid(), sr);
|
||||
|
||||
//----------------------------------------------------
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool RequestManagerAllocate::allocate_authorization(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
Template * tmpl,
|
||||
RequestAttributes& att,
|
||||
PoolObjectAuth * cluster_perms)
|
||||
@ -62,7 +62,7 @@ bool RequestManagerAllocate::allocate_authorization(
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachineAllocate::allocate_authorization(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
Template * tmpl,
|
||||
RequestAttributes& att,
|
||||
PoolObjectAuth * cluster_perms)
|
||||
@ -102,7 +102,13 @@ bool VirtualMachineAllocate::allocate_authorization(
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------- Check Quotas ----------------------------
|
||||
// ---------------------- Check Quotas & Topology --------------------------
|
||||
|
||||
if (VirtualMachine::parse_topology(ttmpl, att.resp_msg) != 0)
|
||||
{
|
||||
failure_response(ALLOCATE, att);
|
||||
return false;
|
||||
}
|
||||
|
||||
VirtualMachineTemplate aux_tmpl(*ttmpl);
|
||||
|
||||
|
@ -82,7 +82,7 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList
|
||||
}
|
||||
|
||||
ErrorCode ec = tmpl_clone.request_execute(id, tmpl_name, new_id, true,
|
||||
str_uattrs, att);
|
||||
str_uattrs, att);
|
||||
|
||||
if (ec != SUCCESS)
|
||||
{
|
||||
@ -199,6 +199,12 @@ Request::ErrorCode VMTemplateInstantiate::request_execute(int id, string name,
|
||||
tmpl->set(new SingleAttribute("NAME",name));
|
||||
}
|
||||
|
||||
if (VirtualMachine::parse_topology(tmpl, att.resp_msg) != 0)
|
||||
{
|
||||
delete tmpl;
|
||||
return ALLOCATE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
AuthRequest ar(att.uid, att.group_ids);
|
||||
|
@ -367,19 +367,16 @@ int RequestManagerVirtualMachine::get_host_information(
|
||||
bool RequestManagerVirtualMachine::check_host(
|
||||
int hid, bool enforce, VirtualMachine* vm, string& error)
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
HostPool * hpool = nd.get_hpool();
|
||||
HostPool * hpool = Nebula::instance().get_hpool();
|
||||
|
||||
Host * host;
|
||||
bool test;
|
||||
bool test = true;
|
||||
string capacity_error;
|
||||
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
host = hpool->get_ro(hid);
|
||||
Host * host = hpool->get_ro(hid);
|
||||
|
||||
if (host == 0)
|
||||
{
|
||||
@ -387,16 +384,14 @@ bool RequestManagerVirtualMachine::check_host(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enforce)
|
||||
if ( enforce )
|
||||
{
|
||||
test = host->test_capacity(cpu, mem, disk, pci, capacity_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
test = host->test_capacity(pci, capacity_error);
|
||||
test = host->test_capacity(sr, capacity_error);
|
||||
}
|
||||
|
||||
if (!test)
|
||||
host->unlock();
|
||||
|
||||
if (enforce && !test)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
@ -407,8 +402,6 @@ bool RequestManagerVirtualMachine::check_host(
|
||||
error = oss.str();
|
||||
}
|
||||
|
||||
host->unlock();
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
@ -834,6 +827,8 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
int uid = vm->get_uid();
|
||||
int gid = vm->get_gid();
|
||||
|
||||
enforce = enforce || vm->is_pinned();
|
||||
|
||||
vm->unlock();
|
||||
|
||||
if (is_public_cloud) // Set ds_id to -1 and tm_mad empty(). This is used by
|
||||
@ -967,7 +962,7 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_host(hid, enforce, vm, att.resp_msg) == false)
|
||||
if (check_host(hid, enforce || vm->is_pinned(), vm, att.resp_msg) == false)
|
||||
{
|
||||
vm->unlock();
|
||||
|
||||
@ -1180,6 +1175,15 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList
|
||||
if (live)
|
||||
{
|
||||
action = History::LIVE_MIGRATE_ACTION;
|
||||
|
||||
if ( vm->is_pinned() )
|
||||
{
|
||||
att.resp_msg = "VM with a pinned NUMA topology cannot be live-migrated";
|
||||
failure_response(ACTION, att);
|
||||
|
||||
vm->unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1239,16 +1243,17 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList
|
||||
}
|
||||
|
||||
//Check PCI devices are compatible with migration type
|
||||
int cpu, mem, disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
if ((pci.size() > 0) && (!poffmgr && vm->get_state() != VirtualMachine::POWEROFF))
|
||||
if ((sr.pci.size() > 0) && (!poffmgr &&
|
||||
vm->get_state() != VirtualMachine::POWEROFF))
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << "Cannot migrate VM [" << id << "], for migrating a VM with PCI devices attached it's necessary either the poweroff or poweroff-hard flag";
|
||||
oss << "Cannot migrate VM [" << id << "], use poweroff or poweroff-hard"
|
||||
" flag for migrating a VM with PCI devices";
|
||||
|
||||
att.resp_msg = oss.str();
|
||||
failure_response(ACTION, att);
|
||||
@ -1948,43 +1953,81 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int test_set_capacity(VirtualMachine * vm, float cpu, long mem, int vcpu,
|
||||
string& error)
|
||||
{
|
||||
HostPool * hpool = Nebula::instance().get_hpool();
|
||||
|
||||
int rc;
|
||||
|
||||
if ( vm->get_state() == VirtualMachine::POWEROFF )
|
||||
{
|
||||
HostShareCapacity sr;
|
||||
|
||||
Host * host = hpool->get(vm->get_hid());
|
||||
|
||||
if ( host == 0 )
|
||||
{
|
||||
error = "Could not update host";
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm->get_capacity(sr);
|
||||
|
||||
host->del_capacity(sr);
|
||||
|
||||
rc = vm->resize(cpu, mem, vcpu, error);
|
||||
|
||||
if ( rc == -1 )
|
||||
{
|
||||
host->unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm->get_capacity(sr);
|
||||
|
||||
if (!host->test_capacity(sr, error))
|
||||
{
|
||||
host->unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
host->add_capacity(sr);
|
||||
|
||||
hpool->update(host);
|
||||
|
||||
host->unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = vm->resize(cpu, mem, vcpu, error);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
||||
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
||||
bool enforce_param = xmlrpc_c::value_boolean(paramList.getBoolean(3));
|
||||
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
||||
std::string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
||||
//Argument 3 enforce deprecated to check/re-evaluate NUMA topology
|
||||
|
||||
float ncpu, ocpu, dcpu;
|
||||
int nmemory, omemory, dmemory;
|
||||
long nmemory, omemory, dmemory;
|
||||
int nvcpu, ovcpu;
|
||||
|
||||
Nebula& nd = Nebula::instance();
|
||||
HostPool * hpool = nd.get_hpool();
|
||||
Host * host;
|
||||
|
||||
Template deltas;
|
||||
bool rc;
|
||||
int ret;
|
||||
int hid = -1;
|
||||
|
||||
PoolObjectAuth vm_perms;
|
||||
|
||||
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
||||
VirtualMachine * vm;
|
||||
VirtualMachineTemplate tmpl;
|
||||
|
||||
bool enforce = true;
|
||||
|
||||
if (att.is_admin())
|
||||
{
|
||||
enforce = enforce_param;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Parse template
|
||||
// -------------------------------------------------------------------------
|
||||
rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
||||
int rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
||||
|
||||
if ( rc != 0 )
|
||||
{
|
||||
@ -2016,12 +2059,40 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Get the resize values */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
ncpu = nvcpu = nmemory = 0;
|
||||
|
||||
tmpl.get("CPU", ncpu);
|
||||
tmpl.get("VCPU", nvcpu);
|
||||
tmpl.get("MEMORY", nmemory);
|
||||
|
||||
vm = vmpool->get_ro(id);
|
||||
if (ncpu < 0)
|
||||
{
|
||||
att.resp_msg = "CPU must be a positive float or integer value.";
|
||||
|
||||
failure_response(INTERNAL, att);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nmemory < 0)
|
||||
{
|
||||
att.resp_msg = "MEMORY must be a positive integer value.";
|
||||
|
||||
failure_response(INTERNAL, att);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nvcpu < 0)
|
||||
{
|
||||
att.resp_msg = "VCPU must be a positive integer value.";
|
||||
|
||||
failure_response(INTERNAL, att);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Compute deltas and check quotas */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
VirtualMachine * vm = vmpool->get_ro(id);
|
||||
|
||||
if (vm == 0)
|
||||
{
|
||||
@ -2036,6 +2107,13 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
vm->get_template_attribute("CPU", ocpu);
|
||||
vm->get_template_attribute("VCPU", ovcpu);
|
||||
|
||||
if (vm->is_pinned())
|
||||
{
|
||||
ncpu = nvcpu;
|
||||
}
|
||||
|
||||
vm->unlock();
|
||||
|
||||
if (nmemory == 0)
|
||||
{
|
||||
nmemory = omemory;
|
||||
@ -2058,50 +2136,6 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
deltas.add("CPU", dcpu);
|
||||
deltas.add("VMS", 0);
|
||||
|
||||
switch (vm->get_state())
|
||||
{
|
||||
case VirtualMachine::POWEROFF: //Only check host capacity in POWEROFF
|
||||
if (vm->hasHistory() == true)
|
||||
{
|
||||
hid = vm->get_hid();
|
||||
}
|
||||
break;
|
||||
|
||||
case VirtualMachine::INIT:
|
||||
case VirtualMachine::PENDING:
|
||||
case VirtualMachine::HOLD:
|
||||
case VirtualMachine::UNDEPLOYED:
|
||||
case VirtualMachine::CLONING:
|
||||
case VirtualMachine::CLONING_FAILURE:
|
||||
break;
|
||||
|
||||
case VirtualMachine::STOPPED:
|
||||
case VirtualMachine::DONE:
|
||||
case VirtualMachine::SUSPENDED:
|
||||
case VirtualMachine::ACTIVE:
|
||||
att.resp_msg="Resize action is not available for state " +
|
||||
vm->state_str();
|
||||
|
||||
failure_response(ACTION, att);
|
||||
|
||||
vm->unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vm->check_resize(ncpu, nmemory, nvcpu, att.resp_msg);
|
||||
|
||||
vm->unlock();
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
failure_response(INTERNAL, att);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Check quotas */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
if (quota_resize_authorization(&deltas, att, vm_perms) == false)
|
||||
{
|
||||
return;
|
||||
@ -2110,58 +2144,8 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes att_rollback(vm_perms.uid, vm_perms.gid, att);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Check & update host capacity */
|
||||
/* Check & update VM & host capacity */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
if (hid != -1)
|
||||
{
|
||||
int dcpu_host = (int) (dcpu * 100);//now in 100%
|
||||
int dmem_host = dmemory * 1024; //now in Kilobytes
|
||||
|
||||
vector<VectorAttribute *> empty_pci;
|
||||
|
||||
host = hpool->get(hid);
|
||||
|
||||
if (host == 0)
|
||||
{
|
||||
att.resp_obj = PoolObjectSQL::HOST;
|
||||
att.resp_id = hid;
|
||||
failure_response(NO_EXISTS, att);
|
||||
|
||||
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0,
|
||||
empty_pci, att.resp_msg) == false)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << object_name(PoolObjectSQL::HOST) << " " << hid
|
||||
<< " does not have enough capacity.";
|
||||
|
||||
att.resp_msg = oss.str();
|
||||
failure_response(ACTION, att);
|
||||
|
||||
host->unlock();
|
||||
|
||||
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
host->update_capacity(dcpu_host, dmem_host, 0);
|
||||
|
||||
hpool->update(host);
|
||||
|
||||
host->unlock();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Resize the VM */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
vm = vmpool->get(id);
|
||||
|
||||
if (vm == 0)
|
||||
@ -2170,77 +2154,48 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
failure_response(NO_EXISTS, att);
|
||||
|
||||
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
||||
|
||||
if (hid != -1)
|
||||
{
|
||||
host = hpool->get(hid);
|
||||
|
||||
if (host != 0)
|
||||
{
|
||||
host->update_capacity(-dcpu, -dmemory, 0);
|
||||
hpool->update(host);
|
||||
|
||||
host->unlock();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Check again state as the VM may transit to active (e.g. scheduled)
|
||||
switch (vm->get_state())
|
||||
{
|
||||
case VirtualMachine::POWEROFF: //Only check host capacity in POWEROFF
|
||||
case VirtualMachine::INIT:
|
||||
case VirtualMachine::PENDING:
|
||||
case VirtualMachine::HOLD:
|
||||
case VirtualMachine::POWEROFF:
|
||||
case VirtualMachine::UNDEPLOYED:
|
||||
case VirtualMachine::CLONING:
|
||||
case VirtualMachine::CLONING_FAILURE:
|
||||
ret = vm->resize(ncpu, nmemory, nvcpu, att.resp_msg);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
vm->unlock();
|
||||
|
||||
failure_response(INTERNAL, att);
|
||||
return;
|
||||
}
|
||||
|
||||
vmpool->update(vm);
|
||||
vmpool->update_search(vm);
|
||||
rc = test_set_capacity(vm, ncpu, nmemory, nvcpu, att.resp_msg);
|
||||
break;
|
||||
|
||||
case VirtualMachine::STOPPED:
|
||||
case VirtualMachine::DONE:
|
||||
case VirtualMachine::SUSPENDED:
|
||||
case VirtualMachine::ACTIVE:
|
||||
att.resp_msg = "Resize action is not available for state " +
|
||||
vm->state_str();
|
||||
|
||||
failure_response(ACTION, att);
|
||||
|
||||
vm->unlock();
|
||||
|
||||
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
||||
|
||||
if (hid != -1)
|
||||
{
|
||||
host = hpool->get(hid);
|
||||
|
||||
if (host != 0)
|
||||
{
|
||||
host->update_capacity(ocpu - ncpu, omemory - nmemory, 0);
|
||||
hpool->update(host);
|
||||
|
||||
host->unlock();
|
||||
}
|
||||
}
|
||||
return;
|
||||
rc = -1;
|
||||
att.resp_msg = "Cannot resize a VM in state " + vm->state_str();
|
||||
break;
|
||||
}
|
||||
|
||||
vm->unlock();
|
||||
if ( rc == -1 )
|
||||
{
|
||||
vm->unlock();
|
||||
|
||||
success_response(id, att);
|
||||
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
||||
|
||||
failure_response(ACTION, att);
|
||||
}
|
||||
else
|
||||
{
|
||||
vmpool->update(vm);
|
||||
|
||||
vm->unlock();
|
||||
|
||||
success_response(id, att);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -24,7 +24,124 @@
|
||||
#include "HostShare.h"
|
||||
#include "PoolObjectAuth.h"
|
||||
|
||||
using namespace std;
|
||||
/**
|
||||
* This class represents the needed information HostShare for a Host to
|
||||
* perform the scheduling
|
||||
*/
|
||||
class HostShareXML
|
||||
{
|
||||
public:
|
||||
HostShareXML(){};
|
||||
|
||||
virtual ~HostShareXML(){};
|
||||
|
||||
/**
|
||||
* Tests whether a new VM can be hosted by the host or not
|
||||
* @param sr the share request including CPU, memory, PCI and NUMA nodes
|
||||
* @return true if the share can host the VM
|
||||
*/
|
||||
bool test_capacity(HostShareCapacity& sr, string & error);
|
||||
|
||||
/**
|
||||
* Adds a new VM to the given share by incrementing the cpu,mem and disk
|
||||
* counters
|
||||
* @param cpu needed by the VM (percentage)
|
||||
* @param mem needed by the VM (in KB)
|
||||
* @return 0 on success
|
||||
*/
|
||||
void add_capacity(HostShareCapacity& sr)
|
||||
{
|
||||
cpu_usage += sr.cpu;
|
||||
mem_usage += sr.mem;
|
||||
|
||||
pci.add(sr.pci, sr.vmid);
|
||||
|
||||
numa.add(sr);
|
||||
|
||||
running_vms++;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a VM to the given host by updating the cpu,mem and disk
|
||||
* counters
|
||||
* @param cpu needed by the VM (percentage)
|
||||
* @param mem needed by the VM (in KB)
|
||||
* @return 0 on success
|
||||
*/
|
||||
void del_capacity(HostShareCapacity& sr)
|
||||
{
|
||||
cpu_usage -= sr.cpu;
|
||||
mem_usage -= sr.mem;
|
||||
|
||||
running_vms--;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether a new VM can be hosted by the local system DS or not
|
||||
* @param dsid DS id
|
||||
* @param vm_disk_mb System disk needed by the VM (in MB)
|
||||
* @return true if the share can host the VM
|
||||
*/
|
||||
bool test_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
if (ds_free_disk.count(dsid) == 0)
|
||||
{
|
||||
ds_free_disk[dsid] = free_disk;
|
||||
}
|
||||
|
||||
return (vm_disk_mb < ds_free_disk[dsid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new VM to the given local sytem DS share by incrementing the disk
|
||||
* counter
|
||||
* @param dsid DS id
|
||||
* @param vm_disk_mb System disk needed by the VM (in MB)
|
||||
*/
|
||||
void add_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
if (ds_free_disk.count(dsid) == 0)
|
||||
{
|
||||
ds_free_disk[dsid] = free_disk;
|
||||
}
|
||||
|
||||
ds_free_disk[dsid] -= vm_disk_mb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the share information to an output stream.
|
||||
*/
|
||||
friend ostream& operator<<(ostream& o, const HostShareXML& p);
|
||||
|
||||
private:
|
||||
friend class HostXML;
|
||||
|
||||
// Host computing capacity and usage
|
||||
long long mem_usage;
|
||||
long long cpu_usage;
|
||||
|
||||
long long max_mem;
|
||||
long long max_cpu;
|
||||
|
||||
long long running_vms;
|
||||
|
||||
// PCI devices
|
||||
HostSharePCI pci;
|
||||
|
||||
// System datastore
|
||||
long long free_disk;
|
||||
map<int, long long> ds_free_disk;
|
||||
|
||||
//Numa Nodes
|
||||
HostShareNUMA numa;
|
||||
|
||||
/**
|
||||
* Construct the share information from the XML information in the
|
||||
* <HOST> element
|
||||
*/
|
||||
void init_attributes(ObjectXML * host);
|
||||
};
|
||||
|
||||
|
||||
class HostXML : public ObjectXML
|
||||
{
|
||||
@ -39,6 +156,9 @@ public:
|
||||
init_attributes();
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int get_hid() const
|
||||
{
|
||||
return oid;
|
||||
@ -54,29 +174,26 @@ public:
|
||||
return dispatched_vms.size();
|
||||
}
|
||||
|
||||
bool is_public_cloud() const
|
||||
{
|
||||
return public_cloud;
|
||||
}
|
||||
|
||||
void get_permissions(PoolObjectAuth& auth);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/**
|
||||
* 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 sr, the host share capacity request including cpu, mem, pci
|
||||
* devices and numa topology
|
||||
* @param error error message
|
||||
* @return true if the share can host the VM
|
||||
*/
|
||||
bool test_capacity(long long cpu, long long mem,
|
||||
vector<VectorAttribute *> &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,vector<VectorAttribute *> &p)
|
||||
bool test_capacity(HostShareCapacity &sr, string & error)
|
||||
{
|
||||
string tmp_st;
|
||||
return test_capacity(cpu, mem, p, tmp_st);
|
||||
};
|
||||
return share.test_capacity(sr, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new VM to the given share by incrementing the cpu,mem and disk
|
||||
@ -85,17 +202,10 @@ public:
|
||||
* @param mem needed by the VM (in KB)
|
||||
* @return 0 on success
|
||||
*/
|
||||
void add_capacity(int vmid, long long cpu, long long mem,
|
||||
vector<VectorAttribute *> &p)
|
||||
void add_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
cpu_usage += cpu;
|
||||
mem_usage += mem;
|
||||
|
||||
pci.add(p, vmid);
|
||||
|
||||
dispatched_vms.insert(vmid);
|
||||
|
||||
running_vms++;
|
||||
share.add_capacity(sr);
|
||||
dispatched_vms.insert(sr.vmid);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -105,12 +215,9 @@ public:
|
||||
* @param mem needed by the VM (in KB)
|
||||
* @return 0 on success
|
||||
*/
|
||||
void del_capacity(int cpu, int mem)
|
||||
void del_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
cpu_usage -= cpu;
|
||||
mem_usage -= mem;
|
||||
|
||||
running_vms--;
|
||||
share.del_capacity(sr);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -119,7 +226,10 @@ public:
|
||||
* @param vm_disk_mb System disk needed by the VM (in MB)
|
||||
* @return true if the share can host the VM
|
||||
*/
|
||||
bool test_ds_capacity(int dsid, long long vm_disk_mb);
|
||||
bool test_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
return share.test_ds_capacity(dsid, vm_disk_mb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new VM to the given local sytem DS share by incrementing the disk
|
||||
@ -127,7 +237,10 @@ public:
|
||||
* @param dsid DS id
|
||||
* @param vm_disk_mb System disk needed by the VM (in MB)
|
||||
*/
|
||||
void add_ds_capacity(int dsid, long long vm_disk_mb);
|
||||
void add_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
share.add_ds_capacity(dsid, vm_disk_mb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the Object for a given attribute in a set of object specific
|
||||
@ -152,57 +265,25 @@ public:
|
||||
return __search(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the host is a remote public cloud
|
||||
* @return true if the host is a remote public cloud
|
||||
*/
|
||||
bool is_public_cloud() const
|
||||
{
|
||||
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);
|
||||
|
||||
/**
|
||||
* Fills a auth class to perform an authZ/authN request based on the object
|
||||
* attributes
|
||||
* @param auths to be filled
|
||||
*/
|
||||
void get_permissions(PoolObjectAuth& auth);
|
||||
|
||||
private:
|
||||
int oid;
|
||||
int cluster_id;
|
||||
|
||||
// Host share values
|
||||
long long mem_usage; /**< Memory allocated to VMs (in KB) */
|
||||
long long cpu_usage; /**< CPU allocated to VMs (in percentage)*/
|
||||
HostShareXML share;
|
||||
|
||||
long long max_mem; /**< Total memory capacity (in KB) */
|
||||
long long max_cpu; /**< Total cpu capacity (in percentage)*/
|
||||
bool public_cloud;
|
||||
|
||||
HostSharePCI pci; /**< PCI devices of the host */
|
||||
// ---------------------------------------------------------------------- //
|
||||
// Scheduling statistics //
|
||||
// ---------------------------------------------------------------------- //
|
||||
set<int> dispatched_vms;
|
||||
|
||||
long long free_disk; /**< Free disk capacity (in MB)*/
|
||||
|
||||
map<int, long long> ds_free_disk; /**< Free MB for local system DS */
|
||||
|
||||
long long running_vms; /**< Number of running VMs in this Host */
|
||||
set<int> dispatched_vms; /**< Dispatched VMs to this host in this cycle */
|
||||
|
||||
bool public_cloud; /**< This host is a public cloud */
|
||||
|
||||
// Configuration attributes
|
||||
static const char *host_paths[]; /**< paths for search function */
|
||||
static int host_num_paths; /**< number of paths */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Functions to search for values in the HostXML object */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
bool is_dispatched(const std::string& vm_id) const
|
||||
{
|
||||
std::istringstream iss(vm_id);
|
||||
@ -225,6 +306,13 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Functions to search for values in the HostXML object */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static const char *host_paths[];
|
||||
|
||||
static int host_num_paths;
|
||||
|
||||
/**
|
||||
* Search the Object for a given attribute in a set of object specific
|
||||
* routes. Overrite ObjectXML function to deal with pseudo-attributes
|
||||
|
@ -135,156 +135,110 @@ public:
|
||||
//--------------------------------------------------------------------------
|
||||
// Get Methods for VirtualMachineXML class
|
||||
//--------------------------------------------------------------------------
|
||||
int get_oid() const
|
||||
{
|
||||
return oid;
|
||||
};
|
||||
int get_oid() const { return oid; };
|
||||
|
||||
int get_uid() const
|
||||
{
|
||||
return uid;
|
||||
};
|
||||
int get_uid() const { return uid; };
|
||||
|
||||
int get_gid() const
|
||||
{
|
||||
return gid;
|
||||
};
|
||||
int get_gid() const { return gid; };
|
||||
|
||||
int get_hid() const
|
||||
{
|
||||
return hid;
|
||||
};
|
||||
int get_hid() const { return hid; };
|
||||
|
||||
int get_dsid() const
|
||||
{
|
||||
return dsid;
|
||||
};
|
||||
int get_dsid() const { return dsid; };
|
||||
|
||||
time_t get_stime() const
|
||||
{
|
||||
return stime;
|
||||
}
|
||||
time_t get_stime() const { return stime; }
|
||||
|
||||
bool is_resched() const
|
||||
{
|
||||
return (resched == 1);
|
||||
}
|
||||
bool is_resched() const { return resched; }
|
||||
|
||||
bool is_resume() const
|
||||
{
|
||||
return resume;
|
||||
}
|
||||
bool is_resume() const { return resume; }
|
||||
|
||||
const string& get_rank()
|
||||
{
|
||||
return rank;
|
||||
};
|
||||
bool is_public_cloud() const { return public_cloud; }
|
||||
|
||||
const string& get_ds_rank()
|
||||
{
|
||||
return ds_rank;
|
||||
};
|
||||
bool is_active() const { return active; }
|
||||
|
||||
const string& get_nic_rank(int nic_id)
|
||||
{
|
||||
static std::string es;
|
||||
bool is_only_public_cloud() const { return only_public_cloud; }
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
void set_only_public_cloud() { only_public_cloud = true; }
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
return it->second->get_rank();
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
// Scheduling requirements and rank
|
||||
//--------------------------------------------------------------------------
|
||||
const string& get_requirements() { return requirements; };
|
||||
|
||||
return es;
|
||||
};
|
||||
const string& get_ds_requirements() { return ds_requirements; }
|
||||
|
||||
const string& get_requirements()
|
||||
{
|
||||
return requirements;
|
||||
};
|
||||
const string& get_rank() { return rank; };
|
||||
|
||||
const string& get_ds_requirements()
|
||||
{
|
||||
return ds_requirements;
|
||||
}
|
||||
|
||||
const string& get_nic_requirements(int nic_id)
|
||||
{
|
||||
static std::string es;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
return it->second->get_requirements();
|
||||
}
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return VM usage requirments
|
||||
*/
|
||||
void get_requirements(int& cpu, int& memory, long long& disk,
|
||||
vector<VectorAttribute *> &pci);
|
||||
|
||||
/**
|
||||
* Return the requirements of this VM (as is) and reset them
|
||||
* @param cpu in unit
|
||||
* @param memory in kb
|
||||
* @param disk in mb (system ds usage)
|
||||
*/
|
||||
void reset_requirements(float& cpu, int& memory, long long& disk);
|
||||
|
||||
/**
|
||||
* @return the usage requirements in image ds.
|
||||
*/
|
||||
map<int,long long> get_storage_usage();
|
||||
|
||||
/**
|
||||
* Checks if the VM can be deployed in a public cloud provider
|
||||
* @return true if the VM can be deployed in a public cloud provider
|
||||
*/
|
||||
bool is_public_cloud() const
|
||||
{
|
||||
return public_cloud;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds usage requirements to this VM
|
||||
* @param cpu in unit form
|
||||
* @param m memory in kb
|
||||
* @param d in mb (system ds usage)
|
||||
*/
|
||||
void add_requirements(float c, long int m, long long d);
|
||||
const string& get_ds_rank() { return ds_rank; };
|
||||
|
||||
/**
|
||||
* Adds (logical AND) new placement requirements to the current ones
|
||||
* @param reqs additional requirements
|
||||
*/
|
||||
void add_requirements(const string& reqs)
|
||||
{
|
||||
if ( reqs.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ( requirements.empty() )
|
||||
{
|
||||
requirements = reqs;
|
||||
}
|
||||
else
|
||||
{
|
||||
requirements += " & (" + reqs + ")";
|
||||
}
|
||||
}
|
||||
void add_requirements(const string& reqs);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Functions to schedule network interfaces (NIC)
|
||||
//--------------------------------------------------------------------------
|
||||
VirtualMachineNicXML * get_nic(int nic_id);
|
||||
|
||||
const string& get_nic_rank(int nic_id);
|
||||
|
||||
const string& get_nic_requirements(int nic_id);
|
||||
|
||||
/**
|
||||
* Check if the VM is ACTIVE state
|
||||
* Return ids of NICs with NETWORK_MODE=auto (i.e. need to schedule networks)
|
||||
*/
|
||||
bool is_active() const
|
||||
set<int> get_nics_ids()
|
||||
{
|
||||
return state == 3;
|
||||
return nics_ids_auto;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Capacity Interface
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* This function fills a share capacity request based on the VM information:
|
||||
* - cpu
|
||||
* - memory
|
||||
* - system_ds disk usage
|
||||
* - PCI devices
|
||||
* - NUMA node topology
|
||||
*/
|
||||
void get_capacity(HostShareCapacity &sr);
|
||||
|
||||
/**
|
||||
* Add capacity to (cpu, mem, system_ds disk, numa_nodes) this VM
|
||||
* @param the capacity to be added
|
||||
*/
|
||||
void add_capacity(HostShareCapacity &sr);
|
||||
|
||||
/**
|
||||
* Clears the capacity allocaton of this VM and return it.
|
||||
* @param sr, the sorage requirements
|
||||
*/
|
||||
void reset_capacity(HostShareCapacity &sr);
|
||||
|
||||
/**
|
||||
* Tests if the Image DS have enough free space to host the VM
|
||||
* @param img_datastores Image Datastores
|
||||
* @param error_msg error reason
|
||||
* @return true if the Image Datastores can host the VM
|
||||
*/
|
||||
bool test_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool, string & error_msg) const;
|
||||
|
||||
/**
|
||||
* Adds the VM disk requirements to each Image Datastore counter
|
||||
* @param img_datastores Image Datastores
|
||||
*/
|
||||
void add_image_datastore_capacity(ImageDatastorePoolXML * img_dspool);
|
||||
|
||||
/**
|
||||
* @return storage usage for the VM
|
||||
*/
|
||||
map<int,long long> get_storage_usage()
|
||||
{
|
||||
return ds_usage;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -296,7 +250,7 @@ public:
|
||||
*/
|
||||
void add_match_host(int oid)
|
||||
{
|
||||
if (( resched == 1 && hid != oid ) || ( resched == 0 ))
|
||||
if ((resched && hid != oid) || !resched )
|
||||
{
|
||||
match_hosts.add_resource(oid);
|
||||
}
|
||||
@ -317,7 +271,7 @@ public:
|
||||
*/
|
||||
void add_match_network(int oid, int nic_id)
|
||||
{
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
auto it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
@ -348,7 +302,7 @@ public:
|
||||
{
|
||||
static std::vector<Resource *> ev;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
auto it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
@ -358,23 +312,6 @@ public:
|
||||
return ev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a VirtualMachineNicXML
|
||||
*/
|
||||
VirtualMachineNicXML * get_nic(int nic_id)
|
||||
{
|
||||
VirtualMachineNicXML * n = 0;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
n = it->second;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the matched hosts for the VM
|
||||
*/
|
||||
@ -396,7 +333,7 @@ public:
|
||||
*/
|
||||
void sort_match_networks(int nic_id)
|
||||
{
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
auto it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
@ -425,25 +362,12 @@ public:
|
||||
*/
|
||||
void clear_match_networks()
|
||||
{
|
||||
map<int, VirtualMachineNicXML *>::iterator it;
|
||||
|
||||
for (it = nics.begin(); it != nics.end(); it++ )
|
||||
for (auto it = nics.begin(); it != nics.end(); it++ )
|
||||
{
|
||||
it->second->clear_match_networks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the VM to be only deployed on public cloud hosts
|
||||
*/
|
||||
void set_only_public_cloud();
|
||||
|
||||
/**
|
||||
* Returns true is the VM can only be deployed in public cloud hosts
|
||||
* @return true is the VM can only be deployed in public cloud hosts
|
||||
*/
|
||||
bool is_only_public_cloud() const;
|
||||
|
||||
/**
|
||||
* Add a VM to the set of affined VMs. This is used for the VM leader
|
||||
* when scheduling a group.
|
||||
@ -462,28 +386,8 @@ public:
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Capacity Interface
|
||||
// Scheduled Action Interface
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Tests if the Image DS have enough free space to host the VM
|
||||
* @param img_datastores Image Datastores
|
||||
* @param error_msg error reason
|
||||
* @return true if the Image Datastores can host the VM
|
||||
*/
|
||||
bool test_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool, string & error_msg) const;
|
||||
|
||||
/**
|
||||
* Adds the VM disk requirements to each Image Datastore counter
|
||||
* @param img_datastores Image Datastores
|
||||
*/
|
||||
void add_image_datastore_capacity(ImageDatastorePoolXML * img_dspool);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Action Interface
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the user template of the VM
|
||||
* @return the template as a XML string
|
||||
@ -531,6 +435,9 @@ public:
|
||||
*/
|
||||
static int parse_action_name(string& action_st);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Logging
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* Function to write a Virtual Machine in an output stream
|
||||
*/
|
||||
@ -549,16 +456,7 @@ public:
|
||||
*/
|
||||
bool clear_log();
|
||||
|
||||
/**
|
||||
* Return ids of NICs with NETWORK_MODE=auto (i.e. need to schedule networks)
|
||||
*/
|
||||
set<int> get_nics_ids()
|
||||
{
|
||||
return nics_ids_auto;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* For constructors
|
||||
*/
|
||||
@ -566,30 +464,28 @@ protected:
|
||||
|
||||
void init_storage_usage();
|
||||
|
||||
/* ------------------- SCHEDULER INFORMATION --------------------------- */
|
||||
|
||||
/* ---------------------- SCHEDULER INFORMATION ------------------------- */
|
||||
ResourceMatch match_hosts;
|
||||
|
||||
ResourceMatch match_datastores;
|
||||
|
||||
|
||||
bool only_public_cloud;
|
||||
|
||||
set<int> affined_vms;
|
||||
|
||||
/* ----------------------- VIRTUAL MACHINE ATTRIBUTES ------------------- */
|
||||
int oid;
|
||||
int oid;
|
||||
|
||||
int uid;
|
||||
int gid;
|
||||
int uid;
|
||||
int gid;
|
||||
|
||||
int hid;
|
||||
int dsid;
|
||||
int hid;
|
||||
int dsid;
|
||||
|
||||
int resched;
|
||||
bool resume;
|
||||
|
||||
int state;
|
||||
bool resched;
|
||||
bool resume;
|
||||
bool active;
|
||||
bool public_cloud;
|
||||
|
||||
long int memory;
|
||||
float cpu;
|
||||
@ -597,8 +493,6 @@ protected:
|
||||
|
||||
map<int,long long> ds_usage;
|
||||
|
||||
bool public_cloud;
|
||||
|
||||
string rank;
|
||||
string requirements;
|
||||
|
||||
|
@ -35,55 +35,148 @@ const char *HostXML::host_paths[] = {
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void HostXML::init_attributes()
|
||||
void HostShareXML::init_attributes(ObjectXML * host)
|
||||
{
|
||||
xpath(oid, "/HOST/ID", -1);
|
||||
xpath(cluster_id, "/HOST/CLUSTER_ID", -1);
|
||||
xpath<long long>(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0);
|
||||
xpath<long long>(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0);
|
||||
xpath<long long>(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0);
|
||||
xpath<long long>(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0);
|
||||
xpath<long long>(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0);
|
||||
xpath<long long>(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0);
|
||||
//------------------ HostShare Computing Capacity --------------------------
|
||||
host->xpath<long long>(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0);
|
||||
host->xpath<long long>(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0);
|
||||
|
||||
string public_cloud_st;
|
||||
host->xpath<long long>(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0);
|
||||
host->xpath<long long>(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0);
|
||||
|
||||
xpath(public_cloud_st, "/HOST/TEMPLATE/PUBLIC_CLOUD", "");
|
||||
public_cloud = (one_util::toupper(public_cloud_st) == "YES");
|
||||
host->xpath<long long>(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0);
|
||||
host->xpath<long long>(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0);
|
||||
|
||||
//-------------------- HostShare Datastores ------------------------------
|
||||
vector<string> ds_ids;
|
||||
vector<string> ds_free;
|
||||
std::vector<int> ds_ids;
|
||||
std::vector<long long> ds_free;
|
||||
|
||||
xpaths(ds_ids, "/HOST/HOST_SHARE/DATASTORES/DS/ID");
|
||||
xpaths(ds_free,"/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB");
|
||||
|
||||
int id;
|
||||
long long disk;
|
||||
host->xpaths<int>(ds_ids, "/HOST/HOST_SHARE/DATASTORES/DS/ID");
|
||||
host->xpaths<long long>(ds_free, "/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB");
|
||||
|
||||
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[i].c_str());
|
||||
|
||||
ds_free_disk[id] = disk;
|
||||
ds_free_disk[ds_ids[i]] = ds_free[i];
|
||||
}
|
||||
|
||||
//-------------------- HostShare PCI Devices ------------------------------
|
||||
vector<xmlNodePtr> content;
|
||||
|
||||
get_nodes("/HOST/HOST_SHARE/PCI_DEVICES", content);
|
||||
host->get_nodes("/HOST/HOST_SHARE/PCI_DEVICES", content);
|
||||
|
||||
if( !content.empty())
|
||||
{
|
||||
pci.from_xml_node(content[0]);
|
||||
|
||||
free_nodes(content);
|
||||
host->free_nodes(content);
|
||||
|
||||
content.clear();
|
||||
}
|
||||
|
||||
//---------------------- HostShare NUMA Nodes ------------------------------
|
||||
host->get_nodes("/HOST/HOST_SHARE/NUMA_NODES/NODE", content);
|
||||
|
||||
if(!content.empty())
|
||||
{
|
||||
numa.from_xml_node(content);
|
||||
|
||||
host->free_nodes(content);
|
||||
|
||||
content.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool HostShareXML::test_capacity(HostShareCapacity &sr, string & error)
|
||||
{
|
||||
bool pci_fit = pci.test(sr.pci);
|
||||
bool numa_fit = numa.test(sr);
|
||||
bool cpu_fit = (max_cpu - cpu_usage ) >= sr.cpu;
|
||||
bool mem_fit = (max_mem - mem_usage ) >= sr.mem;
|
||||
|
||||
bool fits = cpu_fit && mem_fit && numa_fit && pci_fit;
|
||||
|
||||
if ( fits )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
if (!cpu_fit)
|
||||
{
|
||||
oss << "Not enough CPU capacity: " << sr.cpu << "/" << max_cpu - cpu_usage;
|
||||
}
|
||||
else if (!mem_fit)
|
||||
{
|
||||
oss << "Not enough memory: " << sr.mem << "/" << max_mem - mem_usage;
|
||||
}
|
||||
else if (!numa_fit)
|
||||
{
|
||||
oss << "Cannot allocate NUMA topology";
|
||||
}
|
||||
else if (!pci_fit)
|
||||
{
|
||||
oss << "Unavailable PCI device.";
|
||||
}
|
||||
|
||||
error = oss.str();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
ostream& operator<<(ostream& o, const HostShareXML& s)
|
||||
{
|
||||
o << "MEM_USAGE : " << s.mem_usage << endl;
|
||||
o << "CPU_USAGE : " << s.cpu_usage << endl;
|
||||
o << "MAX_MEM : " << s.max_mem << endl;
|
||||
o << "MAX_CPU : " << s.max_cpu << endl;
|
||||
o << "FREE_DISK : " << s.free_disk << endl;
|
||||
o << "RUNNING_VMS : " << s.running_vms << endl;
|
||||
o << endl;
|
||||
|
||||
o << right << setw(5) << "DSID" << " " << right << setw(15) << "FREE_MB"
|
||||
<< " " << endl << setw(30) << setfill('-') << "-" << setfill (' ') << endl;
|
||||
|
||||
for (auto it = s.ds_free_disk.begin() ; it != s.ds_free_disk.end() ; ++it)
|
||||
{
|
||||
o << right << setw(5) << it->first << " "
|
||||
<< right << setw(15)<< it->second<< " " << endl;
|
||||
}
|
||||
|
||||
o << endl << s.pci;
|
||||
|
||||
o << endl << s.numa;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void HostXML::init_attributes()
|
||||
{
|
||||
std::string public_cloud_st;
|
||||
|
||||
//--------------------- Init host attributes -------------------------------
|
||||
xpath(oid, "/HOST/ID", -1);
|
||||
xpath(cluster_id, "/HOST/CLUSTER_ID", -1);
|
||||
|
||||
xpath(public_cloud_st, "/HOST/TEMPLATE/PUBLIC_CLOUD", "");
|
||||
public_cloud = (one_util::toupper(public_cloud_st) == "YES");
|
||||
|
||||
share.init_attributes(this);
|
||||
|
||||
//-------------------- Init search xpath routes ---------------------------
|
||||
ObjectXML::paths = host_paths;
|
||||
ObjectXML::num_paths = host_num_paths;
|
||||
@ -92,107 +185,12 @@ void HostXML::init_attributes()
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool HostXML::test_capacity(long long cpu, long long mem,
|
||||
vector<VectorAttribute *>& p, string & error)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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";
|
||||
|
||||
error = oss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Unavailable PCI device.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pci_fits )
|
||||
{
|
||||
error = "Not enough capacity.";
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Unavailable PCI device.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fits;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool HostXML::test_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
if (ds_free_disk.count(dsid) == 0)
|
||||
{
|
||||
ds_free_disk[dsid] = free_disk;
|
||||
}
|
||||
|
||||
return (vm_disk_mb < ds_free_disk[dsid]);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void HostXML::add_ds_capacity(int dsid, long long vm_disk_mb)
|
||||
{
|
||||
if (ds_free_disk.count(dsid) == 0)
|
||||
{
|
||||
ds_free_disk[dsid] = free_disk;
|
||||
}
|
||||
|
||||
ds_free_disk[dsid] -= 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 << "ID : " << p.oid << endl;
|
||||
o << "CLUSTER_ID : " << p.cluster_id << 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;
|
||||
o << p.share;
|
||||
|
||||
return o;
|
||||
}
|
||||
@ -210,3 +208,4 @@ void HostXML::get_permissions(PoolObjectAuth& auth)
|
||||
auth.cids = cids;
|
||||
auth.obj_type = PoolObjectSQL::HOST;
|
||||
}
|
||||
|
||||
|
@ -330,10 +330,7 @@ static void schecule_affined_set(const std::set<int>& vms,
|
||||
|
||||
for ( ++it ; it != vms.end() ; ++it )
|
||||
{
|
||||
float cpu;
|
||||
int memory;
|
||||
|
||||
long long disk;
|
||||
HostShareCapacity sr;
|
||||
|
||||
VirtualMachineXML * tmp = vmpool->get(*it);
|
||||
|
||||
@ -342,9 +339,9 @@ static void schecule_affined_set(const std::set<int>& vms,
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp->reset_requirements(cpu, memory, disk);
|
||||
tmp->reset_capacity(sr);
|
||||
|
||||
vm->add_requirements(cpu, memory, disk);
|
||||
vm->add_capacity(sr);
|
||||
vm->add_requirements(tmp->get_requirements());
|
||||
vm->add_affined(*it);
|
||||
|
||||
|
@ -56,9 +56,7 @@ int VirtualMachinePoolXML::set_up()
|
||||
|
||||
for (it = objects.begin() ; it != objects.end() ; ++it)
|
||||
{
|
||||
int cpu, mem;
|
||||
long long disk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
string action = "DEPLOY";
|
||||
|
||||
@ -66,7 +64,7 @@ int VirtualMachinePoolXML::set_up()
|
||||
|
||||
vm = static_cast<VirtualMachineXML *>(it->second);
|
||||
|
||||
vm->get_requirements(cpu, mem, disk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
if (vm->is_resched())
|
||||
{
|
||||
@ -79,10 +77,10 @@ int VirtualMachinePoolXML::set_up()
|
||||
|
||||
oss << right << setw(8) << action << " "
|
||||
<< right << setw(8) << it->first << " "
|
||||
<< right << setw(4) << cpu << " "
|
||||
<< right << setw(11) << mem << " "
|
||||
<< right << setw(3) << pci.size() << " "
|
||||
<< right << setw(11) << disk << " ";
|
||||
<< right << setw(4) << sr.cpu << " "
|
||||
<< right << setw(11) << sr.mem << " "
|
||||
<< right << setw(3) << sr.pci.size() << " "
|
||||
<< right << setw(11) << sr.disk << " ";
|
||||
|
||||
map<int,long long> ds_usage = vm->get_storage_usage();
|
||||
map<int,long long>::const_iterator ds_it;
|
||||
@ -120,7 +118,7 @@ void VirtualMachinePoolXML::add_object(xmlNodePtr node)
|
||||
|
||||
VirtualMachineXML* vm = new VirtualMachineXML(node);
|
||||
|
||||
objects.insert(pair<int,ObjectXML*>(vm->get_oid(),vm));
|
||||
objects.insert(pair<int,ObjectXML*>(vm->get_oid(), vm));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -130,7 +128,7 @@ int VirtualMachinePoolXML::load_info(xmlrpc_c::value &result)
|
||||
{
|
||||
try
|
||||
{
|
||||
client->call("one.vmpool.info", "iiii", &result, -2, -1, -1, -1);
|
||||
client->call("one.vmpool.infoextended", "iiii", &result, -2, -1, -1, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,28 +24,59 @@
|
||||
#include "History.h"
|
||||
#include "RankScheduler.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/* INITIALIZE VM object attributes from its XML representation */
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
void VirtualMachineXML::init_attributes()
|
||||
{
|
||||
vector<xmlNodePtr> nodes;
|
||||
std::vector<xmlNodePtr> nodes;
|
||||
std::vector<VectorAttribute*> attrs;
|
||||
|
||||
int rc;
|
||||
int action;
|
||||
int tmp;
|
||||
|
||||
string automatic_requirements;
|
||||
string automatic_ds_requirements;
|
||||
string automatic_nic_requirements;
|
||||
std::string automatic_requirements;
|
||||
std::string automatic_ds_requirements;
|
||||
std::string automatic_nic_requirements;
|
||||
|
||||
/**************************************************************************/
|
||||
/* VM attributes and flags */
|
||||
/**************************************************************************/
|
||||
xpath(oid, "/VM/ID", -1);
|
||||
xpath(uid, "/VM/UID", -1);
|
||||
xpath(gid, "/VM/GID", -1);
|
||||
|
||||
xpath(state, "/VM/STATE", -1);
|
||||
xpath(tmp, "/VM/STATE", -1);
|
||||
active = tmp == 3;
|
||||
|
||||
xpath(tmp, "/VM/RESCHED", 0);
|
||||
resched = tmp == 1;
|
||||
|
||||
xpath(action, "/VM/HISTORY_RECORDS/HISTORY/ACTION", -1);
|
||||
resume = (action == History::STOP_ACTION || action == History::UNDEPLOY_ACTION
|
||||
|| action == History::UNDEPLOY_HARD_ACTION );
|
||||
|
||||
xpath(hid, "/VM/HISTORY_RECORDS/HISTORY/HID", -1);
|
||||
xpath(dsid, "/VM/HISTORY_RECORDS/HISTORY/DS_ID", -1);
|
||||
|
||||
xpath(stime, "/VM/STIME", (time_t) 0);
|
||||
|
||||
/**************************************************************************/
|
||||
/* VM Capacity memory, cpu and disk (system ds storage) */
|
||||
/**************************************************************************/
|
||||
xpath<long int>(memory, "/VM/TEMPLATE/MEMORY", 0);
|
||||
|
||||
xpath<float>(cpu, "/VM/TEMPLATE/CPU", 0);
|
||||
|
||||
// ------------------------ RANK & DS_RANK ---------------------------------
|
||||
|
||||
/**************************************************************************/
|
||||
/* Scheduling rank expresions for: */
|
||||
/* - host */
|
||||
/* - datastore */
|
||||
/**************************************************************************/
|
||||
rc = xpath(rank, "/VM/USER_TEMPLATE/SCHED_RANK", "");
|
||||
|
||||
if (rc != 0)
|
||||
@ -56,8 +87,15 @@ void VirtualMachineXML::init_attributes()
|
||||
|
||||
xpath(ds_rank, "/VM/USER_TEMPLATE/SCHED_DS_RANK", "");
|
||||
|
||||
// ------------------- HOST REQUIREMENTS -----------------------------------
|
||||
|
||||
/**************************************************************************/
|
||||
/* Scheduling requirements for: */
|
||||
/* - host */
|
||||
/* - datastore */
|
||||
/* - network */
|
||||
/**************************************************************************/
|
||||
// ---------------------------------------------------------------------- //
|
||||
// Host requirements //
|
||||
// ---------------------------------------------------------------------- //
|
||||
xpath(automatic_requirements, "/VM/TEMPLATE/AUTOMATIC_REQUIREMENTS", "");
|
||||
|
||||
rc = xpath(requirements, "/VM/USER_TEMPLATE/SCHED_REQUIREMENTS", "");
|
||||
@ -78,9 +116,11 @@ void VirtualMachineXML::init_attributes()
|
||||
requirements = automatic_requirements;
|
||||
}
|
||||
|
||||
// ------------------- DS REQUIREMENTS -------------------------------------
|
||||
|
||||
xpath(automatic_ds_requirements, "/VM/TEMPLATE/AUTOMATIC_DS_REQUIREMENTS", "");
|
||||
// ---------------------------------------------------------------------- //
|
||||
// Datastore requirements //
|
||||
// ---------------------------------------------------------------------- //
|
||||
xpath(automatic_ds_requirements, "/VM/TEMPLATE/AUTOMATIC_DS_REQUIREMENTS",
|
||||
"");
|
||||
|
||||
rc = xpath(ds_requirements, "/VM/USER_TEMPLATE/SCHED_DS_REQUIREMENTS", "");
|
||||
|
||||
@ -100,17 +140,17 @@ void VirtualMachineXML::init_attributes()
|
||||
ds_requirements = automatic_ds_requirements;
|
||||
}
|
||||
|
||||
// ------------------- NIC REQUIREMENTS -------------------------------------
|
||||
|
||||
xpath(automatic_nic_requirements, "/VM/TEMPLATE/AUTOMATIC_NIC_REQUIREMENTS", "");
|
||||
// ---------------------------------------------------------------------- //
|
||||
// Network requirements & rank //
|
||||
// ---------------------------------------------------------------------- //
|
||||
xpath(automatic_nic_requirements, "/VM/TEMPLATE/AUTOMATIC_NIC_REQUIREMENTS",
|
||||
"");
|
||||
|
||||
if (get_nodes("/VM/TEMPLATE/NIC", nodes) > 0)
|
||||
{
|
||||
std::string net_mode;
|
||||
|
||||
vector<xmlNodePtr>::iterator it_nodes;
|
||||
|
||||
for (it_nodes = nodes.begin(); it_nodes != nodes.end(); ++it_nodes)
|
||||
for (auto it_nodes = nodes.begin(); it_nodes != nodes.end(); ++it_nodes)
|
||||
{
|
||||
VirtualMachineTemplate * nic_template = new VirtualMachineTemplate;
|
||||
|
||||
@ -119,37 +159,39 @@ void VirtualMachineXML::init_attributes()
|
||||
bool rc = nic_template->get("NETWORK_MODE", net_mode);
|
||||
one_util::toupper(net_mode);
|
||||
|
||||
if ( rc && net_mode == "AUTO" )
|
||||
if ( !rc || net_mode != "AUTO" )
|
||||
{
|
||||
std::string requirements, rank;
|
||||
int nic_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
nic_template->get("NIC_ID", nic_id);
|
||||
std::string reqs, rank;
|
||||
int nic_id;
|
||||
|
||||
nics_ids_auto.insert(nic_id);
|
||||
nic_template->get("NIC_ID", nic_id);
|
||||
|
||||
VirtualMachineNicXML * the_nic = new VirtualMachineNicXML();
|
||||
nics_ids_auto.insert(nic_id);
|
||||
|
||||
nics.insert(make_pair(nic_id, the_nic));
|
||||
VirtualMachineNicXML * the_nic = new VirtualMachineNicXML();
|
||||
|
||||
if ( nic_template->get("SCHED_REQUIREMENTS", requirements) )
|
||||
nics.insert(make_pair(nic_id, the_nic));
|
||||
|
||||
if ( nic_template->get("SCHED_REQUIREMENTS", reqs) )
|
||||
{
|
||||
if ( !automatic_nic_requirements.empty() )
|
||||
{
|
||||
if ( !automatic_nic_requirements.empty() )
|
||||
{
|
||||
ostringstream oss;
|
||||
ostringstream oss;
|
||||
|
||||
oss << automatic_nic_requirements << " & ( " << requirements << " )";
|
||||
oss << automatic_nic_requirements <<" & ( " << reqs << " )";
|
||||
|
||||
requirements = oss.str();
|
||||
}
|
||||
|
||||
the_nic->set_requirements(requirements);
|
||||
reqs = oss.str();
|
||||
}
|
||||
|
||||
if ( nic_template->get("SCHED_RANK", rank) )
|
||||
{
|
||||
the_nic->set_rank(rank);
|
||||
}
|
||||
the_nic->set_requirements(reqs);
|
||||
}
|
||||
|
||||
if ( nic_template->get("SCHED_RANK", rank) )
|
||||
{
|
||||
the_nic->set_rank(rank);
|
||||
}
|
||||
|
||||
delete nic_template;
|
||||
@ -160,21 +202,9 @@ void VirtualMachineXML::init_attributes()
|
||||
|
||||
nodes.clear();
|
||||
|
||||
// ---------------- HISTORY HID, DSID, RESCHED & TEMPLATE ------------------
|
||||
|
||||
xpath(hid, "/VM/HISTORY_RECORDS/HISTORY/HID", -1);
|
||||
xpath(dsid, "/VM/HISTORY_RECORDS/HISTORY/DS_ID", -1);
|
||||
|
||||
xpath(resched, "/VM/RESCHED", 0);
|
||||
|
||||
xpath(action, "/VM/HISTORY_RECORDS/HISTORY/ACTION", -1);
|
||||
|
||||
xpath(stime, "/VM/STIME", (time_t) 0);
|
||||
|
||||
resume = (action == History::STOP_ACTION ||
|
||||
action == History::UNDEPLOY_ACTION ||
|
||||
action == History::UNDEPLOY_HARD_ACTION );
|
||||
|
||||
/**************************************************************************/
|
||||
/* Template, user template, history information and rescheduling flag */
|
||||
/**************************************************************************/
|
||||
if (get_nodes("/VM/TEMPLATE", nodes) > 0)
|
||||
{
|
||||
vm_template = new VirtualMachineTemplate;
|
||||
@ -203,17 +233,6 @@ void VirtualMachineXML::init_attributes()
|
||||
user_template = 0;
|
||||
}
|
||||
|
||||
if (vm_template != 0)
|
||||
{
|
||||
init_storage_usage();
|
||||
}
|
||||
else
|
||||
{
|
||||
system_ds_usage = 0;
|
||||
}
|
||||
|
||||
vector<VectorAttribute*> attrs;
|
||||
|
||||
public_cloud = (user_template->get("PUBLIC_CLOUD", attrs) > 0);
|
||||
|
||||
if (public_cloud == false)
|
||||
@ -223,124 +242,22 @@ void VirtualMachineXML::init_attributes()
|
||||
}
|
||||
|
||||
only_public_cloud = false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
ostream& operator<<(ostream& os, VirtualMachineXML& vm)
|
||||
{
|
||||
const vector<Resource *> resources = vm.match_hosts.get_resources();
|
||||
|
||||
vector<Resource *>::const_reverse_iterator i;
|
||||
|
||||
if (resources.empty())
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
os << "Virtual Machine: " << vm.oid << endl << endl;
|
||||
|
||||
os << "\tPRI\tID - HOSTS"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
for (i = resources.rbegin(); i != resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
|
||||
os << "\tPRI\tID - DATASTORES"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
const vector<Resource *> ds_resources = vm.match_datastores.get_resources();
|
||||
|
||||
for (i = ds_resources.rbegin(); i != ds_resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
|
||||
set<int> nics_ids = vm.get_nics_ids();
|
||||
|
||||
for (set<int>::iterator it = nics_ids.begin(); it != nics_ids.end(); it++)
|
||||
{
|
||||
os << "\tNIC_ID: "<< *it << endl
|
||||
<< "\t-----------------------------------" << endl;
|
||||
os << "\tPRI\tID - NETWORKS"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
const vector<Resource *> net_resources = vm.nics[*it]->get_match_networks();
|
||||
|
||||
for (i = net_resources.rbegin(); i != net_resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
}
|
||||
|
||||
return os;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::add_requirements(float c, long int m, long long d)
|
||||
{
|
||||
cpu += c;
|
||||
memory += m;
|
||||
system_ds_usage += d;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::reset_requirements(float& c, int& m, long long& d)
|
||||
{
|
||||
c = cpu;
|
||||
m = memory;
|
||||
d = system_ds_usage;
|
||||
|
||||
cpu = 0;
|
||||
memory = 0;
|
||||
system_ds_usage = 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::get_requirements (int& cpu, int& memory,
|
||||
long long& disk, vector<VectorAttribute *> &pci)
|
||||
{
|
||||
pci.clear();
|
||||
|
||||
if (vm_template != 0)
|
||||
{
|
||||
vm_template->get("PCI", pci);
|
||||
init_storage_usage();
|
||||
}
|
||||
|
||||
if (this->memory == 0 || this->cpu == 0)
|
||||
else
|
||||
{
|
||||
cpu = 0;
|
||||
memory = 0;
|
||||
disk = 0;
|
||||
|
||||
return;
|
||||
system_ds_usage = 0;
|
||||
}
|
||||
|
||||
cpu = (int) (this->cpu * 100);//now in 100%
|
||||
memory = this->memory * 1024; //now in Kilobytes
|
||||
disk = this->system_ds_usage; // MB
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
// TODO: use VirtualMachine::isVolatile(disk)
|
||||
bool isVolatile(const VectorAttribute * disk)
|
||||
static bool isVolatile(const VectorAttribute * disk)
|
||||
{
|
||||
string type = disk->vector_value("TYPE");
|
||||
|
||||
@ -349,10 +266,7 @@ bool isVolatile(const VectorAttribute * disk)
|
||||
return ( type == "SWAP" || type == "FS");
|
||||
}
|
||||
|
||||
map<int,long long> VirtualMachineXML::get_storage_usage()
|
||||
{
|
||||
return ds_usage;
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::init_storage_usage()
|
||||
{
|
||||
@ -444,6 +358,243 @@ void VirtualMachineXML::init_storage_usage()
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/* VM requirements and capacity interface */
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
void VirtualMachineXML::add_requirements(const string& reqs)
|
||||
{
|
||||
if ( reqs.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ( requirements.empty() )
|
||||
{
|
||||
requirements = reqs;
|
||||
}
|
||||
else
|
||||
{
|
||||
requirements += " & (" + reqs + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::get_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
sr.vmid = oid;
|
||||
|
||||
sr.pci.clear();
|
||||
|
||||
if (vm_template != 0)
|
||||
{
|
||||
vm_template->get("PCI", sr.pci);
|
||||
|
||||
vm_template->get("NUMA_NODE", sr.nodes);
|
||||
|
||||
sr.topology = vm_template->get("TOPOLOGY");
|
||||
}
|
||||
|
||||
if ( memory == 0 || cpu == 0 )
|
||||
{
|
||||
sr.cpu = 0;
|
||||
sr.mem = 0;
|
||||
sr.disk = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sr.cpu = (int) (cpu * 100); //100%
|
||||
sr.mem = memory * 1024; //Kilobytes
|
||||
sr.disk = system_ds_usage; //MB
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::add_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
cpu += sr.cpu;
|
||||
memory += sr.mem;
|
||||
system_ds_usage += sr.disk;
|
||||
|
||||
vm_template->set(sr.nodes);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::reset_capacity(HostShareCapacity &sr)
|
||||
{
|
||||
std::vector<VectorAttribute *> numa_nodes;
|
||||
|
||||
sr.cpu = cpu;
|
||||
sr.mem = memory;
|
||||
sr.disk = system_ds_usage;
|
||||
|
||||
if ( vm_template != 0 )
|
||||
{
|
||||
vm_template->remove("NUMA_NODE", sr.nodes);
|
||||
}
|
||||
|
||||
cpu = 0;
|
||||
memory = 0;
|
||||
system_ds_usage = 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachineXML::test_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool, string & error_msg) const
|
||||
{
|
||||
for (auto ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it)
|
||||
{
|
||||
DatastoreXML* ds = img_dspool->get(ds_it->first);
|
||||
|
||||
if (ds == 0 || !ds->test_capacity(ds_it->second))
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << "Image Datastore " << ds->get_oid()
|
||||
<< " does not have enough capacity";
|
||||
|
||||
error_msg = oss.str();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::add_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool)
|
||||
{
|
||||
for (auto ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it)
|
||||
{
|
||||
DatastoreXML *ds = img_dspool->get(ds_it->first);
|
||||
|
||||
if (ds == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ds->add_capacity(ds_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Functions to schedule network interfaces (NIC)
|
||||
//******************************************************************************
|
||||
|
||||
VirtualMachineNicXML * VirtualMachineXML::get_nic(int nic_id)
|
||||
{
|
||||
VirtualMachineNicXML * n = 0;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
n = it->second;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
const string& VirtualMachineXML::get_nic_rank(int nic_id)
|
||||
{
|
||||
static std::string es;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
return it->second->get_rank();
|
||||
}
|
||||
|
||||
return es;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
const string& VirtualMachineXML::get_nic_requirements(int nic_id)
|
||||
{
|
||||
static std::string es;
|
||||
|
||||
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
|
||||
|
||||
if ( it != nics.end() )
|
||||
{
|
||||
return it->second->get_requirements();
|
||||
}
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Logging
|
||||
//******************************************************************************
|
||||
|
||||
ostream& operator<<(ostream& os, VirtualMachineXML& vm)
|
||||
{
|
||||
const vector<Resource *> resources = vm.match_hosts.get_resources();
|
||||
|
||||
vector<Resource *>::const_reverse_iterator i;
|
||||
|
||||
if (resources.empty())
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
os << "Virtual Machine: " << vm.oid << endl << endl;
|
||||
|
||||
os << "\tPRI\tID - HOSTS"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
for (i = resources.rbegin(); i != resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
|
||||
os << "\tPRI\tID - DATASTORES"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
const vector<Resource *> ds_resources = vm.match_datastores.get_resources();
|
||||
|
||||
for (i = ds_resources.rbegin(); i != ds_resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
|
||||
set<int> nics_ids = vm.get_nics_ids();
|
||||
|
||||
for (set<int>::iterator it = nics_ids.begin(); it != nics_ids.end(); it++)
|
||||
{
|
||||
os << "\tNIC_ID: "<< *it << endl
|
||||
<< "\t-----------------------------------" << endl;
|
||||
os << "\tPRI\tID - NETWORKS"<< endl
|
||||
<< "\t------------------------" << endl;
|
||||
|
||||
const vector<Resource *> net_resources = vm.nics[*it]->get_match_networks();
|
||||
|
||||
for (i = net_resources.rbegin(); i != net_resources.rend() ; i++)
|
||||
{
|
||||
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
}
|
||||
|
||||
return os;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -517,79 +668,3 @@ int VirtualMachineXML::parse_action_name(string& action_st)
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachineXML::test_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool, string & error_msg) const
|
||||
{
|
||||
map<int,long long>::const_iterator ds_it;
|
||||
DatastoreXML* ds;
|
||||
|
||||
for (ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it)
|
||||
{
|
||||
ds = img_dspool->get(ds_it->first);
|
||||
|
||||
if (ds == 0 || !ds->test_capacity(ds_it->second))
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << "Image Datastore " << ds->get_oid()
|
||||
<< " does not have enough capacity";
|
||||
|
||||
error_msg = oss.str();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::add_image_datastore_capacity(
|
||||
ImageDatastorePoolXML * img_dspool)
|
||||
{
|
||||
map<int,long long>::const_iterator ds_it;
|
||||
|
||||
DatastoreXML *ds;
|
||||
|
||||
for (ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it)
|
||||
{
|
||||
ds = img_dspool->get(ds_it->first);
|
||||
|
||||
if (ds == 0) //Should never reach here
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ds->add_capacity(ds_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachineXML::set_only_public_cloud()
|
||||
{
|
||||
only_public_cloud = true;
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
oss << "VM " << oid << ": Local Datastores do not have enough capacity. "
|
||||
<< "This VM can be only deployed in a Public Cloud Host.";
|
||||
|
||||
NebulaLog::log("SCHED",Log::INFO,oss);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachineXML::is_only_public_cloud() const
|
||||
{
|
||||
return only_public_cloud;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -510,9 +510,7 @@ int Scheduler::set_up_pools()
|
||||
* @param acl pool
|
||||
* @param users the user pool
|
||||
* @param vm the virtual machine
|
||||
* @param vm_memory vm requirement
|
||||
* @param vm_cpu vm requirement
|
||||
* @param vm_pci vm requirement
|
||||
* @param sr share capacity request
|
||||
* @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
|
||||
@ -522,8 +520,8 @@ int Scheduler::set_up_pools()
|
||||
* @return true for a positive match
|
||||
*/
|
||||
static bool match_host(AclXML * acls, UserPoolXML * upool, VirtualMachineXML* vm,
|
||||
int vmem, int vcpu, vector<VectorAttribute *>& vpci, HostXML * host,
|
||||
int &n_auth, int& n_error, int &n_fits, int &n_matched, string &error)
|
||||
HostShareCapacity &sr, HostXML * host, int &n_auth, int& n_error, int &n_fits,
|
||||
int &n_matched, string &error)
|
||||
{
|
||||
// -------------------------------------------------------------------------
|
||||
// Filter current Hosts for resched VMs
|
||||
@ -576,7 +574,7 @@ static bool match_host(AclXML * acls, UserPoolXML * upool, VirtualMachineXML* vm
|
||||
// -------------------------------------------------------------------------
|
||||
// Check host capacity
|
||||
// -------------------------------------------------------------------------
|
||||
if (host->test_capacity(vcpu, vmem, vpci, error) != true)
|
||||
if (host->test_capacity(sr, error) != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -846,10 +844,7 @@ void Scheduler::match_schedule()
|
||||
{
|
||||
VirtualMachineXML * vm;
|
||||
|
||||
int vm_memory;
|
||||
int vm_cpu;
|
||||
long long vm_disk;
|
||||
vector<VectorAttribute *> vm_pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
int n_resources;
|
||||
int n_matched;
|
||||
@ -888,7 +883,7 @@ void Scheduler::match_schedule()
|
||||
{
|
||||
vm = static_cast<VirtualMachineXML*>(vm_it->second);
|
||||
|
||||
vm->get_requirements(vm_cpu, vm_memory, vm_disk, vm_pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
n_resources = 0;
|
||||
n_fits = 0;
|
||||
@ -928,8 +923,8 @@ void Scheduler::match_schedule()
|
||||
{
|
||||
host = static_cast<HostXML *>(obj_it->second);
|
||||
|
||||
if (match_host(acls, upool, vm, vm_memory, vm_cpu, vm_pci, host,
|
||||
n_auth, n_error, n_fits, n_matched, m_error))
|
||||
if (match_host(acls, upool, vm, sr, host, n_auth, n_error, n_fits,
|
||||
n_matched, m_error))
|
||||
{
|
||||
vm->add_match_host(host->get_hid());
|
||||
|
||||
@ -1035,7 +1030,7 @@ void Scheduler::match_schedule()
|
||||
{
|
||||
ds = static_cast<DatastoreXML *>(obj_it->second);
|
||||
|
||||
if (match_system_ds(acls, upool, vm, vm_disk, ds, n_auth, n_error,
|
||||
if (match_system_ds(acls, upool, vm, sr.disk, ds, n_auth, n_error,
|
||||
n_fits, n_matched, m_error))
|
||||
{
|
||||
vm->add_match_datastore(ds->get_oid());
|
||||
@ -1301,9 +1296,7 @@ void Scheduler::dispatch()
|
||||
ostringstream dss;
|
||||
string error;
|
||||
|
||||
int cpu, mem;
|
||||
long long dsk;
|
||||
vector<VectorAttribute *> pci;
|
||||
HostShareCapacity sr;
|
||||
|
||||
int hid, dsid, cid, netid;
|
||||
|
||||
@ -1369,7 +1362,7 @@ void Scheduler::dispatch()
|
||||
}
|
||||
}
|
||||
|
||||
vm->get_requirements(cpu, mem, dsk, pci);
|
||||
vm->get_capacity(sr);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Get the highest ranked host and best System DS for it
|
||||
@ -1415,7 +1408,7 @@ void Scheduler::dispatch()
|
||||
//------------------------------------------------------------------
|
||||
// Test host capacity
|
||||
//------------------------------------------------------------------
|
||||
if (host->test_capacity(cpu, mem, pci) != true)
|
||||
if (host->test_capacity(sr, error) != true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1490,12 +1483,12 @@ void Scheduler::dispatch()
|
||||
}
|
||||
else
|
||||
{
|
||||
ds_capacity = ds->test_capacity(dsk);
|
||||
ds_capacity = ds->test_capacity(sr.disk);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ds_capacity = host->test_ds_capacity(ds->get_oid(), dsk);
|
||||
ds_capacity = host->test_ds_capacity(ds->get_oid(), sr.disk);
|
||||
}
|
||||
|
||||
if (!ds_capacity)
|
||||
@ -1642,12 +1635,12 @@ void Scheduler::dispatch()
|
||||
{
|
||||
if (!vm->is_resched() && !vm->is_resume())
|
||||
{
|
||||
ds->add_capacity(dsk);
|
||||
ds->add_capacity(sr.disk);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
host->add_ds_capacity(ds->get_oid(), dsk);
|
||||
host->add_ds_capacity(ds->get_oid(), sr.disk);
|
||||
}
|
||||
|
||||
// ---------- Add image DS usage (i.e. clone = self) ----------
|
||||
@ -1683,7 +1676,7 @@ void Scheduler::dispatch()
|
||||
//------------------------------------------------------------------
|
||||
// Update usage and statistics counters
|
||||
//------------------------------------------------------------------
|
||||
host->add_capacity(vm->get_oid(), cpu, mem, pci);
|
||||
host->add_capacity(sr);
|
||||
|
||||
dispatched_vms++;
|
||||
|
||||
|
@ -103,25 +103,25 @@ int VirtualMachine::vm_state_from_str(string& st, VmState& state)
|
||||
if ( st == "INIT" ) {
|
||||
state = INIT;
|
||||
} else if ( st == "PENDING" ) {
|
||||
state = PENDING;
|
||||
state = PENDING;
|
||||
} else if ( st == "HOLD" ) {
|
||||
state = HOLD;
|
||||
state = HOLD;
|
||||
} else if ( st == "ACTIVE" ) {
|
||||
state = ACTIVE;
|
||||
state = ACTIVE;
|
||||
} else if ( st == "STOPPED" ) {
|
||||
state = STOPPED;
|
||||
state = STOPPED;
|
||||
} else if ( st == "SUSPENDED" ) {
|
||||
state = SUSPENDED;
|
||||
state = SUSPENDED;
|
||||
} else if ( st == "DONE" ) {
|
||||
state = DONE;
|
||||
state = DONE;
|
||||
} else if ( st == "POWEROFF" ) {
|
||||
state = POWEROFF;
|
||||
state = POWEROFF;
|
||||
} else if ( st == "UNDEPLOYED" ) {
|
||||
state = UNDEPLOYED;
|
||||
state = UNDEPLOYED;
|
||||
} else if ( st == "CLONING" ) {
|
||||
state = CLONING;
|
||||
state = CLONING;
|
||||
} else if ( st == "CLONING_FAILURE" ) {
|
||||
state = CLONING_FAILURE;
|
||||
state = CLONING_FAILURE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@ -136,27 +136,27 @@ string& VirtualMachine::vm_state_to_str(string& st, VmState state)
|
||||
switch (state)
|
||||
{
|
||||
case INIT:
|
||||
st = "INIT"; break;
|
||||
st = "INIT"; break;
|
||||
case PENDING:
|
||||
st = "PENDING"; break;
|
||||
st = "PENDING"; break;
|
||||
case HOLD:
|
||||
st = "HOLD"; break;
|
||||
st = "HOLD"; break;
|
||||
case ACTIVE:
|
||||
st = "ACTIVE"; break;
|
||||
st = "ACTIVE"; break;
|
||||
case STOPPED:
|
||||
st = "STOPPED"; break;
|
||||
st = "STOPPED"; break;
|
||||
case SUSPENDED:
|
||||
st = "SUSPENDED"; break;
|
||||
st = "SUSPENDED"; break;
|
||||
case DONE:
|
||||
st = "DONE"; break;
|
||||
st = "DONE"; break;
|
||||
case POWEROFF:
|
||||
st = "POWEROFF"; break;
|
||||
st = "POWEROFF"; break;
|
||||
case UNDEPLOYED:
|
||||
st = "UNDEPLOYED"; break;
|
||||
st = "UNDEPLOYED"; break;
|
||||
case CLONING:
|
||||
st = "CLONING"; break;
|
||||
st = "CLONING"; break;
|
||||
case CLONING_FAILURE:
|
||||
st = "CLONING_FAILURE"; break;
|
||||
st = "CLONING_FAILURE"; break;
|
||||
}
|
||||
|
||||
return st;
|
||||
@ -180,119 +180,119 @@ int VirtualMachine::lcm_state_from_str(string& st, LcmState& state)
|
||||
} else if ( st == "MIGRATE") {
|
||||
state = MIGRATE;
|
||||
} else if ( st == "SAVE_STOP") {
|
||||
state = SAVE_STOP;
|
||||
state = SAVE_STOP;
|
||||
} else if ( st == "SAVE_SUSPEND") {
|
||||
state = SAVE_SUSPEND;
|
||||
state = SAVE_SUSPEND;
|
||||
} else if ( st == "SAVE_MIGRATE") {
|
||||
state = SAVE_MIGRATE;
|
||||
state = SAVE_MIGRATE;
|
||||
} else if ( st == "PROLOG_MIGRATE") {
|
||||
state = PROLOG_MIGRATE;
|
||||
state = PROLOG_MIGRATE;
|
||||
} else if ( st == "PROLOG_RESUME") {
|
||||
state = PROLOG_RESUME;
|
||||
state = PROLOG_RESUME;
|
||||
} else if ( st == "EPILOG_STOP") {
|
||||
state = EPILOG_STOP;
|
||||
state = EPILOG_STOP;
|
||||
} else if ( st == "EPILOG") {
|
||||
state = EPILOG;
|
||||
state = EPILOG;
|
||||
} else if ( st == "SHUTDOWN") {
|
||||
state = SHUTDOWN;
|
||||
state = SHUTDOWN;
|
||||
} else if ( st == "CLEANUP_RESUBMIT") {
|
||||
state = CLEANUP_RESUBMIT;
|
||||
state = CLEANUP_RESUBMIT;
|
||||
} else if ( st == "UNKNOWN") {
|
||||
state = UNKNOWN;
|
||||
state = UNKNOWN;
|
||||
} else if ( st == "HOTPLUG") {
|
||||
state = HOTPLUG;
|
||||
state = HOTPLUG;
|
||||
} else if ( st == "SHUTDOWN_POWEROFF") {
|
||||
state = SHUTDOWN_POWEROFF;
|
||||
state = SHUTDOWN_POWEROFF;
|
||||
} else if ( st == "BOOT_UNKNOWN") {
|
||||
state = BOOT_UNKNOWN;
|
||||
state = BOOT_UNKNOWN;
|
||||
} else if ( st == "BOOT_POWEROFF") {
|
||||
state = BOOT_POWEROFF;
|
||||
state = BOOT_POWEROFF;
|
||||
} else if ( st == "BOOT_SUSPENDED") {
|
||||
state = BOOT_SUSPENDED;
|
||||
state = BOOT_SUSPENDED;
|
||||
} else if ( st == "BOOT_STOPPED") {
|
||||
state = BOOT_STOPPED;
|
||||
state = BOOT_STOPPED;
|
||||
} else if ( st == "CLEANUP_DELETE") {
|
||||
state = CLEANUP_DELETE;
|
||||
state = CLEANUP_DELETE;
|
||||
} else if ( st == "HOTPLUG_SNAPSHOT") {
|
||||
state = HOTPLUG_SNAPSHOT;
|
||||
state = HOTPLUG_SNAPSHOT;
|
||||
} else if ( st == "HOTPLUG_NIC") {
|
||||
state = HOTPLUG_NIC;
|
||||
state = HOTPLUG_NIC;
|
||||
} else if ( st == "HOTPLUG_SAVEAS") {
|
||||
state = HOTPLUG_SAVEAS;
|
||||
state = HOTPLUG_SAVEAS;
|
||||
} else if ( st == "HOTPLUG_SAVEAS_POWEROFF") {
|
||||
state = HOTPLUG_SAVEAS_POWEROFF;
|
||||
state = HOTPLUG_SAVEAS_POWEROFF;
|
||||
} else if ( st == "HOTPLUG_SAVEAS_SUSPENDED") {
|
||||
state = HOTPLUG_SAVEAS_SUSPENDED;
|
||||
state = HOTPLUG_SAVEAS_SUSPENDED;
|
||||
} else if ( st == "SHUTDOWN_UNDEPLOY") {
|
||||
state = SHUTDOWN_UNDEPLOY;
|
||||
state = SHUTDOWN_UNDEPLOY;
|
||||
} else if ( st == "EPILOG_UNDEPLOY") {
|
||||
state = EPILOG_UNDEPLOY;
|
||||
state = EPILOG_UNDEPLOY;
|
||||
} else if ( st == "PROLOG_UNDEPLOY") {
|
||||
state = PROLOG_UNDEPLOY;
|
||||
state = PROLOG_UNDEPLOY;
|
||||
} else if ( st == "BOOT_UNDEPLOY") {
|
||||
state = BOOT_UNDEPLOY;
|
||||
state = BOOT_UNDEPLOY;
|
||||
} else if ( st == "HOTPLUG_PROLOG_POWEROFF") {
|
||||
state = HOTPLUG_PROLOG_POWEROFF;
|
||||
state = HOTPLUG_PROLOG_POWEROFF;
|
||||
} else if ( st == "HOTPLUG_EPILOG_POWEROFF") {
|
||||
state = HOTPLUG_EPILOG_POWEROFF;
|
||||
state = HOTPLUG_EPILOG_POWEROFF;
|
||||
} else if ( st == "BOOT_MIGRATE") {
|
||||
state = BOOT_MIGRATE;
|
||||
state = BOOT_MIGRATE;
|
||||
} else if ( st == "BOOT_FAILURE") {
|
||||
state = BOOT_FAILURE;
|
||||
state = BOOT_FAILURE;
|
||||
} else if ( st == "BOOT_MIGRATE_FAILURE") {
|
||||
state = BOOT_MIGRATE_FAILURE;
|
||||
state = BOOT_MIGRATE_FAILURE;
|
||||
} else if ( st == "PROLOG_MIGRATE_FAILURE") {
|
||||
state = PROLOG_MIGRATE_FAILURE;
|
||||
state = PROLOG_MIGRATE_FAILURE;
|
||||
} else if ( st == "PROLOG_FAILURE") {
|
||||
state = PROLOG_FAILURE;
|
||||
state = PROLOG_FAILURE;
|
||||
} else if ( st == "EPILOG_FAILURE") {
|
||||
state = EPILOG_FAILURE;
|
||||
state = EPILOG_FAILURE;
|
||||
} else if ( st == "EPILOG_STOP_FAILURE") {
|
||||
state = EPILOG_STOP_FAILURE;
|
||||
state = EPILOG_STOP_FAILURE;
|
||||
} else if ( st == "EPILOG_UNDEPLOY_FAILURE") {
|
||||
state = EPILOG_UNDEPLOY_FAILURE;
|
||||
state = EPILOG_UNDEPLOY_FAILURE;
|
||||
} else if ( st == "PROLOG_MIGRATE_POWEROFF") {
|
||||
state = PROLOG_MIGRATE_POWEROFF;
|
||||
state = PROLOG_MIGRATE_POWEROFF;
|
||||
} else if ( st == "PROLOG_MIGRATE_POWEROFF_FAILURE") {
|
||||
state = PROLOG_MIGRATE_POWEROFF_FAILURE;
|
||||
state = PROLOG_MIGRATE_POWEROFF_FAILURE;
|
||||
} else if ( st == "PROLOG_MIGRATE_SUSPEND") {
|
||||
state = PROLOG_MIGRATE_SUSPEND;
|
||||
state = PROLOG_MIGRATE_SUSPEND;
|
||||
} else if ( st == "PROLOG_MIGRATE_SUSPEND_FAILURE") {
|
||||
state = PROLOG_MIGRATE_SUSPEND_FAILURE;
|
||||
state = PROLOG_MIGRATE_SUSPEND_FAILURE;
|
||||
} else if ( st == "BOOT_STOPPED_FAILURE") {
|
||||
state = BOOT_STOPPED_FAILURE;
|
||||
state = BOOT_STOPPED_FAILURE;
|
||||
} else if ( st == "BOOT_UNDEPLOY_FAILURE") {
|
||||
state = BOOT_UNDEPLOY_FAILURE;
|
||||
state = BOOT_UNDEPLOY_FAILURE;
|
||||
} else if ( st == "PROLOG_RESUME_FAILURE") {
|
||||
state = PROLOG_RESUME_FAILURE;
|
||||
state = PROLOG_RESUME_FAILURE;
|
||||
} else if ( st == "PROLOG_UNDEPLOY_FAILURE") {
|
||||
state = PROLOG_UNDEPLOY_FAILURE;
|
||||
state = PROLOG_UNDEPLOY_FAILURE;
|
||||
} else if ( st == "DISK_SNAPSHOT_POWEROFF") {
|
||||
state = DISK_SNAPSHOT_POWEROFF;
|
||||
state = DISK_SNAPSHOT_POWEROFF;
|
||||
} else if ( st == "DISK_SNAPSHOT_REVERT_POWEROFF") {
|
||||
state = DISK_SNAPSHOT_REVERT_POWEROFF;
|
||||
state = DISK_SNAPSHOT_REVERT_POWEROFF;
|
||||
} else if ( st == "DISK_SNAPSHOT_DELETE_POWEROFF") {
|
||||
state = DISK_SNAPSHOT_DELETE_POWEROFF;
|
||||
state = DISK_SNAPSHOT_DELETE_POWEROFF;
|
||||
} else if ( st == "DISK_SNAPSHOT_SUSPENDED") {
|
||||
state = DISK_SNAPSHOT_SUSPENDED;
|
||||
state = DISK_SNAPSHOT_SUSPENDED;
|
||||
} else if ( st == "DISK_SNAPSHOT_REVERT_SUSPENDED") {
|
||||
state = DISK_SNAPSHOT_REVERT_SUSPENDED;
|
||||
state = DISK_SNAPSHOT_REVERT_SUSPENDED;
|
||||
} else if ( st == "DISK_SNAPSHOT_DELETE_SUSPENDED") {
|
||||
state = DISK_SNAPSHOT_DELETE_SUSPENDED;
|
||||
state = DISK_SNAPSHOT_DELETE_SUSPENDED;
|
||||
} else if ( st == "DISK_SNAPSHOT") {
|
||||
state = DISK_SNAPSHOT;
|
||||
state = DISK_SNAPSHOT;
|
||||
} else if ( st == "DISK_SNAPSHOT_DELETE") {
|
||||
state = DISK_SNAPSHOT_DELETE;
|
||||
state = DISK_SNAPSHOT_DELETE;
|
||||
} else if ( st == "PROLOG_MIGRATE_UNKNOWN") {
|
||||
state = PROLOG_MIGRATE_UNKNOWN;
|
||||
state = PROLOG_MIGRATE_UNKNOWN;
|
||||
} else if ( st == "PROLOG_MIGRATE_UNKNOWN_FAILURE") {
|
||||
state = PROLOG_MIGRATE_UNKNOWN_FAILURE;
|
||||
state = PROLOG_MIGRATE_UNKNOWN_FAILURE;
|
||||
} else if ( st == "DISK_RESIZE") {
|
||||
state = DISK_RESIZE;
|
||||
state = DISK_RESIZE;
|
||||
} else if ( st == "DISK_RESIZE_POWEROFF") {
|
||||
state = DISK_RESIZE_POWEROFF;
|
||||
state = DISK_RESIZE_POWEROFF;
|
||||
} else if ( st == "DISK_RESIZE_UNDEPLOYED") {
|
||||
state = DISK_RESIZE_UNDEPLOYED;
|
||||
state = DISK_RESIZE_UNDEPLOYED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@ -315,124 +315,124 @@ string& VirtualMachine::lcm_state_to_str(string& st, LcmState state)
|
||||
case RUNNING:
|
||||
st = "RUNNING"; break;
|
||||
case MIGRATE:
|
||||
st = "MIGRATE"; break;
|
||||
st = "MIGRATE"; break;
|
||||
case SAVE_STOP:
|
||||
st = "SAVE_STOP"; break;
|
||||
st = "SAVE_STOP"; break;
|
||||
case SAVE_SUSPEND:
|
||||
st = "SAVE_SUSPEND"; break;
|
||||
st = "SAVE_SUSPEND"; break;
|
||||
case SAVE_MIGRATE:
|
||||
st = "SAVE_MIGRATE"; break;
|
||||
st = "SAVE_MIGRATE"; break;
|
||||
case PROLOG_MIGRATE:
|
||||
st = "PROLOG_MIGRATE"; break;
|
||||
st = "PROLOG_MIGRATE"; break;
|
||||
case PROLOG_RESUME:
|
||||
st = "PROLOG_RESUME"; break;
|
||||
st = "PROLOG_RESUME"; break;
|
||||
case EPILOG_STOP:
|
||||
st = "EPILOG_STOP"; break;
|
||||
st = "EPILOG_STOP"; break;
|
||||
case EPILOG:
|
||||
st = "EPILOG"; break;
|
||||
st = "EPILOG"; break;
|
||||
case SHUTDOWN:
|
||||
st = "SHUTDOWN"; break;
|
||||
st = "SHUTDOWN"; break;
|
||||
case CLEANUP_RESUBMIT:
|
||||
st = "CLEANUP_RESUBMIT"; break;
|
||||
st = "CLEANUP_RESUBMIT"; break;
|
||||
case UNKNOWN:
|
||||
st = "UNKNOWN"; break;
|
||||
st = "UNKNOWN"; break;
|
||||
case HOTPLUG:
|
||||
st = "HOTPLUG"; break;
|
||||
st = "HOTPLUG"; break;
|
||||
case SHUTDOWN_POWEROFF:
|
||||
st = "SHUTDOWN_POWEROFF"; break;
|
||||
st = "SHUTDOWN_POWEROFF"; break;
|
||||
case BOOT_UNKNOWN:
|
||||
st = "BOOT_UNKNOWN"; break;
|
||||
st = "BOOT_UNKNOWN"; break;
|
||||
case BOOT_POWEROFF:
|
||||
st = "BOOT_POWEROFF"; break;
|
||||
st = "BOOT_POWEROFF"; break;
|
||||
case BOOT_SUSPENDED:
|
||||
st = "BOOT_SUSPENDED"; break;
|
||||
st = "BOOT_SUSPENDED"; break;
|
||||
case BOOT_STOPPED:
|
||||
st = "BOOT_STOPPED"; break;
|
||||
st = "BOOT_STOPPED"; break;
|
||||
case CLEANUP_DELETE:
|
||||
st = "CLEANUP_DELETE"; break;
|
||||
st = "CLEANUP_DELETE"; break;
|
||||
case HOTPLUG_SNAPSHOT:
|
||||
st = "HOTPLUG_SNAPSHOT"; break;
|
||||
st = "HOTPLUG_SNAPSHOT"; break;
|
||||
case HOTPLUG_NIC:
|
||||
st = "HOTPLUG_NIC"; break;
|
||||
st = "HOTPLUG_NIC"; break;
|
||||
case HOTPLUG_SAVEAS:
|
||||
st = "HOTPLUG_SAVEAS"; break;
|
||||
st = "HOTPLUG_SAVEAS"; break;
|
||||
case HOTPLUG_SAVEAS_POWEROFF:
|
||||
st = "HOTPLUG_SAVEAS_POWEROFF"; break;
|
||||
st = "HOTPLUG_SAVEAS_POWEROFF"; break;
|
||||
case HOTPLUG_SAVEAS_SUSPENDED:
|
||||
st = "HOTPLUG_SAVEAS_SUSPENDED"; break;
|
||||
st = "HOTPLUG_SAVEAS_SUSPENDED"; break;
|
||||
case SHUTDOWN_UNDEPLOY:
|
||||
st = "SHUTDOWN_UNDEPLOY"; break;
|
||||
st = "SHUTDOWN_UNDEPLOY"; break;
|
||||
case EPILOG_UNDEPLOY:
|
||||
st = "EPILOG_UNDEPLOY"; break;
|
||||
st = "EPILOG_UNDEPLOY"; break;
|
||||
case PROLOG_UNDEPLOY:
|
||||
st = "PROLOG_UNDEPLOY"; break;
|
||||
st = "PROLOG_UNDEPLOY"; break;
|
||||
case BOOT_UNDEPLOY:
|
||||
st = "BOOT_UNDEPLOY"; break;
|
||||
st = "BOOT_UNDEPLOY"; break;
|
||||
case HOTPLUG_PROLOG_POWEROFF:
|
||||
st = "HOTPLUG_PROLOG_POWEROFF"; break;
|
||||
st = "HOTPLUG_PROLOG_POWEROFF"; break;
|
||||
case HOTPLUG_EPILOG_POWEROFF:
|
||||
st = "HOTPLUG_EPILOG_POWEROFF"; break;
|
||||
st = "HOTPLUG_EPILOG_POWEROFF"; break;
|
||||
case BOOT_MIGRATE:
|
||||
st = "BOOT_MIGRATE"; break;
|
||||
st = "BOOT_MIGRATE"; break;
|
||||
case BOOT_FAILURE:
|
||||
st = "BOOT_FAILURE"; break;
|
||||
st = "BOOT_FAILURE"; break;
|
||||
case BOOT_MIGRATE_FAILURE:
|
||||
st = "BOOT_MIGRATE_FAILURE"; break;
|
||||
st = "BOOT_MIGRATE_FAILURE"; break;
|
||||
case PROLOG_MIGRATE_FAILURE:
|
||||
st = "PROLOG_MIGRATE_FAILURE"; break;
|
||||
st = "PROLOG_MIGRATE_FAILURE"; break;
|
||||
case PROLOG_FAILURE:
|
||||
st = "PROLOG_FAILURE"; break;
|
||||
st = "PROLOG_FAILURE"; break;
|
||||
case EPILOG_FAILURE:
|
||||
st = "EPILOG_FAILURE"; break;
|
||||
st = "EPILOG_FAILURE"; break;
|
||||
case EPILOG_STOP_FAILURE:
|
||||
st = "EPILOG_STOP_FAILURE"; break;
|
||||
st = "EPILOG_STOP_FAILURE"; break;
|
||||
case EPILOG_UNDEPLOY_FAILURE:
|
||||
st = "EPILOG_UNDEPLOY_FAILURE"; break;
|
||||
st = "EPILOG_UNDEPLOY_FAILURE"; break;
|
||||
case PROLOG_MIGRATE_POWEROFF:
|
||||
st = "PROLOG_MIGRATE_POWEROFF"; break;
|
||||
st = "PROLOG_MIGRATE_POWEROFF"; break;
|
||||
case PROLOG_MIGRATE_POWEROFF_FAILURE:
|
||||
st = "PROLOG_MIGRATE_POWEROFF_FAILURE"; break;
|
||||
st = "PROLOG_MIGRATE_POWEROFF_FAILURE"; break;
|
||||
case PROLOG_MIGRATE_SUSPEND:
|
||||
st = "PROLOG_MIGRATE_SUSPEND"; break;
|
||||
st = "PROLOG_MIGRATE_SUSPEND"; break;
|
||||
case PROLOG_MIGRATE_SUSPEND_FAILURE:
|
||||
st = "PROLOG_MIGRATE_SUSPEND_FAILURE"; break;
|
||||
st = "PROLOG_MIGRATE_SUSPEND_FAILURE"; break;
|
||||
case BOOT_STOPPED_FAILURE:
|
||||
st = "BOOT_STOPPED_FAILURE"; break;
|
||||
st = "BOOT_STOPPED_FAILURE"; break;
|
||||
case BOOT_UNDEPLOY_FAILURE:
|
||||
st = "BOOT_UNDEPLOY_FAILURE"; break;
|
||||
st = "BOOT_UNDEPLOY_FAILURE"; break;
|
||||
case PROLOG_RESUME_FAILURE:
|
||||
st = "PROLOG_RESUME_FAILURE"; break;
|
||||
st = "PROLOG_RESUME_FAILURE"; break;
|
||||
case PROLOG_UNDEPLOY_FAILURE:
|
||||
st = "PROLOG_UNDEPLOY_FAILURE"; break;
|
||||
st = "PROLOG_UNDEPLOY_FAILURE"; break;
|
||||
case DISK_SNAPSHOT_POWEROFF:
|
||||
st = "DISK_SNAPSHOT_POWEROFF"; break;
|
||||
st = "DISK_SNAPSHOT_POWEROFF"; break;
|
||||
case DISK_SNAPSHOT_REVERT_POWEROFF:
|
||||
st = "DISK_SNAPSHOT_REVERT_POWEROFF"; break;
|
||||
st = "DISK_SNAPSHOT_REVERT_POWEROFF"; break;
|
||||
case DISK_SNAPSHOT_DELETE_POWEROFF:
|
||||
st = "DISK_SNAPSHOT_DELETE_POWEROFF"; break;
|
||||
st = "DISK_SNAPSHOT_DELETE_POWEROFF"; break;
|
||||
case DISK_SNAPSHOT_SUSPENDED:
|
||||
st = "DISK_SNAPSHOT_SUSPENDED"; break;
|
||||
st = "DISK_SNAPSHOT_SUSPENDED"; break;
|
||||
case DISK_SNAPSHOT_REVERT_SUSPENDED:
|
||||
st = "DISK_SNAPSHOT_REVERT_SUSPENDED"; break;
|
||||
st = "DISK_SNAPSHOT_REVERT_SUSPENDED"; break;
|
||||
case DISK_SNAPSHOT_DELETE_SUSPENDED:
|
||||
st = "DISK_SNAPSHOT_DELETE_SUSPENDED"; break;
|
||||
st = "DISK_SNAPSHOT_DELETE_SUSPENDED"; break;
|
||||
case DISK_SNAPSHOT:
|
||||
st = "DISK_SNAPSHOT"; break;
|
||||
st = "DISK_SNAPSHOT"; break;
|
||||
case DISK_SNAPSHOT_DELETE:
|
||||
st = "DISK_SNAPSHOT_DELETE"; break;
|
||||
st = "DISK_SNAPSHOT_DELETE"; break;
|
||||
case PROLOG_MIGRATE_UNKNOWN:
|
||||
st = "PROLOG_MIGRATE_UNKNOWN"; break;
|
||||
st = "PROLOG_MIGRATE_UNKNOWN"; break;
|
||||
case PROLOG_MIGRATE_UNKNOWN_FAILURE:
|
||||
st = "PROLOG_MIGRATE_UNKNOWN_FAILURE"; break;
|
||||
st = "PROLOG_MIGRATE_UNKNOWN_FAILURE"; break;
|
||||
case DISK_RESIZE:
|
||||
st = "DISK_RESIZE"; break;
|
||||
st = "DISK_RESIZE"; break;
|
||||
case DISK_RESIZE_POWEROFF:
|
||||
st = "DISK_RESIZE_POWEROFF"; break;
|
||||
st = "DISK_RESIZE_POWEROFF"; break;
|
||||
case DISK_RESIZE_UNDEPLOYED:
|
||||
st = "DISK_RESIZE_UNDEPLOYED"; break;
|
||||
st = "DISK_RESIZE_UNDEPLOYED"; break;
|
||||
}
|
||||
|
||||
return st;
|
||||
return st;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -819,10 +819,14 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
|
||||
this->name = name;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Move known attributes that doesn't need additional procesing to template
|
||||
// -------------------------------------------------------------------------
|
||||
parse_well_known_attributes();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Parse the Public Cloud specs for this VM
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (parse_public_clouds(error_str) != 0)
|
||||
{
|
||||
goto error_public;
|
||||
@ -831,7 +835,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check for EMULATOR attribute
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
user_obj_template->get("EMULATOR", value);
|
||||
|
||||
if (!value.empty())
|
||||
@ -841,10 +844,9 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Check for CPU, VCPU and MEMORY attributes
|
||||
// Check for CPU, VCPU, MEMORY and TOPOLOGY attributes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if ( user_obj_template->get("MEMORY", ivalue) == false || (ivalue * 1024) <= 0 )
|
||||
if ( user_obj_template->get("MEMORY", ivalue) == false || ivalue <= 0 )
|
||||
{
|
||||
goto error_memory;
|
||||
}
|
||||
@ -878,7 +880,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check the cost attributes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if ( user_obj_template->get("CPU_COST", fvalue) == true )
|
||||
{
|
||||
if ( fvalue < 0 )
|
||||
@ -915,7 +916,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check the OS attribute
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_os(error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -931,7 +931,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// PCI Devices (Needs to be parsed before network)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_pci(error_str, user_obj_template);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -942,7 +941,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Parse the defaults to merge
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_defaults(error_str, user_obj_template);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -953,7 +951,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Parse the virtual router attributes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_vrouter(error_str, user_obj_template);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -964,7 +961,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Get network leases
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = get_network_leases(error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -975,7 +971,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// ------------------------------------------------------------------------
|
||||
// Get disk images
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = get_disk_images(error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -1002,7 +997,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// -------------------------------------------------------------------------
|
||||
// Set boot order
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
rc = set_boot_order(obj_template, error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -1013,7 +1007,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// -------------------------------------------------------------------------
|
||||
// Parse the context & requirements
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
rc = parse_context(error_str, false); //Don't generate context for auto NICs
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -1043,7 +1036,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
// -------------------------------------------------------------------------
|
||||
// Get and set DEPLOY_ID for imported VMs
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
user_obj_template->get("IMPORT_VM_ID", value);
|
||||
user_obj_template->erase("IMPORT_VM_ID");
|
||||
|
||||
@ -1078,14 +1070,9 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
goto error_rollback;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
parse_well_known_attributes();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Insert the VM
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = insert_replace(db, false, error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
@ -1096,7 +1083,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
//-------------------------------------------------------------------------
|
||||
//Check for missing unlock callbacks during creation
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
if ( state == VirtualMachine::CLONING )
|
||||
{
|
||||
Nebula::instance().get_lcm()->trigger(LCMAction::DISK_LOCK_SUCCESS,oid);
|
||||
@ -1599,6 +1585,15 @@ int VirtualMachine::automatic_requirements(set<int>& cluster_ids,
|
||||
oss << "!(PUBLIC_CLOUD = YES)";
|
||||
}
|
||||
|
||||
if ( is_pinned() )
|
||||
{
|
||||
oss << " & (PIN_POLICY = PINNED)";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << " & !(PIN_POLICY = PINNED)";
|
||||
}
|
||||
|
||||
int num_public = get_public_clouds(clouds);
|
||||
|
||||
if (num_public != 0)
|
||||
@ -1988,95 +1983,103 @@ void VirtualMachine::cp_previous_history()
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk,
|
||||
vector<VectorAttribute *>& pci_devs)
|
||||
void VirtualMachine::get_capacity(HostShareCapacity& sr)
|
||||
{
|
||||
istringstream iss;
|
||||
float fcpu;
|
||||
float fcpu;
|
||||
|
||||
pci_devs.clear();
|
||||
sr.pci.clear();
|
||||
sr.nodes.clear();
|
||||
|
||||
if ((get_template_attribute("MEMORY",memory) == false) ||
|
||||
(get_template_attribute("CPU",fcpu) == false))
|
||||
sr.vmid = oid;
|
||||
|
||||
if ((get_template_attribute("MEMORY", sr.mem) == false) ||
|
||||
(get_template_attribute("CPU", fcpu) == false))
|
||||
{
|
||||
cpu = 0;
|
||||
memory = 0;
|
||||
disk = 0;
|
||||
sr.cpu = 0;
|
||||
sr.mem = 0;
|
||||
sr.disk = 0;
|
||||
|
||||
sr.vcpu = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cpu = (int) (fcpu * 100);//now in 100%
|
||||
memory = memory * 1024; //now in Kilobytes
|
||||
disk = 0;
|
||||
sr.cpu = (int) (fcpu * 100); //%
|
||||
sr.mem = sr.mem * 1024; //Kb
|
||||
sr.disk = 0;
|
||||
|
||||
obj_template->get("PCI", pci_devs);
|
||||
get_template_attribute("VCPU", sr.vcpu);
|
||||
|
||||
obj_template->get("PCI", sr.pci);
|
||||
|
||||
obj_template->get("NUMA_NODE", sr.nodes);
|
||||
|
||||
sr.topology = obj_template->get("TOPOLOGY");
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachine::check_resize (
|
||||
float cpu, long int memory, int vcpu, string& error_str)
|
||||
int VirtualMachine::resize(float cpu, long int memory, unsigned int vcpu,
|
||||
string& error)
|
||||
{
|
||||
if (cpu < 0)
|
||||
{
|
||||
error_str = "CPU must be a positive float or integer value.";
|
||||
return -1;
|
||||
}
|
||||
unsigned int s, c, t;
|
||||
|
||||
if (memory < 0)
|
||||
{
|
||||
error_str = "MEMORY must be a positive integer value.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vcpu < 0)
|
||||
{
|
||||
error_str = "VCPU must be a positive integer value.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachine::resize(float cpu, long int memory, int vcpu, string& error_str)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
int rc = check_resize(cpu, memory, vcpu, error_str);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
s = c = t = 0;
|
||||
|
||||
if (cpu > 0)
|
||||
{
|
||||
oss << cpu;
|
||||
replace_template_attribute("CPU", oss.str());
|
||||
oss.str("");
|
||||
replace_template_attribute("CPU", cpu);
|
||||
}
|
||||
|
||||
if (memory > 0)
|
||||
{
|
||||
oss << memory;
|
||||
replace_template_attribute("MEMORY", oss.str());
|
||||
oss.str("");
|
||||
replace_template_attribute("MEMORY", memory);
|
||||
}
|
||||
|
||||
if (vcpu > 0)
|
||||
{
|
||||
oss << vcpu;
|
||||
replace_template_attribute("VCPU", oss.str());
|
||||
replace_template_attribute("VCPU", vcpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
get_template_attribute("VCPU", vcpu);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Update the NUMA topology with new size: */
|
||||
/* 1. Increase number of cores for new VCPU (keep threads and sockets) */
|
||||
/* 2. Clear current nodes and build new ones with new MEMORY/VCPU */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
VectorAttribute * vtopol = get_template_attribute("TOPOLOGY");
|
||||
|
||||
if ( vtopol == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vtopol->vector_value("SOCKETS", s);
|
||||
vtopol->vector_value("CORES", c);
|
||||
vtopol->vector_value("THREADS", t);
|
||||
|
||||
if ( s != 0 && c != 0 && t != 0 && (s * c * t) != vcpu)
|
||||
{
|
||||
if ( vcpu%(t * s) != 0 )
|
||||
{
|
||||
error = "new VCPU is not multiple of the total number of threads";
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = vcpu/(t * s);
|
||||
|
||||
vtopol->replace("CORES", c);
|
||||
}
|
||||
|
||||
remove_template_attribute("NUMA_NODE");
|
||||
|
||||
return parse_topology(obj_template, error);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -2361,14 +2364,12 @@ string& VirtualMachine::to_token(string& text) const
|
||||
string& VirtualMachine::to_xml_short(string& xml)
|
||||
{
|
||||
string disks_xml, monitoring_xml, user_template_xml, history_xml, nics_xml;
|
||||
string cpu_tmpl, mem_tmpl;
|
||||
|
||||
ostringstream oss;
|
||||
string cpu_tmpl, mem_tmpl, auto_reqs, auto_ds_reqs, auto_nic_reqs;
|
||||
|
||||
obj_template->get("CPU", cpu_tmpl);
|
||||
obj_template->get("MEMORY", mem_tmpl);
|
||||
obj_template->get("AUTOMATIC_REQUIREMENTS", auto_reqs);
|
||||
obj_template->get("AUTOMATIC_DS_REQUIREMENTS", auto_ds_reqs);
|
||||
obj_template->get("AUTOMATIC_NIC_REQUIREMENTS", auto_nic_reqs);
|
||||
|
||||
oss << "<VM>"
|
||||
<< "<ID>" << oid << "</ID>"
|
||||
@ -2403,27 +2404,6 @@ string& VirtualMachine::to_xml_short(string& xml)
|
||||
graph->to_xml(oss);
|
||||
}
|
||||
|
||||
if (!auto_reqs.empty())
|
||||
{
|
||||
oss << "<AUTOMATIC_REQUIREMENTS>";
|
||||
oss << one_util::escape_xml(auto_reqs);
|
||||
oss << "</AUTOMATIC_REQUIREMENTS>";
|
||||
}
|
||||
|
||||
if (!auto_ds_reqs.empty())
|
||||
{
|
||||
oss << "<AUTOMATIC_DS_REQUIREMENTS>";
|
||||
oss << one_util::escape_xml(auto_ds_reqs);
|
||||
oss << "</AUTOMATIC_DS_REQUIREMENTS>";
|
||||
}
|
||||
|
||||
if (!auto_nic_reqs.empty())
|
||||
{
|
||||
oss << "<AUTOMATIC_NIC_REQUIREMENTS>";
|
||||
oss << one_util::escape_xml(auto_nic_reqs);
|
||||
oss << "</AUTOMATIC_NIC_REQUIREMENTS>";
|
||||
}
|
||||
|
||||
oss << "</TEMPLATE>"
|
||||
<< monitoring.to_xml_short(monitoring_xml)
|
||||
<< user_obj_template->to_xml_short(user_template_xml);
|
||||
@ -2439,17 +2419,6 @@ string& VirtualMachine::to_xml_short(string& xml)
|
||||
oss << "<HISTORY_RECORDS/>";
|
||||
}
|
||||
|
||||
std::vector<VectorAttribute *> vm_groups;
|
||||
|
||||
if (obj_template->get("VMGROUP", vm_groups) > 0)
|
||||
{
|
||||
for (std::vector<VectorAttribute *>::iterator it = vm_groups.begin();
|
||||
it != vm_groups.end() ; it++)
|
||||
{
|
||||
(*it)->to_xml(oss);
|
||||
}
|
||||
}
|
||||
|
||||
oss << "</VM>";
|
||||
|
||||
xml = oss.str();
|
||||
|
@ -318,12 +318,12 @@ int VirtualMachine::parse_vrouter(string& error_str, Template * tmpl)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int check_pci_attributes(VectorAttribute * pci, const string& default_bus,
|
||||
string& error_str)
|
||||
string& error_str)
|
||||
{
|
||||
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
|
||||
static int num_attrs = 3;
|
||||
|
||||
string bus;
|
||||
string bus;
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < num_attrs; i++)
|
||||
@ -348,11 +348,11 @@ static int check_pci_attributes(VectorAttribute * pci, const string& default_bus
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( HostSharePCI::set_pci_address(pci, default_bus) != 0 )
|
||||
{
|
||||
error_str = "Wrong BUS in PCI attribute";
|
||||
return -1;
|
||||
}
|
||||
if ( HostSharePCI::set_pci_address(pci, default_bus) != 0 )
|
||||
{
|
||||
error_str = "Wrong BUS in PCI attribute";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -373,10 +373,10 @@ int VirtualMachine::parse_pci(string& error_str, Template * tmpl)
|
||||
obj_template->set(*it);
|
||||
}
|
||||
|
||||
Nebula& nd = Nebula::instance();
|
||||
string default_bus;
|
||||
Nebula& nd = Nebula::instance();
|
||||
string default_bus;
|
||||
|
||||
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", default_bus);
|
||||
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", default_bus);
|
||||
|
||||
for (it = array_pci.begin(); it !=array_pci.end(); ++it)
|
||||
{
|
||||
@ -519,22 +519,21 @@ void VirtualMachine::parse_well_known_attributes()
|
||||
* FEATURES
|
||||
* RAW
|
||||
* CLONING_TEMPLATE_ID
|
||||
* TOPOLOGY
|
||||
* NUMA_NODE
|
||||
*/
|
||||
std::vector<std::string> names = {"INPUT", "FEATURES", "RAW",
|
||||
"CLONING_TEMPLATE_ID", "TOPOLOGY", "NUMA_NODE"};
|
||||
|
||||
vector<Attribute *> v_attr;
|
||||
vector<Attribute *>::iterator it;
|
||||
|
||||
string names[] = {"INPUT", "FEATURES", "RAW", "CLONING_TEMPLATE_ID"};
|
||||
|
||||
for (int i=0; i<4; i++)
|
||||
for (auto it = names.begin(); it != names.end() ; ++it)
|
||||
{
|
||||
v_attr.clear();
|
||||
vector<Attribute *> v_attr;
|
||||
|
||||
user_obj_template->remove(names[i], v_attr);
|
||||
user_obj_template->remove(*it, v_attr);
|
||||
|
||||
for (it=v_attr.begin(); it != v_attr.end(); it++)
|
||||
for (auto jt=v_attr.begin(); jt != v_attr.end(); jt++)
|
||||
{
|
||||
obj_template->set(*it);
|
||||
obj_template->set(*jt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -732,3 +731,280 @@ int VirtualMachine::parse_cpu_model(Template * tmpl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachine::parse_topology(Template * tmpl, std::string &error)
|
||||
{
|
||||
/**
|
||||
* TOPOLOGY
|
||||
* - NUMA_NODES: number of numa nodes
|
||||
* - PIN_POLICY: CORE, THREAD, SHARED, NONE
|
||||
* - THREADS
|
||||
* - CORES
|
||||
* - SOCKETS
|
||||
*/
|
||||
std::vector<VectorAttribute *> numa_nodes;
|
||||
std::vector<VectorAttribute *> vtopol_a;
|
||||
|
||||
VectorAttribute * vtopol = 0;
|
||||
|
||||
tmpl->remove("TOPOLOGY", vtopol_a);
|
||||
|
||||
if ( !vtopol_a.empty() )
|
||||
{
|
||||
auto it = vtopol_a.begin();
|
||||
vtopol = *it;
|
||||
|
||||
for ( ++it; it != vtopol_a.end(); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
tmpl->get("NUMA_NODE", numa_nodes);
|
||||
|
||||
if ( vtopol == 0 && numa_nodes.empty() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( vtopol == 0 )
|
||||
{
|
||||
vtopol = new VectorAttribute("TOPOLOGY");
|
||||
}
|
||||
|
||||
tmpl->set(vtopol);
|
||||
|
||||
std::string pp_s = vtopol->vector_value("PIN_POLICY");
|
||||
|
||||
HostShare::PinPolicy pp = HostShare::str_to_pin_policy(pp_s);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Set MEMORY, HUGEPAGE_SIZE, vCPU & update CPU for pinned VMS */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
long long memory;
|
||||
|
||||
unsigned int vcpu = 0;
|
||||
unsigned long int hpsz_mb = 0;
|
||||
|
||||
if (!tmpl->get("MEMORY", memory))
|
||||
{
|
||||
error = "VM has not MEMORY set";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!tmpl->get("VCPU", vcpu))
|
||||
{
|
||||
vcpu = 1;
|
||||
tmpl->replace("VCPU", 1);
|
||||
}
|
||||
|
||||
if ( pp != HostShare::PP_NONE )
|
||||
{
|
||||
tmpl->replace("CPU", vcpu);
|
||||
}
|
||||
|
||||
if ( vtopol->vector_value("HUGEPAGE_SIZE", hpsz_mb) == 0 )
|
||||
{
|
||||
vtopol->replace("HUGEPAGE_SIZE", hpsz_mb * 1024);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Check topology for non pinned & pinned VMs */
|
||||
/* - non-pinned VM needs to set SOCKETS, CORES and THREADS */
|
||||
/* - pinned VM */
|
||||
/* 1. Set sockets to number of NUMA_NODE or 1 if not given */
|
||||
/* 2. core and thread given. Check consistency */
|
||||
/* 3. core given. Compute threads & check power of 2 */
|
||||
/* 4. other combinations are set by the scheduler */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
unsigned int s, c, t;
|
||||
|
||||
s = c = t = 0;
|
||||
|
||||
vtopol->vector_value("SOCKETS", s);
|
||||
vtopol->vector_value("CORES", c);
|
||||
vtopol->vector_value("THREADS", t);
|
||||
|
||||
if ( pp == HostShare::PP_NONE )
|
||||
{
|
||||
if ( c == 0 || t == 0 || s == 0 )
|
||||
{
|
||||
error = "Non-pinned VMs with a virtual topology needs to set "
|
||||
" SOCKETS, CORES and THREADS numbers.";
|
||||
return -1;
|
||||
}
|
||||
else if ((s * c * t) != vcpu)
|
||||
{
|
||||
error = "Total threads per core and socket needs to match VCPU";
|
||||
return -1;
|
||||
}
|
||||
|
||||
vtopol->replace("PIN_POLICY", "NONE");
|
||||
|
||||
tmpl->erase("NUMA_NODE");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( s == 0 )
|
||||
{
|
||||
if ( numa_nodes.empty() )
|
||||
{
|
||||
s = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = numa_nodes.size();
|
||||
}
|
||||
|
||||
vtopol->replace("SOCKETS", s);
|
||||
}
|
||||
|
||||
if ( c != 0 && t != 0 && (s * c * t) != vcpu)
|
||||
{
|
||||
error = "Total threads per core and socket needs to match VCPU";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( t == 0 && c != 0 )
|
||||
{
|
||||
if ( vcpu%(c * s) != 0 )
|
||||
{
|
||||
error = "VCPU is not multiple of the total number of cores";
|
||||
return -1;
|
||||
}
|
||||
|
||||
t = vcpu/(c * s);
|
||||
|
||||
if ((t & (t - 1)) != 0 )
|
||||
{
|
||||
error = "Computed number of threads is not power of 2";
|
||||
return -1;
|
||||
}
|
||||
|
||||
vtopol->replace("THREADS", t);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Build NUMA_NODE stanzas for the given topology */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
if (numa_nodes.empty()) // Automatic Homogenous Topology
|
||||
{
|
||||
if ( vcpu % s != 0 )
|
||||
{
|
||||
error = "VCPU is not multiple of the number of NUMA nodes";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( memory % s != 0 )
|
||||
{
|
||||
error = "MEMORY is not multiple of the number of NUMA nodes";
|
||||
return -1;
|
||||
}
|
||||
|
||||
long long mem_node = memory / s;
|
||||
|
||||
unsigned int cpu_node = vcpu / s;
|
||||
|
||||
for (unsigned int i = 0 ; i < s ; ++i)
|
||||
{
|
||||
VectorAttribute * node = new VectorAttribute("NUMA_NODE");
|
||||
|
||||
node->replace("TOTAL_CPUS", cpu_node);
|
||||
node->replace("MEMORY", mem_node * 1024);
|
||||
|
||||
tmpl->set(node);
|
||||
}
|
||||
}
|
||||
else // Manual/Asymmetric Topology, NUMA_NODE array
|
||||
{
|
||||
long long node_mem = 0;
|
||||
unsigned int node_cpu = 0;
|
||||
|
||||
std::vector<VectorAttribute *> new_nodes;
|
||||
|
||||
for (auto it = numa_nodes.begin() ; it != numa_nodes.end() ; ++it)
|
||||
{
|
||||
long long nmem = 0;
|
||||
unsigned int ncpu = 0;
|
||||
|
||||
(*it)->vector_value("TOTAL_CPUS", ncpu);
|
||||
(*it)->vector_value("MEMORY", nmem);
|
||||
|
||||
if ( ncpu == 0 || nmem == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
VectorAttribute * node = new VectorAttribute("NUMA_NODE");
|
||||
|
||||
node->replace("TOTAL_CPUS", ncpu);
|
||||
node->replace("MEMORY", nmem * 1024);
|
||||
|
||||
new_nodes.push_back(node);
|
||||
|
||||
node_cpu += ncpu;
|
||||
node_mem += nmem;
|
||||
}
|
||||
|
||||
tmpl->erase("NUMA_NODE");
|
||||
|
||||
if (node_cpu != vcpu || node_mem != memory ||
|
||||
node_cpu == 0 || node_mem == 0)
|
||||
{
|
||||
for (auto it = new_nodes.begin(); it != new_nodes.end(); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
if (node_cpu == 0)
|
||||
{
|
||||
error = "NUMA_NODES cannot have 0 CPUs";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node_mem == 0)
|
||||
{
|
||||
error = "NUMA_NODES cannot have 0 MEMORY";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node_cpu != vcpu)
|
||||
{
|
||||
error = "Total CPUS of NUMA nodes is different from VM VCPU";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node_mem != memory)
|
||||
{
|
||||
error = "Total MEMORY of NUMA nodes is different from VM MEMORY";
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmpl->set(new_nodes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachine::is_pinned()
|
||||
{
|
||||
VectorAttribute * topology = obj_template->get("TOPOLOGY");
|
||||
|
||||
if ( topology == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string pp_s = topology->vector_value("PIN_POLICY");
|
||||
|
||||
HostShare::PinPolicy pp = HostShare::str_to_pin_policy(pp_s);
|
||||
|
||||
return pp != HostShare::PP_NONE;
|
||||
}
|
||||
|
@ -156,6 +156,193 @@ static void insert_sec(ofstream& file, const string& base, const string& s,
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void pin_cpu(ofstream& file, const VectorAttribute * topology,
|
||||
std::vector<const VectorAttribute *> &nodes)
|
||||
{
|
||||
HostShare::PinPolicy pp = HostShare::PP_NONE;
|
||||
unsigned int vcpu_id = 0;
|
||||
|
||||
std::ostringstream oss;
|
||||
|
||||
if ( topology != 0 )
|
||||
{
|
||||
std::string pp_s;
|
||||
|
||||
pp_s = topology->vector_value("PIN_POLICY");
|
||||
pp = HostShare::str_to_pin_policy(pp_s);
|
||||
}
|
||||
|
||||
if ( pp == HostShare::PP_NONE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = nodes.begin(); it != nodes.end() ; ++it)
|
||||
{
|
||||
unsigned int nv = 0;
|
||||
|
||||
std::vector<unsigned int> cpus_a;
|
||||
std::string cpus = (*it)->vector_value("CPUS");
|
||||
|
||||
(*it)->vector_value("TOTAL_CPUS", nv);
|
||||
|
||||
if ( nv == 0 || cpus.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
one_util::split(cpus, ',', cpus_a);
|
||||
|
||||
for ( unsigned int i = 0; i < nv; ++i, ++vcpu_id )
|
||||
{
|
||||
file << "\t\t<vcpupin vcpu='" << vcpu_id << "' cpuset='";
|
||||
|
||||
if ( pp == HostShare::PP_SHARED )
|
||||
{
|
||||
file << cpus << "'/>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
file << cpus_a[i] << "'/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( it != nodes.begin() )
|
||||
{
|
||||
oss << ",";
|
||||
}
|
||||
|
||||
oss << cpus;
|
||||
}
|
||||
|
||||
file << "\t\t<emulatorpin cpuset='" << oss.str() << "'/>\n";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void vtopol(ofstream& file, const VectorAttribute * topology,
|
||||
std::vector<const VectorAttribute *> &nodes, std::string &numatune,
|
||||
std::string &membacking)
|
||||
{
|
||||
std::string ma;
|
||||
int hpsz_kb = 0;
|
||||
|
||||
if ( topology != 0 )
|
||||
{
|
||||
int s, c, t;
|
||||
|
||||
s = c = t = 1;
|
||||
|
||||
topology->vector_value("SOCKETS", s);
|
||||
topology->vector_value("CORES", c);
|
||||
topology->vector_value("THREADS", t);
|
||||
topology->vector_value("HUGEPAGE_SIZE", hpsz_kb);
|
||||
|
||||
ma = topology->vector_value("MEMORY_ACCESS");
|
||||
|
||||
if (!ma.empty() && hpsz_kb != 0)
|
||||
{
|
||||
one_util::tolower(ma);
|
||||
|
||||
if (ma != "private" && ma != "shared")
|
||||
{
|
||||
ma = "";
|
||||
}
|
||||
}
|
||||
|
||||
file << "\t\t<topology sockets='" << s << "' cores='" << c
|
||||
<< "' threads='"<< t <<"'/>\n";
|
||||
}
|
||||
|
||||
if ( nodes.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream oss, mnodes;
|
||||
|
||||
unsigned int cpuid = 0;
|
||||
unsigned int cid = 0;
|
||||
|
||||
oss << "\t<numatune>\n";
|
||||
file << "\t\t<numa>\n";
|
||||
|
||||
for (auto it = nodes.begin() ; it != nodes.end() ; ++it, ++cid)
|
||||
{
|
||||
unsigned int ncpu = 0;
|
||||
|
||||
std::string mem = (*it)->vector_value("MEMORY");
|
||||
std::string mem_id = (*it)->vector_value("MEMORY_NODE_ID");
|
||||
|
||||
(*it)->vector_value("TOTAL_CPUS", ncpu);
|
||||
|
||||
file << "\t\t\t<cell id='" << cid << "' memory='" << mem << "'";
|
||||
|
||||
if ( ncpu > 0 )
|
||||
{
|
||||
file << " cpus='" << cpuid << "-" << cpuid + ncpu - 1 << "'";
|
||||
}
|
||||
|
||||
if (!ma.empty())
|
||||
{
|
||||
file << " memAccess='" << ma << "'";
|
||||
}
|
||||
|
||||
file << "/>\n";
|
||||
|
||||
cpuid += ncpu;
|
||||
|
||||
if (!mem_id.empty())
|
||||
{
|
||||
oss << "\t\t<memnode cellid='" << cid << "' mode='strict' nodeset='"
|
||||
<< mem_id <<"'/>\n";
|
||||
|
||||
if (!mnodes.str().empty())
|
||||
{
|
||||
mnodes << ",";
|
||||
}
|
||||
|
||||
mnodes << mem_id;
|
||||
}
|
||||
}
|
||||
|
||||
file << "\t\t</numa>\n";
|
||||
|
||||
if (!mnodes.str().empty())
|
||||
{
|
||||
oss << "\t\t<memory mode='strict' nodeset='" << mnodes.str() << "'/>\n";
|
||||
oss << "\t</numatune>\n";
|
||||
|
||||
numatune = oss.str();
|
||||
}
|
||||
|
||||
if ( hpsz_kb != 0 )
|
||||
{
|
||||
std::ostringstream mboss;
|
||||
|
||||
mboss << "\t<memoryBacking>\n";
|
||||
mboss << "\t\t<hugepages>\n";
|
||||
|
||||
mboss << "\t\t\t<page size=" << one_util::escape_xml_attr(hpsz_kb);
|
||||
|
||||
if (!mnodes.str().empty())
|
||||
{
|
||||
mboss << " nodeset='" << mnodes.str() << "'";
|
||||
}
|
||||
|
||||
mboss << "/>\n";
|
||||
|
||||
mboss << "\t\t</hugepages>\n";
|
||||
mboss << "\t</memoryBacking>\n";
|
||||
|
||||
membacking = mboss.str();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int LibVirtDriver::deployment_description_kvm(
|
||||
const VirtualMachine * vm,
|
||||
const string& file_name) const
|
||||
@ -328,6 +515,12 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
string default_raw = "";
|
||||
string data = "";
|
||||
|
||||
const VectorAttribute * topology;
|
||||
vector<const VectorAttribute *> nodes;
|
||||
|
||||
std::string numa_tune = "";
|
||||
std::string mbacking = "";
|
||||
|
||||
string vm_xml;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -376,13 +569,18 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
}
|
||||
|
||||
//Every process gets 1024 shares by default (cgroups), scale this with CPU
|
||||
if(vm->get_template_attribute("CPU", cpu))
|
||||
{
|
||||
file << "\t<cputune>" << endl
|
||||
<< "\t\t<shares>"<< ceil( cpu * CGROUP_BASE_CPU_SHARES )
|
||||
<< "</shares>" << endl
|
||||
<< "\t</cputune>"<< endl;
|
||||
}
|
||||
cpu = 1;
|
||||
vm->get_template_attribute("CPU", cpu);
|
||||
|
||||
topology = vm->get_template_attribute("TOPOLOGY");
|
||||
vm->get_template_attribute("NUMA_NODE", nodes);
|
||||
|
||||
file << "\t<cputune>\n";
|
||||
file << "\t\t<shares>"<< ceil(cpu * CGROUP_BASE_CPU_SHARES) << "</shares>\n";
|
||||
|
||||
pin_cpu(file, topology, nodes);
|
||||
|
||||
file << "\t</cputune>\n";
|
||||
|
||||
// Memory must be expressed in Kb
|
||||
if (vm->get_template_attribute("MEMORY",memory))
|
||||
@ -497,6 +695,7 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
// ------------------------------------------------------------------------
|
||||
cpu_model_v = vm->get_template_attribute("CPU_MODEL");
|
||||
|
||||
|
||||
if( cpu_model_v != 0 )
|
||||
{
|
||||
cpu_model = cpu_model_v->vector_value("MODEL");
|
||||
@ -513,19 +712,40 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
//TODO #756 cache, feature
|
||||
}
|
||||
|
||||
if ( !cpu_model.empty() )
|
||||
if ( !cpu_model.empty() || topology != 0 )
|
||||
{
|
||||
file << "\t<cpu mode=" << one_util::escape_xml_attr(cpu_mode) << ">\n";
|
||||
file << "\t<cpu" ;
|
||||
|
||||
if ( cpu_mode == "custom" )
|
||||
if (!cpu_model.empty())
|
||||
{
|
||||
file << "\t\t<model fallback='forbid'>" << one_util::escape_xml(cpu_model)
|
||||
<< "</model>\n";
|
||||
file << " mode=" << one_util::escape_xml_attr(cpu_mode) << ">\n";
|
||||
|
||||
if ( cpu_mode == "custom" )
|
||||
{
|
||||
file << "\t\t<model fallback='forbid'>"
|
||||
<< one_util::escape_xml(cpu_model) << "</model>\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file << ">\n";
|
||||
}
|
||||
|
||||
vtopol(file, topology, nodes, numa_tune, mbacking);
|
||||
|
||||
file << "\t</cpu>\n";
|
||||
}
|
||||
|
||||
if (!numa_tune.empty())
|
||||
{
|
||||
file << numa_tune;
|
||||
}
|
||||
|
||||
if (!mbacking.empty())
|
||||
{
|
||||
file << mbacking;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// DEVICES SECTION
|
||||
// ------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user