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

F #2347: Set antiaffinity placement constraints for VMs

This commit is contained in:
Ruben S. Montero 2017-01-20 20:46:50 +01:00
parent d73a57dab7
commit 685b0bd944
11 changed files with 289 additions and 148 deletions

View File

@ -23,6 +23,8 @@
class VMGroupPool;
enum class VMGroupPolicy;
/**
* A VM group is a set of related VMs that may impose placement constraints.
*
@ -124,18 +126,17 @@ private:
*
* @return 0 if all roles are defined -1 otherwise
*/
int check_rule_names(VMGroupRule::Policy policy, std::string& error_str);
int check_rule_names(VMGroupPolicy policy, std::string& error_str);
/**
* Generate a rule_set from the AFFINED/ANTI_AFFINED rules
* @param policy AFFINED or ANTIAFFINED
* @param rule_set with the rules
* @param error_str if some of the roles are not defined
* @param p policy AFFINED or ANTIAFFINED
* @param rs rule_set with the rules
* @param error if some of the roles are not defined
*
* @return 0 if success -1 otherwise
*/
int get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules,
std::string& error_str);
int get_rules(VMGroupPolicy p, VMGroupRule::rule_set& rs, std::string& err);
int check_rule_consistency(std::string& error);

View File

@ -22,6 +22,8 @@
class VMGroupPool;
enum class VMGroupPolicy;
/**
* A VMGroupRole defines a VM type that typically implements a role in a
* multi-vm application.
@ -37,19 +39,6 @@ class VMGroupPool;
class VMGroupRole
{
public:
/**
* Scheduling policy for the VMs within this role
*/
enum Policy
{
NONE = 0x00,
AFFINED = 0x01,
ANTI_AFFINED= 0x02
};
/* ---------------------------------------------------------------------- */
VMGroupRole(VectorAttribute *_va);
virtual ~VMGroupRole(){};
@ -77,7 +66,7 @@ public:
/**
* @return the policy of this role
*/
Policy policy();
VMGroupPolicy policy();
std::string policy_s()
{
@ -92,6 +81,11 @@ public:
return vms;
};
int size_vms()
{
return vms.size();
}
void add_vm(int vm_id);
void del_vm(int vm_id);
@ -110,10 +104,10 @@ public:
/**
* Generates a string with the boolean expression to conform an affinity
* constraint policy
* @param policy to place VMs respect to this role VMs
* @param p policy to place VMs respect to this role VMs
* @param requirements
*/
void role_requirements(Policy policy, std::string& requirements);
void role_requirements(VMGroupPolicy p, std::string& requirements);
private:
/**
@ -230,11 +224,6 @@ public:
return by_id.get(id);
}
/**
* Function to write a the roles in an output stream
*/
friend ostream& operator<<(ostream& os, VMGroupRoles& roles);
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/**

View File

@ -23,41 +23,40 @@
struct VMGroupRule_compare;
/**
* Placement policy rules for roles
* AFFINED: VMs of all roles are placed in the same hypervisor
* ANTI_AFFINED: VMs are placed in different hypervisors (role-wise)
* NONE: No additional placement constraints
*/
enum class VMGroupPolicy
{
NONE = 0x00,
AFFINED = 0x01,
ANTI_AFFINED= 0x02
};
std::ostream& operator<<(std::ostream& os, VMGroupPolicy policy);
/**
* A rule represents a role placement policy
*/
class VMGroupRule
{
public:
/**
* Placement policy rules for roles
* AFFINED: VMs of all roles are placed in the same hypervisor
* ANTI_AFFINED: VMs are placed in different hypervisors (role-wise)
* NONE: No additional placement constraints
*/
enum Policy
{
NONE = 0x00,
AFFINED = 0x01,
ANTI_AFFINED= 0x02
};
/**
* @return policy name
*/
static std::string policy_to_s(Policy policy);
/**
* A specialized set for rules
*/
typedef std::set<VMGroupRule, VMGroupRule_compare> rule_set;
typedef std::bitset<VMGroupRoles::MAX_ROLES> role_bitset;
/* ---------------------------------------------------------------------- */
/* Rule Constructors */
/* ---------------------------------------------------------------------- */
VMGroupRule():policy(NONE),roles(){};
VMGroupRule():policy(VMGroupPolicy::NONE),roles(){};
VMGroupRule(Policy p, std::set<int> roles_id):policy(p)
VMGroupRule(VMGroupPolicy p, std::set<int> roles_id):policy(p)
{
std::set<int>::iterator it;
@ -70,8 +69,7 @@ public:
}
};
VMGroupRule(Policy p, std::bitset<VMGroupRoles::MAX_ROLES> _roles)
:policy(p), roles(_roles){};
VMGroupRule(VMGroupPolicy p, role_bitset _roles):policy(p), roles(_roles){};
VMGroupRule(const VMGroupRule& other)
{
@ -138,21 +136,16 @@ public:
/**
* @return the roles in the rule as a bitset (1 roles is in)
*/
const std::bitset<VMGroupRoles::MAX_ROLES>& get_roles() const
const role_bitset& get_roles() const
{
return roles;
}
std::string get_policy() const
VMGroupPolicy get_policy() const
{
return policy_to_s(policy);
return policy;
}
/**
* Function to write a the rule in an output stream
*/
friend ostream& operator<<(ostream& os, const VMGroupRule& rule);
private:
friend class VMGroupRule_compare;
@ -160,7 +153,7 @@ private:
/**
* Type of the rule
*/
Policy policy;
VMGroupPolicy policy;
/**
* Roles participating in the rule

View File

@ -21,6 +21,8 @@
#include "VMGroupRole.h"
#include "VMGroupRule.h"
class VirtualMachinePoolXML;
class VMGroupXML : public ObjectXML
{
public:
@ -34,13 +36,29 @@ public:
init_attributes();
};
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
int get_oid() const
{
return oid;
};
const std::string& get_name() const
{
return name;
};
/**
* Dumps a Group, its roles and affinity rules to an output stream
*/
friend ostream& operator<<(ostream& os, VMGroupXML& vmg);
/**
* Adds the internal role placement rules to each VM in the role
* @params vmpool VM set of pending VMs
*/
void set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool);
private:
// ------------------------------------------------------------------------
// VMGroup Attributes
@ -53,6 +71,11 @@ private:
VMGroupRule::rule_set rules;
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Bootstrap VMGroup roles ans rules
*/
void init_attributes();
};

View File

@ -87,7 +87,7 @@ public:
/**
*
*
* */
*/
void clear()
{
flush();

View File

@ -60,7 +60,6 @@ public:
//--------------------------------------------------------------------------
// Get Methods for VirtualMachineXML class
//--------------------------------------------------------------------------
int get_oid() const
{
return oid;
@ -130,10 +129,29 @@ public:
return public_cloud;
};
/**
* 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;
}
}
//--------------------------------------------------------------------------
// Matched Resources Interface
//--------------------------------------------------------------------------
/**
* Adds a matching host if it is not equal to the actual one
* @param oid of the host

View File

@ -15,6 +15,7 @@
/* -------------------------------------------------------------------------- */
#include "VMGroupXML.h"
#include "VirtualMachinePoolXML.h"
#include <iomanip>
void VMGroupXML::init_attributes()
@ -47,7 +48,7 @@ void VMGroupXML::init_attributes()
roles.names_to_ids(*it, id_set);
VMGroupRule rule(VMGroupRule::AFFINED, id_set);
VMGroupRule rule(VMGroupPolicy::AFFINED, id_set);
rules.insert(rule);
}
@ -62,12 +63,145 @@ void VMGroupXML::init_attributes()
roles.names_to_ids(*it, id_set);
VMGroupRule rule(VMGroupRule::ANTI_AFFINED, id_set);
VMGroupRule rule(VMGroupPolicy::ANTI_AFFINED, id_set);
rules.insert(rule);
}
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool)
{
VMGroupRoles::role_iterator it;
std::ostringstream oss;
oss << "Placement rules for VMGroup " << get_name() << "\n";
oss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM"
<< " " << left << "ANTI_AFFINITY REQUIRMENTS\n"
<< setfill('-') << setw(80) << '-' << setfill(' ') << "\n";
/* ---------------------------------------------------------------------- */
/* Intra-role anti-affinity placement rule */
/* ---------------------------------------------------------------------- */
for ( it = roles.begin(); it != roles.end() ; ++it )
{
VMGroupRole * r = *it;
if ( r->policy() != VMGroupPolicy::ANTI_AFFINED || r->size_vms() <= 1 )
{
continue;
}
const std::set<int> vms = r->get_vms();
std::set<int>::const_iterator jt;
for ( jt = vms.begin() ; jt != vms.end(); ++jt )
{
std::string reqs;
VirtualMachineXML * vm = vmpool->get(*jt);
if ( vm == 0 )
{
continue;
}
r->vm_role_requirements(*jt, reqs);
if ( !reqs.empty() )
{
vm->add_requirements(reqs);
}
oss << left << setw(8) << r->id() << left << setw(8) << *jt << reqs
<< "\n";
}
}
oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n";
/* ---------------------------------------------------------------------- */
/* Inter-role anti-affinity placement rule */
/* ---------------------------------------------------------------------- */
VMGroupRule::rule_set::iterator rt;
for ( rt = rules.begin() ; rt != rules.end() ; ++rt )
{
if ( (*rt).get_policy() != VMGroupPolicy::ANTI_AFFINED )
{
continue;
}
VMGroupRule::role_bitset rroles = (*rt).get_roles();
for ( int i=0 ; i < VMGroupRoles::MAX_ROLES; ++i)
{
string role_reqs;
if ( rroles[i] == 0 )
{
continue;
}
for ( int j = 0 ; j < VMGroupRoles::MAX_ROLES ; ++j )
{
if ( j == i || rroles[j] == 0 )
{
continue;
}
VMGroupRole * r = roles.get(j);
std::string reqs;
r->role_requirements(VMGroupPolicy::ANTI_AFFINED, reqs);
if ( reqs.empty() )
{
continue;
}
if ( role_reqs.empty() )
{
role_reqs = reqs;
}
else
{
role_reqs += " & " + reqs;
}
}
VMGroupRole * r = roles.get(i);
const std::set<int> vms = r->get_vms();
std::set<int>::const_iterator vt;
for ( vt=vms.begin() ; vt!=vms.end(); ++vt )
{
VirtualMachineXML * vm = vmpool->get(*vt);
if ( vm == 0 )
{
continue;
}
vm->add_requirements(role_reqs);
oss << left << setw(8) << r->id() << left << setw(8) << *vt
<< role_reqs << "\n";
}
}
}
NebulaLog::log("VMGRP", Log::DEBUG, oss);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ostream& operator<<(ostream& os, VMGroupXML& vmg)
{
VMGroupRule::rule_set::iterator rit;
@ -77,7 +211,7 @@ ostream& operator<<(ostream& os, VMGroupXML& vmg)
<< left << setw(8) << vmg.name<< " "
<< left << setw(26)<< "ROLES" << "\n"
<< setfill(' ') << setw(14) << " " << setfill('-') << setw(26) << '-'
<< "\n";
<< setfill(' ') << "\n";
for ( it = vmg.roles.begin() ; it != vmg.roles.end() ; ++it )
{
@ -89,11 +223,11 @@ ostream& operator<<(ostream& os, VMGroupXML& vmg)
os << setfill(' ') << setw(14) << ' ' << left << "RULES" << "\n"
<< setfill(' ') << setw(14) << ' ' << setfill('-') << setw(26) << '-'
<< "\n";
<< setfill(' ') << "\n";
for ( rit = vmg.rules.begin() ; rit != vmg.rules.end(); ++rit )
{
const std::bitset<VMGroupRoles::MAX_ROLES>& rroles = (*rit).get_roles();
const VMGroupRule::role_bitset rroles = (*rit).get_roles();
os << setfill(' ') << setw(14) << ' ' << left << setw(14)
<< (*rit).get_policy() << " ";

View File

@ -1400,20 +1400,30 @@ void Scheduler::do_vm_groups()
map<int, ObjectXML*>::const_iterator it;
const map<int, ObjectXML*> vmgrps = vmgpool->get_objects();
ostringstream oss;
if (NebulaLog::log_level() >= Log::DDDEBUG)
{
ostringstream oss;
oss << "VMGroups\n"
<< left << setw(4)<< "ID" << " " << left << setw(8) << "NAME" << " "
<< "\n" << setfill('-') << setw(40) << '-' << setfill(' ') << "\n";
for (it = vmgrps.begin(); it != vmgrps.end() ; ++it)
{
VMGroupXML * grp = static_cast<VMGroupXML*>(it->second);
oss << *grp;
}
NebulaLog::log("VMGRP", Log::DDDEBUG, oss);
}
for (it = vmgrps.begin(); it != vmgrps.end() ; ++it)
{
oss << "\nVMGroups\n"
<< left << setw(4)<< "ID" << left << setw(8) << "NAME \n"
<< setfill('-') << setw(40) << '-' << setfill(' ') << "\n";
VMGroupXML * grp = static_cast<VMGroupXML*>(it->second);
oss << *grp;
grp->set_antiaffinity_requirements(vmpool);
}
NebulaLog::log("VMGRP", Log::DEBUG, oss);
}
/* -------------------------------------------------------------------------- */

View File

@ -224,12 +224,15 @@ error_common:
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VMGroup::check_rule_names(VMGroupRule::Policy policy, std::string& error)
int VMGroup::check_rule_names(VMGroupPolicy policy, std::string& error)
{
vector<const SingleAttribute *> affined;
vector<const SingleAttribute *>::const_iterator jt;
std::string aname = VMGroupRule::policy_to_s(policy);
std::ostringstream oss;
oss << policy;
std::string aname = oss.str();
obj_template->get(aname, affined);
@ -256,13 +259,16 @@ int VMGroup::check_rule_names(VMGroupRule::Policy policy, std::string& error)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VMGroup::get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules,
int VMGroup::get_rules(VMGroupPolicy policy, VMGroupRule::rule_set& rules,
std::string& error_str)
{
vector<const SingleAttribute *> affined;
vector<const SingleAttribute *>::const_iterator jt;
std::string aname = VMGroupRule::policy_to_s(policy);
std::ostringstream oss;
oss << policy;
std::string aname = oss.str();
obj_template->get(aname, affined);
@ -305,14 +311,14 @@ int VMGroup::check_rule_consistency(std::string& error)
VMGroupRule error_rule;
if ( get_rules(VMGroupRule::AFFINED, affined, error) == -1 )
if ( get_rules(VMGroupPolicy::AFFINED, affined, error) == -1 )
{
return -1;
}
for (it=affined.begin() ; it != affined.end(); ++it)
{
const std::bitset<VMGroupRoles::MAX_ROLES> rs = (*it).get_roles();
const VMGroupRule::role_bitset rs = (*it).get_roles();
for (int i = 0; i < VMGroupRoles::MAX_ROLES; ++i)
{
@ -320,7 +326,7 @@ int VMGroup::check_rule_consistency(std::string& error)
{
VMGroupRole * role = roles.get(i);
if ( role != 0 && role->policy() == VMGroupRole::ANTI_AFFINED )
if ( role != 0 && role->policy() == VMGroupPolicy::ANTI_AFFINED )
{
error = "Role " + role->name() + " is in an AFFINED rule "
"but the role policy is ANTI_AFFINED";
@ -331,7 +337,7 @@ int VMGroup::check_rule_consistency(std::string& error)
}
}
if ( get_rules(VMGroupRule::ANTI_AFFINED, anti, error) == -1 )
if ( get_rules(VMGroupPolicy::ANTI_AFFINED, anti, error) == -1 )
{
return -1;
}
@ -339,7 +345,7 @@ int VMGroup::check_rule_consistency(std::string& error)
if ( !VMGroupRule::compatible(affined, anti, error_rule) )
{
ostringstream oss;
const std::bitset<VMGroupRoles::MAX_ROLES> rs = error_rule.get_roles();
const VMGroupRule::role_bitset rs = error_rule.get_roles();
oss << "Roles defined in AFFINED and ANTI_AFFINED rules:";
@ -415,12 +421,12 @@ int VMGroup::insert(SqlDB *db, string& error_str)
return -1;
}
if ( check_rule_names(VMGroupRule::AFFINED, error_str) == -1 )
if ( check_rule_names(VMGroupPolicy::AFFINED, error_str) == -1 )
{
return -1;
}
if ( check_rule_names(VMGroupRule::ANTI_AFFINED, error_str) == -1 )
if ( check_rule_names(VMGroupPolicy::ANTI_AFFINED, error_str) == -1 )
{
return -1;
}
@ -457,12 +463,12 @@ int VMGroup::post_update_template(string& error)
obj_template->erase("ROLE");
if ( check_rule_names(VMGroupRule::AFFINED, error) == -1 )
if ( check_rule_names(VMGroupPolicy::AFFINED, error) == -1 )
{
return -1;
}
if ( check_rule_names(VMGroupRule::ANTI_AFFINED, error) == -1 )
if ( check_rule_names(VMGroupPolicy::ANTI_AFFINED, error) == -1 )
{
return -1;
}
@ -475,3 +481,5 @@ int VMGroup::post_update_template(string& error)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -15,6 +15,7 @@
/* -------------------------------------------------------------------------*/
#include "VMGroupRole.h"
#include "VMGroupRule.h"
#include <iomanip>
@ -37,21 +38,23 @@ VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
VMGroupRole::Policy VMGroupRole::policy()
VMGroupPolicy VMGroupRole::policy()
{
string p = va->vector_value("POLICY");
one_util::toupper(p);
if ( p == "AFFINED" )
{
return AFFINED;
return VMGroupPolicy::AFFINED;
}
else if ( p == "ANTI_AFFINED" )
{
return ANTI_AFFINED;
return VMGroupPolicy::ANTI_AFFINED;
}
else
{
return NONE;
return VMGroupPolicy::NONE;
}
}
@ -101,7 +104,7 @@ void VMGroupRole::set_vms()
/* -------------------------------------------------------------------------- */
static void affinity_requirements(int vm_id, std::string& requirements,
VMGroupRole::Policy policy, const std::set<int>& vms)
VMGroupPolicy policy, const std::set<int>& vms)
{
string op;
@ -109,28 +112,32 @@ static void affinity_requirements(int vm_id, std::string& requirements,
switch(policy)
{
case VMGroupRole::AFFINED:
case VMGroupPolicy::AFFINED:
op = "=";
break;
case VMGroupRole::ANTI_AFFINED:
case VMGroupPolicy::ANTI_AFFINED:
op = "!=";
break;
case VMGroupRole::NONE:
case VMGroupPolicy::NONE:
return;
}
std::ostringstream oss;
std::set<int>::const_iterator it;
bool first = true;
for ( it = vms.begin(); it != vms.end(); ++it )
{
if ( vm_id == -1 || vm_id != *it )
{
if ( it != vms.begin() )
if ( !first )
{
oss << " & ";
oss << "& ";
}
first = false;
oss << "( CURRENT_VMS " << op << " " << *it << ") ";
}
}
@ -143,9 +150,9 @@ void VMGroupRole::vm_role_requirements(int vm_id, std::string& requirements)
affinity_requirements(vm_id, requirements, policy(), vms);
}
void VMGroupRole::role_requirements(Policy policy, std::string& requirements)
void VMGroupRole::role_requirements(VMGroupPolicy pol, std::string& reqs)
{
affinity_requirements(-1, requirements, policy, vms);
affinity_requirements(-1, reqs, pol, vms);
}
/* -------------------------------------------------------------------------- */
@ -332,20 +339,3 @@ int VMGroupRoles::names_to_ids(const std::string& rnames, std::set<int>& keyi)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ostream& operator<<(ostream& os, VMGroupRoles& roles)
{
VMGroupRoles::role_iterator it;
for ( it = roles.begin() ; it != roles.end() ; ++it )
{
os << right << setw(3) << (*it)->id() << " "
<< right << setw(12) << (*it)->name() << " "
<< right << setw(12) << (*it)->policy_s() << "\n";
}
return os;
}

View File

@ -48,48 +48,23 @@ bool VMGroupRule::compatible(VMGroupRule::rule_set& affined,
return err.none();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
std::string VMGroupRule::policy_to_s(Policy policy)
std::ostream& operator<<(std::ostream& os, VMGroupPolicy policy)
{
std::string name;
switch(policy)
{
case AFFINED:
name="AFFINED";
case VMGroupPolicy::AFFINED:
os << "AFFINED";
break;
case ANTI_AFFINED:
name="ANTI_AFFINED";
case VMGroupPolicy::ANTI_AFFINED:
os << "ANTI_AFFINED";
break;
case NONE:
name="NONE";
case VMGroupPolicy::NONE:
os << "NONE";
break;
}
return name;
}
/* -------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
ostream& operator<<(ostream& os, const VMGroupRule& rule)
{
os << right << setw(14) << VMGroupRule::policy_to_s(rule.policy) << " ";
for (int i = 0 ; i <VMGroupRoles::MAX_ROLES ; ++i)
{
if ( rule.roles[i] == 1 )
{
os << right << setw(3) << i << " ";
}
}
os << '\n';
return os;
}