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

F #2347: Add placement rules consistency checks

This commit is contained in:
Ruben S. Montero 2017-01-13 18:32:37 +01:00
parent 97c5fcd2f2
commit b2f15970c9
4 changed files with 194 additions and 29 deletions

View File

@ -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);

View File

@ -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
*/

View File

@ -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<VMGroupRule, VMGroupRule_compare> rule_set;
/* ---------------------------------------------------------------------- */
/* Rule Constructors */
/* ---------------------------------------------------------------------- */
VMGroupRule():policy(NONE),roles(){};
VMGroupRule(Policy p, std::set<int> roles_id):policy(p)
@ -64,13 +102,8 @@ public:
}
/* ---------------------------------------------------------------------- */
/* Rule operators */
/* ---------------------------------------------------------------------- */
typedef std::set<VMGroupRule, VMGroupRule_compare> 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<VMGroupRoles::MAX_ROLES>& get_roles() const
{
return roles;
}
private:
friend class VMGroupRule_compare;
@ -126,6 +180,10 @@ private:
std::bitset<VMGroupRoles::MAX_ROLES> 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

View File

@ -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<const SingleAttribute *> affined;
vector<const SingleAttribute *>::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<const SingleAttribute *> affined;
vector<const SingleAttribute *>::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<VMGroupRoles::MAX_ROLES> 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<VMGroupRoles::MAX_ROLES> 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;
}