1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-11 05:17:41 +03:00

F #2347: VMGroupRule class. Methods to check rule consistency

This commit is contained in:
Ruben S. Montero 2017-01-13 01:56:25 +01:00
parent a1c1dee188
commit 97c5fcd2f2
5 changed files with 353 additions and 50 deletions

View File

@ -19,6 +19,7 @@
#include "PoolObjectSQL.h" #include "PoolObjectSQL.h"
#include "VMGroupRole.h" #include "VMGroupRole.h"
#include "VMGroupRule.h"
class VMGroupPool; class VMGroupPool;
@ -39,6 +40,7 @@ class VMGroupPool;
* ROLE = [ * ROLE = [
* NAME = "db", * NAME = "db",
* ID = 1, * ID = 1,
* POLICY = ANTI_AFFINED,
* VMS = "2,3,4,5" * VMS = "2,3,4,5"
* ] * ]
* *
@ -121,7 +123,12 @@ private:
* *
* @return 0 if all roles are defined -1 otherwise * @return 0 if all roles are defined -1 otherwise
*/ */
int check_affinity(const std::string& aname, std::string& error_str); int check_rule_names(const std::string& aname, std::string& error_str);
int get_rules(const std::string& aname, VMGroupRule::Policy policy,
VMGroupRule::rule_set& rules, std::string& error_str);
int check_rule_consistency(std::string& error);
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// DataBase implementation // DataBase implementation

View File

@ -29,6 +29,7 @@ class VMGroupPool;
* ROLE = [ * ROLE = [
* NAME = "Web application servers", * NAME = "Web application servers",
* ID = 12, * ID = 12,
* POLICY = AFFINED,
* VMS = "1,2,45,21" * VMS = "1,2,45,21"
* ] * ]
* *
@ -36,10 +37,35 @@ class VMGroupPool;
class VMGroupRole class VMGroupRole
{ {
public: public:
/**
* Scheduling policy for the VMs within this role
*/
enum Policy
{
NONE = 0x00,
AFFINED = 0x01,
ANTI_AFFINED= 0x02
};
/* ---------------------------------------------------------------------- */
VMGroupRole(VectorAttribute *_va); VMGroupRole(VectorAttribute *_va);
virtual ~VMGroupRole(){}; virtual ~VMGroupRole(){};
/**
* @return the role id
*/
int id()
{
int rid;
va->vector_value("ID", rid);
return rid;
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* VMS set Interface */ /* VMS set Interface */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -52,6 +78,17 @@ public:
void del_vm(int vm_id); void del_vm(int vm_id);
/* ---------------------------------------------------------------------- */
/* Placement constraints */
/* ---------------------------------------------------------------------- */
/**
* Generates a string with the boolean expresion to conform the role
* policy
* @param vm_id of the VM to generate the requirements for
* @param requirements
*/
void vm_requirements(int vm_id, std::string requirements);
private: private:
/** /**
* The set of vms in the role * The set of vms in the role
@ -109,14 +146,12 @@ public:
int add_role(VectorAttribute * vrole, string& error); int add_role(VectorAttribute * vrole, string& error);
/** /**
* Check that a key list is defined in the name map * Generates the ids corresponding to a set of role names
* @param key_str separated list of keys * @param keys the set of names
* @param true if the keys are in the map * @param keyi the set of ids
* @return 0 if all the names were successfully translated
*/ */
bool in_map(const std::string& key_str) int names_to_ids(const std::set<std::string> keys, std::set<int>& keyi);
{
return by_name.in_map(key_str);
}
/** /**
* Adds a VM to a role * Adds a VM to a role
@ -141,6 +176,11 @@ public:
*/ */
int vm_size(); int vm_size();
/**
* Max number of roles in a VMGroup
*/
const static int MAX_ROLES = 32;
private: private:
/** /**
* A role map indexed by different key types * A role map indexed by different key types
@ -205,36 +245,6 @@ private:
return roles.erase(k); return roles.erase(k);
} }
/**
* Check id a set of keys are in the map.
* @param key_str a comma separated list of keys
* @return true if all the keys are in the map
*/
bool in_map(const string& key_str)
{
std::set<T> key_set;
typename std::set<T>::iterator it;
one_util::split_unique(key_str, ',', key_set);
if ( key_set.empty() )
{
return true;
}
for ( it = key_set.begin(); it != key_set.end() ; ++it )
{
string rname = one_util::trim(*it);
if ( roles.find(rname) == roles.end() )
{
return false;
}
}
return true;
}
/** /**
* Iterators for the map * Iterators for the map
*/ */

138
include/VMGroupRule.h Normal file
View File

@ -0,0 +1,138 @@
/* ------------------------------------------------------------------------ */
/* Copyright 2002-2016, 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. */
/* -------------------------------------------------------------------------*/
#ifndef VMGROUP_RULE_H_
#define VMGROUP_RULE_H_
#include <bitset>
#include "VMGroupRole.h"
struct VMGroupRule_compare;
/**
* A rule represents a role placement policy
*/
class VMGroupRule
{
public:
enum Policy
{
NONE = 0x00,
AFFINED = 0x01,
ANTI_AFFINED= 0x02
};
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
VMGroupRule():policy(NONE),roles(){};
VMGroupRule(Policy p, std::set<int> roles_id):policy(p)
{
std::set<int>::iterator it;
for ( it = roles_id.begin(); it != roles_id.end(); ++it )
{
if ( *it < VMGroupRoles::MAX_ROLES )
{
roles[*it] = 1;
}
}
};
VMGroupRule(Policy p, std::bitset<VMGroupRoles::MAX_ROLES> _roles)
:policy(p), roles(_roles){};
VMGroupRule(const VMGroupRule& other)
{
policy = other.policy;
roles = other.roles;
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
typedef std::set<VMGroupRule, VMGroupRule_compare> rule_set;
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
VMGroupRule& operator=(const VMGroupRule& other)
{
if ( this != &other )
{
policy = other.policy;
roles = other.roles;
}
return *this;
}
VMGroupRule& operator&= (const VMGroupRule& other)
{
roles &= other.roles;
return *this;
}
VMGroupRule operator& (const VMGroupRule& other)
{
return VMGroupRule(policy, other.roles & roles );
}
VMGroupRule& operator|= (const VMGroupRule& other)
{
roles |= other.roles;
return *this;
}
VMGroupRule operator| (const VMGroupRule& other)
{
return VMGroupRule(policy, other.roles | roles );
}
bool none()
{
return roles.none();
}
static bool compatible(rule_set& affined, rule_set& anti, VMGroupRule& err);
private:
friend class VMGroupRule_compare;
/**
* Type of the rule
*/
Policy policy;
/**
* Roles participating in the rule
*/
std::bitset<VMGroupRoles::MAX_ROLES> roles;
};
struct VMGroupRule_compare
{
bool operator() (const VMGroupRule& lhs, const VMGroupRule& rhs) const
{
return lhs.roles.to_ullong() < rhs.roles.to_ullong();
}
};
#endif /*VMGROUP_RULE_H_*/

View File

@ -16,6 +16,35 @@
#include "VMGroup.h" #include "VMGroup.h"
#include "VMGroupRole.h" #include "VMGroupRole.h"
#include "VMGroupRule.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* VMGroupRule */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool VMGroupRule::compatible(VMGroupRule::rule_set& affined,
VMGroupRule::rule_set& anti, VMGroupRule& err)
{
VMGroupRule ta, taa;
rule_set::iterator it;
for (it=affined.begin() ; it != affined.end(); ++it)
{
ta |= *it;
}
for (it=anti.begin() ; it != anti.end(); ++it)
{
taa |= *it;
}
err = ta & taa;
return err.none();
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -220,6 +249,30 @@ int VMGroupRoles::vm_size()
return total; return total;
} }
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VMGroupRoles::names_to_ids(const std::set<std::string> keys,
std::set<int>& keyi)
{
std::set<std::string>::iterator it;
for ( it = keys.begin(); it != keys.end(); ++it )
{
VMGroupRole *r = by_name.get(*it);
if ( r == 0 )
{
keyi.clear();
return -1;
}
keyi.insert(r->id());
}
return 0;
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* VMGroup */ /* VMGroup */
@ -426,7 +479,7 @@ error_common:
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int VMGroup::check_affinity(const std::string& aname, std::string& error_str) int VMGroup::check_rule_names(const std::string& aname, std::string& error_str)
{ {
vector<const SingleAttribute *> affined; vector<const SingleAttribute *> affined;
vector<const SingleAttribute *>::const_iterator jt; vector<const SingleAttribute *>::const_iterator jt;
@ -435,13 +488,23 @@ int VMGroup::check_affinity(const std::string& aname, std::string& error_str)
for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) for ( jt = affined.begin() ; jt != affined.end() ; ++jt )
{ {
std::string a_str = (*jt)->value(); std::set<std::string> a_set, key_set;
std::set<std::string>::iterator s_it;
if ( !roles.in_map(a_str) ) std::set<int> id_set;
one_util::split_unique((*jt)->value(), ',', a_set);
for (s_it = a_set.begin(); s_it != a_set.end() ; ++s_it)
{
key_set.insert(one_util::trim(*s_it));
}
if ( roles.names_to_ids(key_set, id_set) != 0 )
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "Some roles used in " << aname << " attribute (" << a_str oss << "Some roles used in " << aname << " attribute ("
<< ") are not defined"; << (*jt)->value() << ") are not defined";
error_str = oss.str(); error_str = oss.str();
return -1; return -1;
@ -451,6 +514,81 @@ int VMGroup::check_affinity(const std::string& aname, std::string& error_str)
return 0; return 0;
} }
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VMGroup::get_rules(const std::string& aname, VMGroupRule::Policy policy,
VMGroupRule::rule_set& rules, std::string& error_str)
{
vector<const SingleAttribute *> affined;
vector<const SingleAttribute *>::const_iterator jt;
obj_template->get(aname, affined);
for ( jt = affined.begin() ; jt != affined.end() ; ++jt )
{
std::set<std::string> a_set, key_set;
std::set<std::string>::iterator s_it;
std::set<int> id_set;
std::pair<std::set<VMGroupRule>::iterator, bool> rc;
one_util::split_unique((*jt)->value(), ',', a_set);
for (s_it = a_set.begin(); s_it != a_set.end() ; ++s_it)
{
key_set.insert(one_util::trim(*s_it));
}
roles.names_to_ids(key_set, id_set);
VMGroupRule rule(policy, id_set);
rc = rules.insert(rule);
if ( rc.second == false )
{
error_str = "Duplicated " + aname + " rule (" +
(*jt)->value() + ") detected.";
return -1;
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VMGroup::check_rule_consistency(std::string& error)
{
VMGroupRule::rule_set affined, anti;
VMGroupRule error_rule;
if ( get_rules("AFFINED", VMGroupRule::AFFINED, affined, error) == -1 )
{
return -1;
}
if ( get_rules("ANTI_AFFINED", 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";
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int VMGroup::insert(SqlDB *db, string& error_str) int VMGroup::insert(SqlDB *db, string& error_str)
@ -466,7 +604,17 @@ int VMGroup::insert(SqlDB *db, string& error_str)
return -1; return -1;
} }
obj_template->remove("ROLE", va_roles); int num_role = obj_template->remove("ROLE", va_roles);
if ( num_role > VMGroupRoles::MAX_ROLES )
{
for ( it = va_roles.begin(); it != va_roles.end(); ++it )
{
delete *it;
}
error_str = "Maximum number of roles in a VM Group reached";
}
bool error = false; bool error = false;
@ -492,12 +640,12 @@ int VMGroup::insert(SqlDB *db, string& error_str)
return -1; return -1;
} }
if ( check_affinity("AFFINED", error_str) == -1 ) if ( check_rule_names("AFFINED", error_str) == -1 )
{ {
return -1; return -1;
} }
if ( check_affinity("ANTI_AFFINED", error_str) == -1 ) if ( check_rule_names("ANTI_AFFINED", error_str) == -1 )
{ {
return -1; return -1;
} }
@ -529,12 +677,12 @@ int VMGroup::post_update_template(string& error)
obj_template->erase("ROLE"); obj_template->erase("ROLE");
if ( check_affinity("AFFINED", error) == -1 ) if ( check_rule_names("AFFINED", error) == -1 )
{ {
return -1; return -1;
} }
if ( check_affinity("ANTI_AFFINED", error) == -1 ) if ( check_rule_names("ANTI_AFFINED", error) == -1 )
{ {
return -1; return -1;
} }