diff --git a/include/VMGroup.h b/include/VMGroup.h index 663179bea1..4487239a10 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -38,13 +38,13 @@ class VMGroupPool; * ] * * ROLE = [ - * NAME = "db", - * ID = 1, + * NAME = "db", + * ID = 1, * POLICY = ANTI_AFFINED, - * VMS = "2,3,4,5" + * VMS = "2,3,4,5" * ] * - * ANTI_AFFINED = "db", "front_end" + * ANTI_AFFINED = "db, front_end" */ class VMGroup : public PoolObjectSQL { @@ -117,16 +117,25 @@ private: // Role Management // ------------------------------------------------------------------------- /** - * Check if all the roles are defined in the group - * @param aname attribute with a list (comma-separated) of role names + * Check if all the roles in a AFFINED/ANTI_AFFINED rules are defined in + * the group + * @param policy attribute with a list (comma-separated) of role names * @param error_str if any * * @return 0 if all roles are defined -1 otherwise */ - int check_rule_names(const std::string& aname, std::string& error_str); + int check_rule_names(VMGroupRule::Policy policy, std::string& error_str); - int get_rules(const std::string& aname, VMGroupRule::Policy policy, - VMGroupRule::rule_set& rules, 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 + * + * @return 0 if success -1 otherwise + */ + int get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules, + std::string& error_str); int check_rule_consistency(std::string& error); diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index c029da52f6..4928acbc42 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -66,6 +66,32 @@ public: return rid; } + /** + * @return the role name + */ + std::string name() + { + return va->vector_value("NAME"); + } + + Policy policy() + { + string p = va->vector_value("POLICY"); + + if ( p == "AFFINED" ) + { + return AFFINED; + } + else if ( p == "ANTI_AFFINED" ) + { + return ANTI_AFFINED; + } + else + { + return NONE; + } + } + /* ---------------------------------------------------------------------- */ /* VMS set Interface */ /* ---------------------------------------------------------------------- */ @@ -176,6 +202,24 @@ public: */ int vm_size(); + /** + * @return the a VMGroupRole by its name + * @param rname role name + */ + VMGroupRole * get(const std::string& rname) + { + return by_name.get(rname); + } + + /** + * @return the a VMGroupRole by its id + * @param rname role name + */ + VMGroupRole * get(int id) + { + return by_id.get(id); + } + /** * Max number of roles in a VMGroup */ diff --git a/include/VMGroupRule.h b/include/VMGroupRule.h index a7e07e9f5f..5bdb0840c5 100644 --- a/include/VMGroupRule.h +++ b/include/VMGroupRule.h @@ -29,6 +29,13 @@ struct VMGroupRule_compare; 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, @@ -36,9 +43,40 @@ public: ANTI_AFFINED= 0x02 }; - /* ---------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- */ + /** + * @return policy name + */ + static std::string policy_to_s(Policy policy) + { + std::string name; + + switch(policy) + { + case AFFINED: + name="AFFINED"; + break; + + case ANTI_AFFINED: + name="ANTI_AFFINED"; + break; + + case NONE: + name="NONE"; + break; + } + + return name; + } + + /** + * A specialized set for rules + */ + typedef std::set rule_set; + + /* ---------------------------------------------------------------------- */ + /* Rule Constructors */ + /* ---------------------------------------------------------------------- */ VMGroupRule():policy(NONE),roles(){}; VMGroupRule(Policy p, std::set roles_id):policy(p) @@ -64,13 +102,8 @@ public: } /* ---------------------------------------------------------------------- */ + /* Rule operators */ /* ---------------------------------------------------------------------- */ - - typedef std::set rule_set; - - /* ---------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- */ - VMGroupRule& operator=(const VMGroupRule& other) { if ( this != &other ) @@ -109,8 +142,29 @@ public: return roles.none(); } + /* ---------------------------------------------------------------------- */ + /* Rule interface */ + /* ---------------------------------------------------------------------- */ + /** + * Check if an affined and anti-affined rule set are compatible. Sets are + * compatible if there isn't a role in the affined and anti-affined sets + * at the same time + * @param affined rule set + * @param anti affined rule set + * @param err a rule with the roles in both sets + * + * @return true if sets are compatible + */ static bool compatible(rule_set& affined, rule_set& anti, VMGroupRule& err); + /** + * @return the roles in the rule as a bitset (1 roles is in) + */ + const std::bitset& get_roles() const + { + return roles; + } + private: friend class VMGroupRule_compare; @@ -126,6 +180,10 @@ private: std::bitset roles; }; +/** + * Functor to compre two rules. Two rules are considered equivalent if the + * include the same roles. + */ struct VMGroupRule_compare { bool operator() (const VMGroupRule& lhs, const VMGroupRule& rhs) const diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 205dd7a497..0b411bdacb 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -479,11 +479,13 @@ error_common: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VMGroup::check_rule_names(const std::string& aname, std::string& error_str) +int VMGroup::check_rule_names(VMGroupRule::Policy policy, std::string& error) { vector affined; vector::const_iterator jt; + std::string aname = VMGroupRule::policy_to_s(policy); + obj_template->get(aname, affined); for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) @@ -506,7 +508,7 @@ int VMGroup::check_rule_names(const std::string& aname, std::string& error_str) oss << "Some roles used in " << aname << " attribute (" << (*jt)->value() << ") are not defined"; - error_str = oss.str(); + error = oss.str(); return -1; } } @@ -517,12 +519,14 @@ int VMGroup::check_rule_names(const std::string& aname, std::string& error_str) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VMGroup::get_rules(const std::string& aname, VMGroupRule::Policy policy, - VMGroupRule::rule_set& rules, std::string& error_str) +int VMGroup::get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules, + std::string& error_str) { vector affined; vector::const_iterator jt; + std::string aname = VMGroupRule::policy_to_s(policy); + obj_template->get(aname, affined); for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) @@ -566,22 +570,62 @@ int VMGroup::check_rule_consistency(std::string& error) { VMGroupRule::rule_set affined, anti; + VMGroupRule::rule_set::iterator it; + VMGroupRule error_rule; - if ( get_rules("AFFINED", VMGroupRule::AFFINED, affined, error) == -1 ) + if ( get_rules(VMGroupRule::AFFINED, affined, error) == -1 ) { return -1; } - if ( get_rules("ANTI_AFFINED", VMGroupRule::ANTI_AFFINED, anti, error) == -1 ) + for (it=affined.begin() ; it != affined.end(); ++it) + { + const std::bitset rs = (*it).get_roles(); + + for (int i = 0; i < VMGroupRoles::MAX_ROLES; ++i) + { + if ( rs[i] == 1 ) + { + VMGroupRole * role = roles.get(i); + + if ( role != 0 && role->policy() == VMGroupRole::ANTI_AFFINED ) + { + error = "Role " + role->name() + " is in an AFFINED rule " + "but the role policy is ANTI_AFFINED"; + + return -1; + } + } + } + } + + if ( get_rules(VMGroupRule::ANTI_AFFINED, anti, error) == -1 ) { return -1; } if ( !VMGroupRule::compatible(affined, anti, error_rule) ) { - error = "Some roles are defined in AFFINED and ANTI_AFFINED at the same" - " time"; + ostringstream oss; + const std::bitset rs = error_rule.get_roles(); + + oss << "Roles defined in AFFINED and ANTI_AFFINED rules:"; + + for (int i = 0; i < VMGroupRoles::MAX_ROLES; ++i) + { + if ( rs[i] == 1 ) + { + VMGroupRole * role = roles.get(i); + + if ( role != 0 ) + { + oss << " " << role->name(); + } + } + } + + error = oss.str(); return -1; } @@ -640,12 +684,17 @@ int VMGroup::insert(SqlDB *db, string& error_str) return -1; } - if ( check_rule_names("AFFINED", error_str) == -1 ) + if ( check_rule_names(VMGroupRule::AFFINED, error_str) == -1 ) { return -1; } - if ( check_rule_names("ANTI_AFFINED", error_str) == -1 ) + if ( check_rule_names(VMGroupRule::ANTI_AFFINED, error_str) == -1 ) + { + return -1; + } + + if ( check_rule_consistency(error_str) == -1 ) { return -1; } @@ -677,12 +726,17 @@ int VMGroup::post_update_template(string& error) obj_template->erase("ROLE"); - if ( check_rule_names("AFFINED", error) == -1 ) + if ( check_rule_names(VMGroupRule::AFFINED, error) == -1 ) { return -1; } - if ( check_rule_names("ANTI_AFFINED", error) == -1 ) + if ( check_rule_names(VMGroupRule::ANTI_AFFINED, error) == -1 ) + { + return -1; + } + + if ( check_rule_consistency(error) == -1 ) { return -1; }