diff --git a/include/VMGroup.h b/include/VMGroup.h index 4487239a10..786335e081 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -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); diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 3a44abb4c0..8088adf561 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -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); - /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /** diff --git a/include/VMGroupRule.h b/include/VMGroupRule.h index d434062222..e678b0faa9 100644 --- a/include/VMGroupRule.h +++ b/include/VMGroupRule.h @@ -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 rule_set; + typedef std::bitset role_bitset; + /* ---------------------------------------------------------------------- */ /* Rule Constructors */ /* ---------------------------------------------------------------------- */ - VMGroupRule():policy(NONE),roles(){}; + VMGroupRule():policy(VMGroupPolicy::NONE),roles(){}; - VMGroupRule(Policy p, std::set roles_id):policy(p) + VMGroupRule(VMGroupPolicy p, std::set roles_id):policy(p) { std::set::iterator it; @@ -70,8 +69,7 @@ public: } }; - VMGroupRule(Policy p, std::bitset _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& 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 diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index 45843ef16d..b1084cd20f 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -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(); }; diff --git a/src/scheduler/include/VirtualMachinePoolXML.h b/src/scheduler/include/VirtualMachinePoolXML.h index 1001fa8eb2..14ce5b42df 100644 --- a/src/scheduler/include/VirtualMachinePoolXML.h +++ b/src/scheduler/include/VirtualMachinePoolXML.h @@ -87,7 +87,7 @@ public: /** * * - * */ + */ void clear() { flush(); diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index c8978b0ebb..374afda904 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -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 diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 7fd37f03d7..967d2ee661 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -15,6 +15,7 @@ /* -------------------------------------------------------------------------- */ #include "VMGroupXML.h" +#include "VirtualMachinePoolXML.h" #include 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 vms = r->get_vms(); + std::set::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 vms = r->get_vms(); + std::set::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& rroles = (*rit).get_roles(); + const VMGroupRule::role_bitset rroles = (*rit).get_roles(); os << setfill(' ') << setw(14) << ' ' << left << setw(14) << (*rit).get_policy() << " "; diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 11844867b7..1906295ffe 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -1400,20 +1400,30 @@ void Scheduler::do_vm_groups() map::const_iterator it; const map 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(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(it->second); - oss << *grp; + grp->set_antiaffinity_requirements(vmpool); } - - NebulaLog::log("VMGRP", Log::DEBUG, oss); } /* -------------------------------------------------------------------------- */ diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 68d22e1cd2..50d0a9d49f 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -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 affined; vector::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 affined; vector::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 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 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; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index afc9d6ea8e..01e865a5f0 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -15,6 +15,7 @@ /* -------------------------------------------------------------------------*/ #include "VMGroupRole.h" +#include "VMGroupRule.h" #include @@ -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& vms) + VMGroupPolicy policy, const std::set& 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::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& 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; -} - diff --git a/src/vm_group/VMGroupRule.cc b/src/vm_group/VMGroupRule.cc index 03b1643cfb..a627520d54 100644 --- a/src/vm_group/VMGroupRule.cc +++ b/src/vm_group/VMGroupRule.cc @@ -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