From 7381aa40304a82e864f3970c976e9086e8b3f369 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 2 Jan 2017 16:43:44 +0100 Subject: [PATCH 01/26] F #2347: VMGroup base classes, intial version --- SConstruct | 2 + include/PoolObjectSQL.h | 3 +- include/VMGroup.h | 310 +++++++++++++++++++++++++++ include/VMGroupPool.h | 123 +++++++++++ src/secgroup/SecurityGroup.cc | 2 + src/vm_group/SConstruct | 30 +++ src/vm_group/VMGroup.cc | 387 ++++++++++++++++++++++++++++++++++ 7 files changed, 856 insertions(+), 1 deletion(-) create mode 100644 include/VMGroup.h create mode 100644 include/VMGroupPool.h create mode 100644 src/vm_group/SConstruct create mode 100644 src/vm_group/VMGroup.cc diff --git a/SConstruct b/SConstruct index 5e4b36d856..4fdb6182ac 100644 --- a/SConstruct +++ b/SConstruct @@ -65,6 +65,7 @@ main_env.Append(LIBPATH=[ cwd+'/src/pool', cwd+'/src/template', cwd+'/src/vm', + cwd+'/src/vm_group', cwd+'/src/vm_template', cwd+'/src/vmm', cwd+'/src/lcm', @@ -221,6 +222,7 @@ build_scripts=[ 'src/nebula/SConstruct', 'src/pool/SConstruct', 'src/vm/SConstruct', + 'src/vm_group/SConstruct', 'src/vm_template/SConstruct', 'src/vmm/SConstruct', 'src/lcm/SConstruct', diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index dd47343abf..49c3927575 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -66,7 +66,8 @@ public: VDC = 0x0002000000000000LL, VROUTER = 0x0004000000000000LL, MARKETPLACE = 0x0008000000000000LL, - MARKETPLACEAPP = 0x0010000000000000LL + MARKETPLACEAPP = 0x0010000000000000LL, + VMGROUP = 0x0020000000000000LL }; static string type_to_str(ObjectType ob) diff --git a/include/VMGroup.h b/include/VMGroup.h new file mode 100644 index 0000000000..6c6d729813 --- /dev/null +++ b/include/VMGroup.h @@ -0,0 +1,310 @@ +/* ------------------------------------------------------------------------ */ +/* 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_H_ +#define VMGROUP_H_ + +#include "PoolObjectSQL.h" + +class VMGroupPool; + +/** + * A VMGroupRole defines a VM type that typically implements a role in a + * multi-vm application. + * + * ROLE = [ + * NAME = "Web application servers", + * ID = 12, + * VMS = "1,2,45,21" + * ] + * + */ +class VMGroupRole +{ +public: + VMGroupRole(VectorAttribute *_va); + + virtual ~VMGroupRole(){}; + + /* ---------------------------------------------------------------------- */ + /* VMS set Interface */ + /* ---------------------------------------------------------------------- */ + const std::set& get_vms() + { + return vms; + }; + + void add_vm(int vm_id); + + void del_vm(int vm_id); + +private: + /** + * The set of vms in the role + */ + std::set vms; + + /** + * The associated vector attribute + */ + VectorAttribute * va; + + /** + * Set the VMS attribute for the role (list of VM IDs) + */ + void set_vms(); +}; + +/** + * A VM group is a set of related VMs that may impose placement constraints. + * + * Data model: + * + * NAME = "Web server" + * DESCRIPTION = "A multi-tier web server: frontend, apps servers, db" + * + * ROLE = [ + * NAME = "frontend", + * ID = 0, + * VMS = "0,1" + * ] + * + * ROLE = [ + * NAME = "db", + * ID = 1, + * VMS = "2,3,4,5" + * ] + * + * ANTI_AFFINED = "db", "front_end" + */ +class VMGroup : public PoolObjectSQL +{ +public: + /** + * Function to print the VMGroup object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + + /** + * Returns a copy of the Template + * @return A copy of the Template + */ + Template * clone_template() const + { + return new Template(*obj_template); + }; + +private: + // ------------------------------------------------------------------------- + // Friends + // ------------------------------------------------------------------------- + friend class VMGroupPool; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + VMGroup(int _uid, int _gid, const string& _uname, const string& _gname, + int _umask, Template * group_template); + + ~VMGroup(); + + // ------------------------------------------------------------------------- + // Role Map management + // ------------------------------------------------------------------------- + /** + * A role map indexed by different key types + */ + template + class RoleMap + { + public: + /** + * Inserts a new role in the map + * @param k the key + * @param r pointer to yhe VMGroupRole + * @return true if the role was successfully inserted + */ + bool insert(const T& k, VMGroupRole * r) + { + std::pair rpair(k, r); + std::pair rc; + + rc = roles.insert(rpair); + + return rc.second; + } + + /** + * Frees the memory associated to the map and clears it + */ + void delete_roles() + { + for (roles_it it = roles.begin() ; it != roles.end() ; ++it ) + { + delete it->second; + } + + clear(); + } + + /** + * Clears the contents of the map + */ + void clear() + { + roles.clear(); + } + + size_t erase(const T& 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 key_set; + typename std::set::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 ) + { + if ( roles.find(*it) == roles.end() ) + { + return false; + } + } + + return true; + } + + private: + typedef typename std::map::iterator roles_it; + + std::map roles; + }; + + /** + * Add a new role to the VM group + * @param role to add as a vector attribute + * @param error if any + * + * @return 0 on success + */ + int add_role(VectorAttribute * vrole, string& error); + + // ------------------------------------------------------------------------- + // DataBase implementation + // ------------------------------------------------------------------------- + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Execute an INSERT or REPLACE Sql query. + * @param db The SQL DB + * @param replace Execute an INSERT or a REPLACE + * @param error_str Returns the error reason, if any + * @return 0 one success + */ + int insert_replace(SqlDB *db, bool replace, string& error_str); + + /** + * Bootstraps the database table(s) associated to the VMGroup + * @return 0 on success + */ + static int bootstrap(SqlDB * db) + { + ostringstream oss(VMGroup::db_bootstrap); + + return db->exec(oss); + }; + + /** + * Writes the VMGroup in the database. + * @param db pointer to the db + * @return 0 on success + */ + int insert(SqlDB *db, string& error_str); + + /** + * Writes/updates the VMGroup's data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + int update(SqlDB *db) + { + string error_str; + return insert_replace(db, true, error_str); + } + + /** + * Checks the new roles and affined/anti-affined cross-references + * @param error string describing the error if any + * @return 0 on success + */ + int post_update_template(string& error); + + /** + * Factory method for VMGroup templates + */ + Template * get_new_template() const + { + return new Template; + } + + // ------------------------------------------------------------------------- + // VMGroup attributes + // ------------------------------------------------------------------------- + /** + * Name of the VM Group + */ + std::string name; + + /** + * Map to access the roles by their name + */ + RoleMap by_name; + + /** + * Map to access the roles by their id + */ + RoleMap by_id; +}; + +#endif /*SECURITYGROUP_H_*/ + diff --git a/include/VMGroupPool.h b/include/VMGroupPool.h new file mode 100644 index 0000000000..51f471e4d0 --- /dev/null +++ b/include/VMGroupPool.h @@ -0,0 +1,123 @@ +/* -------------------------------------------------------------------------- */ +/* 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_POOL_H_ +#define VMGROUP_POOL_H_ + +#include "PoolSQL.h" +#include "VMGroup.h" + +class VMGroupPool : public PoolSQL +{ +public: + VMGroupPool(SqlDB * db):PoolSQL(db, VMGroup::table, true, true){}; + + ~VMGroupPool(){}; + + /* ---------------------------------------------------------------------- */ + /* Methods for DB management */ + /* ---------------------------------------------------------------------- */ + /** + * Allocates a new VMGroup, writing it in the pool database. No memory is + * allocated for the object. + * + * @param uid user identifier + * @param gid the id of the group this object is assigned to + * @param uname user name + * @param gname group name + * @param umask permissions umask + * @param vmgroup_template a Template object + * @param oid the id assigned to the new VMGroup + * @param error_str Returns the error reason, if any + * + * @return the oid assigned to the object, -1 in case of failure + */ + int allocate(int uid, int gid, const std::string& uname, + const std::string& gname, int umask, Template * vmgrp_tmpl, int * oid, + std::string& error_str); + + /** + * Function to get a VMGroup from the pool, if the object is not in memory + * it is loaded from the DB + * @param oid VMGroup unique id + * @param lock locks the VMGroup mutex + * @return a pointer to the VMGroup, 0 if the VMGroup could not be loaded + */ + VMGroup * get(int oid, bool lock) + { + return static_cast(PoolSQL::get(oid, lock)); + }; + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param uid id of owner + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + VMGroup * get(const std::string& name, int uid, bool lock) + { + return static_cast(PoolSQL::get(name, uid, lock)); + }; + + /** Update a VMGroup + * @param vmgroup pointer to VMGroup + * @return 0 on success + */ + int update(VMGroup * vmgroup) + { + return vmgroup->update(db); + }; + + /** + * Bootstraps the database table(s) associated to the VMGroup pool + * @return 0 on success + */ + static int bootstrap(SqlDB * _db) + { + return VMGroup::bootstrap(_db); + }; + + /** + * Dumps the VMGroup pool in XML format. A filter can be added to the query + * @param os the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * @param limit parameters used for pagination + * + * @return 0 on success + */ + int dump(std::ostringstream& os, const std::string& where, + const std::string& limit) + { + return PoolSQL::dump(os, "VM_GROUP_POOL", VMGroup::table, where, limit); + }; + +private: + + /** + * Factory method to produce objects + * @return a pointer to the new object + */ + PoolObjectSQL * create() + { + return new VMGroup(-1,-1,"","",0,0); + }; +}; + +#endif /*VMGROUP_POOL_H_*/ + diff --git a/src/secgroup/SecurityGroup.cc b/src/secgroup/SecurityGroup.cc index ee8a0a40b2..3488905dab 100644 --- a/src/secgroup/SecurityGroup.cc +++ b/src/secgroup/SecurityGroup.cc @@ -56,6 +56,8 @@ SecurityGroup::SecurityGroup( { obj_template = new Template; } + + set_umask(_umask); } /* -------------------------------------------------------------------------- */ diff --git a/src/vm_group/SConstruct b/src/vm_group/SConstruct new file mode 100644 index 0000000000..89900acafe --- /dev/null +++ b/src/vm_group/SConstruct @@ -0,0 +1,30 @@ +# SConstruct for src/secgroup + +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +Import('env') + +lib_name='nebula_vmgroup' + +# Sources to generate the library +source_files=[ + 'VMGroupPool.cc', + 'VMGroup.cc' +] + +# Build library +env.StaticLibrary(lib_name, source_files) diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc new file mode 100644 index 0000000000..c9d7a5c4fd --- /dev/null +++ b/src/vm_group/VMGroup.cc @@ -0,0 +1,387 @@ +/* ------------------------------------------------------------------------ */ +/* 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. */ +/* -------------------------------------------------------------------------*/ + +#include "VMGroup.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* VMGroupRole */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va) +{ + string vms_str = va->vector_value("VMS"); + + if ( !vms_str.empty() ) + { + one_util::split_unique(vms_str, ',', vms); + } +} + +/* -------------------------------------------------------------------------- */ + +void VMGroupRole::add_vm(int vm_id) +{ + std::pair::iterator, bool> rc; + + rc = vms.insert(vm_id); + + if ( rc.second == false ) + { + return; + } + + set_vms(); +} + +void VMGroupRole::del_vm(int vm_id) +{ + size_t rc = vms.erase(vm_id); + + if ( rc == 0 ) + { + return; + } + + set_vms(); +} + + +void VMGroupRole::set_vms() +{ + std::string vms_str = one_util::join(vms.begin(), vms.end(), ','); + + va->replace("VMS", vms_str); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* VMGroup */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +const char * VMGroup::table = "vmgroup_pool"; + +const char * VMGroup::db_names = "oid, name, body, uid, gid, owner_u, group_u, " + "other_u"; + +const char * VMGroup::db_bootstrap = "CREATE TABLE IF NOT EXISTS vmgroup_pool " + "(oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, " + "uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, " + "other_u INTEGER, UNIQUE(name,uid))"; + +/* ------------------------------------------------------------------------ */ + +VMGroup::VMGroup(int _uid, int _gid, const string& _uname, const string& _gname, + int _umask, Template * group_template): + PoolObjectSQL(-1, VMGROUP, "", _uid, _gid, _uname, _gname, table) +{ + if (group_template != 0) + { + obj_template = group_template; + } + else + { + obj_template = new Template; + } + + set_umask(_umask); +} + +VMGroup::~VMGroup() +{ + by_id.delete_roles(); + + delete obj_template; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& VMGroup::to_xml(string& xml) const +{ + ostringstream oss; + string template_xml; + string perms_xml; + + oss << + "" << + "" << oid << "" << + "" << uid << "" << + "" << gid << "" << + "" << uname << "" << + "" << gname << "" << + "" << name << "" << + perms_to_xml(perms_xml) << + obj_template->to_xml(template_xml) << + ""; + + xml = oss.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ + +int VMGroup::from_xml(const string &xml_str) +{ + vector content; + int rc = 0; + + // Initialize the internal XML object + update_from_str(xml_str); + + // Get class base attributes + rc += xpath(oid, "/VM_GROUP/ID", -1); + rc += xpath(uid, "/VM_GROUP/UID", -1); + rc += xpath(gid, "/VM_GROUP/GID", -1); + rc += xpath(uname, "/VM_GROUP/UNAME","not_found"); + rc += xpath(gname, "/VM_GROUP/GNAME","not_found"); + rc += xpath(name, "/VM_GROUP/NAME", "not_found"); + + // Permissions + rc += perms_from_xml(); + + // Get associated template + ObjectXML::get_nodes("/VM_GROUP/TEMPLATE", content); + + if (content.empty()) + { + return -1; + } + + // Template contents + rc += obj_template->from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + + content.clear(); + + if (rc != 0) + { + return -1; + } + + // VMGroup roles + vector roles; + vector::iterator it; + + std::string error; + + obj_template->get("ROLE", roles); + + for (it = roles.begin(); it != roles.end(); ++it) + { + if ( add_role(*it, error) == -1 ) + { + return -1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroup::add_role(VectorAttribute * vrole, string& error) +{ + int rid; + std::string rname = vrole->vector_value("NAME"); + + if ( vrole->vector_value("ID", rid) == -1 ) + { + error = "Missing ID in VM group role"; + return -1; + } + else if ( rname.empty() ) + { + error = "Missing NAME in VM group role"; + return -1; + } + + VMGroupRole * role = new VMGroupRole(vrole); + + if ( by_id.insert(rid, role) == false ) + { + delete role; + error = "Role ID already exists"; + return -1; + } + + if ( by_name.insert(rname, role) == false ) + { + by_id.erase(rid); + + delete role; + error = "Role NAME already exists"; + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroup::insert_replace(SqlDB *db, bool replace, string& error_str) +{ + ostringstream oss; + + int rc; + string xml_body; + + char * sql_name; + char * sql_xml; + + sql_name = db->escape_str(name.c_str()); + + if ( sql_name == 0 ) + { + goto error_name; + } + + sql_xml = db->escape_str(to_xml(xml_body).c_str()); + + if ( sql_xml == 0 ) + { + goto error_body; + } + + if ( validate_xml(sql_xml) != 0 ) + { + goto error_xml; + } + + if ( replace ) + { + oss << "REPLACE"; + } + else + { + oss << "INSERT"; + } + + // Construct the SQL statement to Insert or Replace + oss <<" INTO "<exec(oss); + + db->free_str(sql_name); + db->free_str(sql_xml); + + return rc; + +error_xml: + db->free_str(sql_name); + db->free_str(sql_xml); + + error_str = "Error transforming the VM group to XML."; + + goto error_common; + +error_body: + db->free_str(sql_name); + goto error_generic; + +error_name: + goto error_generic; + +error_generic: + error_str = "Error inserting VM group in DB."; +error_common: + return -1; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroup::insert(SqlDB *db, string& error_str) +{ + vector::iterator it; + vector roles; + + vector affined; + vector anti_affined; + + vector::const_iterator jt; + + erase_template_attribute("NAME",name); + + if (name.empty()) + { + error_str = "No NAME in template for VM group."; + return -1; + } + + get_template_attribute("ROLE", roles); + + for ( it = roles.begin(); it != roles.end(); it++ ) + { + if (add_role(*it, error_str) == -1) + { + return -1; + } + } + + get_template_attribute("AFFINED", affined); + + for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) + { + std::string a_str = (*jt)->value(); + + if ( !by_name.in_map(a_str) ) + { + error_str = "Some AFFINED roles: " + a_str + ", not defined"; + return -1; + } + } + + get_template_attribute("ANTI_AFFINED", anti_affined); + + for ( jt = anti_affined.begin() ; jt != anti_affined.end() ; ++jt ) + { + std::string a_str = (*jt)->value(); + + if ( !by_name.in_map(a_str) ) + { + error_str = "Some ANTI_AFFINED roles: " + a_str + ", not defined"; + return -1; + } + } + + if ( insert_replace(db, false, error_str) != 0 ) + { + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + From 17749cb5e791c50f3d8399987d23a49b326301e6 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 01:22:10 +0100 Subject: [PATCH 02/26] F #2347: Allocate, delete and info API calls for the VMGroup --- include/Nebula.h | 16 +- include/RequestManagerAllocate.h | 29 +++ include/RequestManagerDelete.h | 21 ++- include/RequestManagerInfo.h | 16 ++ include/RequestManagerPoolInfoFilter.h | 19 ++ include/VMGroup.h | 6 +- install.sh | 6 + src/cli/etc/onevmgroup.yaml | 25 +++ src/cli/one_helper/onevmgroup_helper.rb | 121 +++++++++++++ src/cli/onevmgroup | 218 +++++++++++++++++++++++ src/nebula/Nebula.cc | 3 + src/nebula/SConstruct | 1 + src/oca/ruby/opennebula.rb | 2 + src/oca/ruby/opennebula/vm_group.rb | 173 ++++++++++++++++++ src/oca/ruby/opennebula/vm_group_pool.rb | 78 ++++++++ src/rm/RequestManager.cc | 12 ++ src/rm/RequestManagerAllocate.cc | 22 +++ src/vm_group/VMGroup.cc | 6 +- src/vm_group/VMGroupPool.cc | 61 +++++++ 19 files changed, 827 insertions(+), 8 deletions(-) create mode 100644 src/cli/etc/onevmgroup.yaml create mode 100644 src/cli/one_helper/onevmgroup_helper.rb create mode 100755 src/cli/onevmgroup create mode 100644 src/oca/ruby/opennebula/vm_group.rb create mode 100644 src/oca/ruby/opennebula/vm_group_pool.rb create mode 100644 src/vm_group/VMGroupPool.cc diff --git a/include/Nebula.h b/include/Nebula.h index e8a328d4ae..8a95086fa2 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -37,6 +37,7 @@ #include "VirtualRouterPool.h" #include "MarketPlacePool.h" #include "MarketPlaceAppPool.h" +#include "VMGroupPool.h" #include "VirtualMachineManager.h" #include "LifeCycleManager.h" @@ -156,6 +157,11 @@ public: return apppool; }; + VMGroupPool * get_vmgrouppool() + { + return vmgrouppool; + }; + // -------------------------------------------------------------- // Manager Accessors // -------------------------------------------------------------- @@ -580,10 +586,10 @@ private: "/DEFAULT_GROUP_QUOTAS/VM_QUOTA"), system_db(0), db(0), vmpool(0), hpool(0), vnpool(0), upool(0), ipool(0), gpool(0), tpool(0), - dspool(0), clpool(0), docpool(0), zonepool(0), - secgrouppool(0), vdcpool(0), vrouterpool(0), marketpool(0), apppool(0), - lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0), authm(0), - aclm(0), imagem(0), marketm(0), ipamm(0) + dspool(0), clpool(0), docpool(0), zonepool(0), secgrouppool(0), + vdcpool(0), vrouterpool(0), marketpool(0), apppool(0), vmgrouppool(0), + lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0), authm(0), aclm(0), + imagem(0), marketm(0), ipamm(0) { const char * nl = getenv("ONE_LOCATION"); @@ -634,6 +640,7 @@ private: delete vrouterpool; delete marketpool; delete apppool; + delete vmgrouppool; delete vmm; delete lcm; delete im; @@ -718,6 +725,7 @@ private: VirtualRouterPool * vrouterpool; MarketPlacePool * marketpool; MarketPlaceAppPool * apppool; + VMGroupPool * vmgrouppool; // --------------------------------------------------------------- // Nebula Managers diff --git a/include/RequestManagerAllocate.h b/include/RequestManagerAllocate.h index bf002e734c..9f099eeac7 100644 --- a/include/RequestManagerAllocate.h +++ b/include/RequestManagerAllocate.h @@ -679,4 +679,33 @@ private: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupAllocate : public RequestManagerAllocate +{ +public: + VMGroupAllocate(): + RequestManagerAllocate("VMGroupAllocate", + "Allocates a new vm group", + "A:ss", + true) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupAllocate(){}; + + /* --------------------------------------------------------------------- */ + + Template * get_object_template() + { + return new Template; + }; + + Request::ErrorCode pool_allocate(xmlrpc_c::paramList const& paramList, + Template * tmpl, + int& id, + RequestAttributes& att); +}; + #endif diff --git a/include/RequestManagerDelete.h b/include/RequestManagerDelete.h index b4382818d5..ea882363ad 100644 --- a/include/RequestManagerDelete.h +++ b/include/RequestManagerDelete.h @@ -449,7 +449,24 @@ protected: int drop(PoolObjectSQL * obj, bool resive, RequestAttributes& att); }; -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VMGroupDelete : public RequestManagerDelete +{ +public: + VMGroupDelete(): + RequestManagerDelete("VMGroupDelete", + "Deletes a vm group") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupDelete(){}; +}; #endif + diff --git a/include/RequestManagerInfo.h b/include/RequestManagerInfo.h index 049e43bc24..4e2a96e17f 100644 --- a/include/RequestManagerInfo.h +++ b/include/RequestManagerInfo.h @@ -371,7 +371,23 @@ public: ~MarketPlaceAppInfo(){}; }; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupInfo : public RequestManagerInfo +{ +public: + VMGroupInfo(): + RequestManagerInfo("VMGroupInfo", + "Returns vm group information") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupInfo(){}; +}; + #endif diff --git a/include/RequestManagerPoolInfoFilter.h b/include/RequestManagerPoolInfoFilter.h index 1a3098f5ad..6f83e52389 100644 --- a/include/RequestManagerPoolInfoFilter.h +++ b/include/RequestManagerPoolInfoFilter.h @@ -553,4 +553,23 @@ public: ~MarketPlaceAppPoolInfo(){}; }; +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VMGroupPoolInfo : public RequestManagerPoolInfoFilter +{ +public: + VMGroupPoolInfo(): + RequestManagerPoolInfoFilter("VMGroupPoolInfo", + "Returns the vm group pool", + "A:siii") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupPoolInfo(){}; +}; + #endif diff --git a/include/VMGroup.h b/include/VMGroup.h index 6c6d729813..28fe029e2f 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -277,7 +277,11 @@ private: * @param error string describing the error if any * @return 0 on success */ - int post_update_template(string& error); + int post_update_template(string& error) + { + //TODO + return 0; + }; /** * Factory method for VMGroup templates diff --git a/install.sh b/install.sh index 04632755c2..e5ba5b9c7f 100755 --- a/install.sh +++ b/install.sh @@ -550,6 +550,7 @@ BIN_FILES="src/nebula/oned \ src/cli/oneflow \ src/cli/oneflow-template \ src/cli/onesecgroup \ + src/cli/onevmgroup \ src/cli/onevdc \ src/cli/onevrouter \ src/cli/onemarket \ @@ -1280,6 +1281,8 @@ RUBY_OPENNEBULA_LIB_FILES="src/oca/ruby/opennebula/acl_pool.rb \ src/oca/ruby/opennebula/pool.rb \ src/oca/ruby/opennebula/security_group_pool.rb \ src/oca/ruby/opennebula/security_group.rb \ + src/oca/ruby/opennebula/vm_group_pool.rb \ + src/oca/ruby/opennebula/vm_group.rb \ src/oca/ruby/opennebula/system.rb \ src/oca/ruby/opennebula/template_pool.rb \ src/oca/ruby/opennebula/template.rb \ @@ -1440,6 +1443,7 @@ ONE_CLI_LIB_FILES="src/cli/one_helper/onegroup_helper.rb \ src/cli/one_helper/onevdc_helper.rb \ src/cli/one_helper/oneacct_helper.rb \ src/cli/one_helper/onesecgroup_helper.rb \ + src/cli/one_helper/onevmgroup_helper.rb \ src/cli/one_helper/onevrouter_helper.rb \ src/cli/one_helper/onemarketapp_helper.rb \ src/cli/one_helper/onemarket_helper.rb" @@ -1459,6 +1463,7 @@ CLI_BIN_FILES="src/cli/onevm \ src/cli/oneflow-template \ src/cli/oneacct \ src/cli/onesecgroup \ + src/cli/onevmgroup \ src/cli/oneshowback \ src/cli/onevdc \ src/cli/onevrouter \ @@ -1478,6 +1483,7 @@ CLI_CONF_FILES="src/cli/etc/onegroup.yaml \ src/cli/etc/onezone.yaml \ src/cli/etc/oneacct.yaml \ src/cli/etc/onesecgroup.yaml \ + src/cli/etc/onevmgroup.yaml \ src/cli/etc/oneshowback.yaml \ src/cli/etc/onevdc.yaml \ src/cli/etc/onevrouter.yaml \ diff --git a/src/cli/etc/onevmgroup.yaml b/src/cli/etc/onevmgroup.yaml new file mode 100644 index 0000000000..f164e8d358 --- /dev/null +++ b/src/cli/etc/onevmgroup.yaml @@ -0,0 +1,25 @@ +--- +:ID: + :desc: ONE identifier for the VM Group + :size: 4 + +:NAME: + :desc: Name of the VM Group + :size: 20 + :left: true + +:USER: + :desc: Username of the VM Group owner + :size: 15 + :left: true + +:GROUP: + :desc: Group of the VM Group + :size: 15 + :left: true + +:default: +- :ID +- :USER +- :GROUP +- :NAME diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb new file mode 100644 index 0000000000..3bd12a131a --- /dev/null +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -0,0 +1,121 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +require 'one_helper' + +class OneVMGroupHelper < OpenNebulaHelper::OneHelper + def self.rname + "VM_GROUP" + end + + def self.conf_file + "onevmgroup.yaml" + end + + def format_pool(options) + config_file = self.class.table_conf + + table = CLIHelper::ShowTable.new(config_file, self) do + column :ID, "ONE identifier for the VM Group", :size=>4 do |d| + d["ID"] + end + + column :NAME, "Name of the VM Group", :left, :size=>20 do |d| + d["NAME"] + end + + column :USER, "Username of the VM Group owner", :left, + :size=>15 do |d| + helper.user_name(d, options) + end + + column :GROUP, "Group of the VM Group", :left, :size=>15 do |d| + helper.group_name(d, options) + end + + default :ID, :USER, :GROUP, :NAME + end + + table + end + + private + + def factory(id=nil) + if id + OpenNebula::VMGroup.new_with_id(id, @client) + else + xml=OpenNebula::VMGroup.build_xml + OpenNebula::VMGroup.new(xml, @client) + end + end + + def factory_pool(user_flag=-2) + OpenNebula::VMGroupPool.new(@client, user_flag) + end + + def format_resource(vmgroup, options = {}) + str="%-15s: %-20s" + str_h1="%-80s" + + CLIHelper.print_header( + str_h1 % "VM GROUP #{vmgroup['ID']} INFORMATION") + puts str % ["ID", vmgroup.id.to_s] + puts str % ["NAME", vmgroup.name] + puts str % ["USER", vmgroup['UNAME']] + puts str % ["GROUP", vmgroup['GNAME']] + + CLIHelper.print_header(str_h1 % "PERMISSIONS",false) + + puts + + ["OWNER", "GROUP", "OTHER"].each { |e| + mask = "---" + mask[0] = "u" if vmgroup["PERMISSIONS/#{e}_U"] == "1" + mask[1] = "m" if vmgroup["PERMISSIONS/#{e}_M"] == "1" + mask[2] = "a" if vmgroup["PERMISSIONS/#{e}_A"] == "1" + + puts str % [e, mask] + } + + puts + + CLIHelper.print_header(str_h1 % "ROLES", false) + + if !vmgroup.to_hash['VM_GROUP']['TEMPLATE']['ROLE'].nil? + roles = [vmgroup.to_hash['VM_GROUP']['TEMPLATE']['ROLE']].flatten + end + + CLIHelper::ShowTable.new(nil, self) do + column :ID, "", :left, :size=>4 do |d| + d["ID"] + end + + column :NAME, "", :left, :size=>16 do |d| + d["NAME"] + end + + column :VIRTUAL_MACHINES, "", :left, :size=>32 do |d| + d["VMS"] + end + end.show(roles, {}) + + puts + + CLIHelper.print_header(str_h1 % "TEMPLATE CONTENTS",false) + puts vmgroup.template_str + end +end diff --git a/src/cli/onevmgroup b/src/cli/onevmgroup new file mode 100755 index 0000000000..e0eeb05d3d --- /dev/null +++ b/src/cli/onevmgroup @@ -0,0 +1,218 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" + +require 'command_parser' +require 'one_helper/onevmgroup_helper' + +cmd=CommandParser::CmdParser.new(ARGV) do + usage "`onevmgroup` [] []" + version OpenNebulaHelper::ONE_VERSION + + helper = OneVMGroupHelper.new + + before_proc do + helper.set_client(options) + end + + ######################################################################## + # Global Options + ######################################################################## + set :option, CommandParser::OPTIONS+OpenNebulaHelper::CLIENT_OPTIONS + + list_options = CLIHelper::OPTIONS + list_options << OpenNebulaHelper::XML + list_options << OpenNebulaHelper::NUMERIC + list_options << OpenNebulaHelper::DESCRIBE + + ######################################################################## + # Formatters for arguments + ######################################################################## + set :format, :groupid, OpenNebulaHelper.rname_to_id_desc("GROUP") do |arg| + OpenNebulaHelper.rname_to_id(arg, "GROUP") + end + + set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg| + OpenNebulaHelper.rname_to_id(arg, "USER") + end + + set :format, :vmgroupid, OneVMGroupHelper.to_id_desc do |arg| + helper.to_id(arg) + end + + set :format, :vmgroupid_list, OneVMGroupHelper.list_to_id_desc do |arg| + helper.list_to_id(arg) + end + + set :format, :filterflag, OneVMGroupHelper.filterflag_to_i_desc do |arg| + helper.filterflag_to_i(arg) + end + + ######################################################################## + # Commands + ######################################################################## + + create_desc = <<-EOT.unindent + Creates a new VM Group from the given description + EOT + + command :create, create_desc, :file do + helper.create_resource(options) do |obj| + begin + template = File.read(args[0]) + + obj.allocate(template) + rescue => e + STDERR.puts e.messsage + exit -1 + end + end + end + + delete_desc = <<-EOT.unindent + Deletes the VM Group + EOT + + command :delete, delete_desc, [:range, :vmgroupid_list] do + helper.perform_actions(args[0],options,"deleted") do |obj| + obj.delete + end + end + + list_desc = <<-EOT.unindent + Lists VM Group in the pool + EOT + + command :list, list_desc, [:filterflag, nil], :options=>list_options do + helper.list_pool(options, false, args[0]) + end + + show_desc = <<-EOT.unindent + Shows information for the given VM Group + EOT + + command :show, show_desc, :vmgroupid, :options=>OpenNebulaHelper::XML do + helper.show_resource(args[0],options) + end + +=begin + clone_desc = <<-EOT.unindent + Creates a new Security Group from an existing one + EOT + + command :clone, clone_desc, :secgroupid, :name do + helper.perform_action(args[0],options,"cloned") do |obj| + res = obj.clone(args[1]) + + if !OpenNebula.is_error?(res) + puts "ID: #{res}" + else + puts res.message + end + end + end + + chgrp_desc = <<-EOT.unindent + Changes the Security Group's group + EOT + + command :chgrp, chgrp_desc,[:range, :secgroupid_list], :groupid do + helper.perform_actions(args[0],options,"Group changed") do |obj| + obj.chown(-1, args[1].to_i) + end + end + + chown_desc = <<-EOT.unindent + Changes the Security Group's owner and group + EOT + + command :chown, chown_desc, [:range, :secgroupid_list], :userid, + [:groupid,nil] do + gid = args[2].nil? ? -1 : args[2].to_i + helper.perform_actions(args[0],options,"Owner/Group changed") do |obj| + obj.chown(args[1].to_i, gid) + end + end + + chmod_desc = <<-EOT.unindent + Changes the Security Group permissions + EOT + + command :chmod, chmod_desc, [:range, :secgroupid_list], :octet do + helper.perform_actions(args[0],options, "Permissions changed") do |t| + t.chmod_octet(args[1]) + end + end + + update_desc = <<-EOT.unindent + Update the template contents. If a path is not provided the editor will + be launched to modify the current content. + EOT + + command :update, update_desc, :secgroupid, [:file, nil], + :options=>OpenNebulaHelper::APPEND do + helper.perform_action(args[0],options,"modified") do |obj| + if options[:append] + str = OpenNebulaHelper.append_template(args[0], obj, args[1]) + else + str = OpenNebulaHelper.update_template(args[0], obj, args[1]) + end + + helper.set_client(options) + obj = helper.retrieve_resource(obj.id) + + obj.update(str, options[:append]) + end + end + + rename_desc = <<-EOT.unindent + Renames the Security Group + EOT + + command :rename, rename_desc, :secgroupid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end + + commit_desc = <<-EOT.unindent + Commit SG changes to associated VMs. This command is to propagate + security group rules to VMs when they are updated. This operation takes + time to iterate over all VMs in the security group, progress can be + checked through the outdated, updating and error VM sets. + EOT + + command :commit, commit_desc, :secgroupid, + :options =>[OneSecurityGroupHelper::RECOVER] do + helper.perform_action(args[0], options, "commit") do |o| + o.commit(options[:recover]==true) + end + end + +=end +end diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index f08daff7f2..08b3dc8493 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -323,6 +323,7 @@ void Nebula::start(bool bootstrap_only) rc += GroupQuotas::bootstrap(db); rc += SecurityGroupPool::bootstrap(db); rc += VirtualRouterPool::bootstrap(db); + rc += VMGroupPool::bootstrap(db); // Create the system tables only if bootstrap went well if (rc == 0) @@ -597,6 +598,8 @@ void Nebula::start(bool bootstrap_only) marketpool = new MarketPlacePool(db, is_federation_slave()); apppool = new MarketPlaceAppPool(db, is_federation_slave()); + vmgrouppool = new VMGroupPool(db); + default_user_quota.select(); default_group_quota.select(); } diff --git a/src/nebula/SConstruct b/src/nebula/SConstruct index 4c1e2a24c1..fe7c3216d0 100644 --- a/src/nebula/SConstruct +++ b/src/nebula/SConstruct @@ -67,6 +67,7 @@ env.Prepend(LIBS=[ 'nebula_vrouter', 'nebula_marketplace', 'nebula_ipamm', + 'nebula_vmgroup', 'crypto', 'xml2' ]) diff --git a/src/oca/ruby/opennebula.rb b/src/oca/ruby/opennebula.rb index f066cffe0e..8b995fe9dc 100644 --- a/src/oca/ruby/opennebula.rb +++ b/src/oca/ruby/opennebula.rb @@ -62,6 +62,8 @@ require 'opennebula/marketplace' require 'opennebula/marketplace_pool' require 'opennebula/marketplaceapp' require 'opennebula/marketplaceapp_pool' +require 'opennebula/vm_group' +require 'opennebula/vm_group_pool' module OpenNebula diff --git a/src/oca/ruby/opennebula/vm_group.rb b/src/oca/ruby/opennebula/vm_group.rb new file mode 100644 index 0000000000..c5f4bbf977 --- /dev/null +++ b/src/oca/ruby/opennebula/vm_group.rb @@ -0,0 +1,173 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +require 'opennebula/pool_element' + +module OpenNebula + class VMGroup < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + VMGROUP_METHODS = { + :allocate => "vmgroup.allocate", + :info => "vmgroup.info", + #:update => "vmgroup.update", + :delete => "vmgroup.delete", + #:chown => "vmgroup.chown", + #:chmod => "vmgroup.chmod", + #:clone => "vmgroup.clone", + #:rename => "vmgroup.rename" + } + + # Creates a VMGroup description with just its identifier + # this method should be used to create plain VMGroup objects. + # @param pe_id [Integer] the id of the object + def VMGroup.build_xml(pe_id=nil) + if pe_id + obj_xml = "#{pe_id}" + else + obj_xml = "" + end + + XMLElement.build_xml(obj_xml,'VM_GROUP') + end + + # Class constructor + def initialize(xml, client) + super(xml,client) + + @client = client + end + + ####################################################################### + # XML-RPC Methods for the VMGroup Object + ####################################################################### + + # Retrieves the information of the VMGroup. + def info() + super(VMGROUP_METHODS[:info], 'VM_GROUP') + end + + alias_method :info!, :info + + # Allocates a new VMGroup in OpenNebula + # + # @param description [String] The contents of the VMGroup. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def allocate(description) + super(VMGROUP_METHODS[:allocate], description) + end + + # Deletes the SecurityGroup + def delete() + super(VMGROUP_METHODS[:delete]) + end +=begin + # Replaces the securitygroup contents + # + # @param new_securitygroup [String] New securitygroup contents + # @param append [true, false] True to append new attributes instead of + # replace the whole securitygroup + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def update(new_securitygroup, append=false) + super(SECGROUP_METHODS[:update], new_securitygroup, append ? 1 : 0) + end + + # Changes the owner/group + # + # @param uid [Integer] the new owner id. Set to -1 to leave the current one + # @param gid [Integer] the new group id. Set to -1 to leave the current one + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chown(uid, gid) + super(SECGROUP_METHODS[:chown], uid, gid) + end + + # Changes the SecurityGroup permissions. + # + # @param octet [String] Permissions octed , e.g. 640 + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod_octet(octet) + super(SECGROUP_METHODS[:chmod], octet) + end + + # Changes the SecurityGroup permissions. + # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, + other_m, other_a) + super(SECGROUP_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, + group_m, group_a, other_u, other_m, other_a) + end + + # Clones this SecurityGroup into a new one + # + # @param [String] name for the new SecurityGroup. + # + # @return [Integer, OpenNebula::Error] The new SecurityGroup ID in case + # of success, Error otherwise + def clone(name) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(SECGROUP_METHODS[:clone], @pe_id, name) + + return rc + end + + # Renames this SecurityGroup + # + # @param name [String] New name for the SecurityGroup. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(SECGROUP_METHODS[:rename], @pe_id, name) + end + + # Commit SG changes to associated VMs + # + # @param recover [Bool] If true will only operate on outdated and error + # VMs. This is intended for retrying updates of VMs or reinitialize the + # updating process if oned stopped or fail. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def commit(recover) + return call(SECGROUP_METHODS[:commit], @pe_id, recover) + end +=end + ####################################################################### + # Helpers to get VMGroup information + ####################################################################### + + # Returns the group identifier + # [return] _Integer_ the element's group ID + def gid + self['GID'].to_i + end + + def owner_id + self['UID'].to_i + end + end +end diff --git a/src/oca/ruby/opennebula/vm_group_pool.rb b/src/oca/ruby/opennebula/vm_group_pool.rb new file mode 100644 index 0000000000..b0dacfbd1b --- /dev/null +++ b/src/oca/ruby/opennebula/vm_group_pool.rb @@ -0,0 +1,78 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +require 'opennebula/pool' + +module OpenNebula + class VMGroupPool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + VMGROUP_POOL_METHODS = { + :info => "vmgrouppool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents an XML-RPC connection + # +user_id+ used to refer to a Pool with Templates from that user + def initialize(client, user_id=-1) + super('VM_GROUP_POOL','VM_GROUP',client) + + @user_id = user_id + end + + # Factory method to create Template objects + def factory(element_xml) + OpenNebula::VMGroup.new(element_xml,@client) + end + + ####################################################################### + # XML-RPC Methods for the Template Object + ####################################################################### + + # Retrieves all or part of the objects in the pool. + def info(*args) + case args.size + when 0 + info_filter(VMGROUP_POOL_METHODS[:info], @user_id, -1, -1) + when 3 + info_filter(VMGROUP_POOL_METHODS[:info], args[0], args[1], + args[2]) + end + end + + def info_all() + return super(VMGROUP_POOL_METHODS[:info]) + end + + def info_mine() + return super(VMGROUP_POOL_METHODS[:info]) + end + + def info_group() + return super(VMGROUP_POOL_METHODS[:info]) + end + + alias_method :info!, :info + alias_method :info_all!, :info_all + alias_method :info_mine!, :info_mine + alias_method :info_group!, :info_group + end +end + diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 3f63410399..8be0bbd0ea 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -378,6 +378,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_allocate(new DocumentAllocate()); xmlrpc_c::methodPtr secg_allocate(new SecurityGroupAllocate()); xmlrpc_c::methodPtr vrouter_allocate(new VirtualRouterAllocate()); + xmlrpc_c::methodPtr vmg_allocate(new VMGroupAllocate()); // Clone Methods xmlrpc_c::methodPtr template_clone(new VMTemplateClone()); @@ -394,6 +395,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_delete(new DocumentDelete()); xmlrpc_c::methodPtr secg_delete(new SecurityGroupDelete()); xmlrpc_c::methodPtr vrouter_delete(new VirtualRouterDelete()); + xmlrpc_c::methodPtr vmg_delete(new VMGroupDelete()); // Info Methods xmlrpc_c::methodPtr vm_info(new VirtualMachineInfo()); @@ -406,6 +408,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_info(new DocumentInfo()); xmlrpc_c::methodPtr secg_info(new SecurityGroupInfo()); xmlrpc_c::methodPtr vrouter_info(new VirtualRouterInfo()); + xmlrpc_c::methodPtr vmg_info(new VMGroupInfo()); // Lock Methods xmlrpc_c::methodPtr doc_lock(new DocumentLock()); @@ -421,6 +424,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr clusterpool_info(new ClusterPoolInfo()); xmlrpc_c::methodPtr docpool_info(new DocumentPoolInfo()); xmlrpc_c::methodPtr secgpool_info(new SecurityGroupPoolInfo()); + xmlrpc_c::methodPtr vmgpool_info(new VMGroupPoolInfo()); xmlrpc_c::methodPtr vrouter_pool_info(new VirtualRouterPoolInfo()); // Host Methods @@ -829,6 +833,14 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.secgrouppool.info",secgpool_info); + /* VM Group objects related methods*/ + + RequestManagerRegistry.addMethod("one.vmgroup.allocate", vmg_allocate); + RequestManagerRegistry.addMethod("one.vmgroup.delete", vmg_delete); + RequestManagerRegistry.addMethod("one.vmgroup.info", vmg_info); + + RequestManagerRegistry.addMethod("one.vmgrouppool.info", vmgpool_info); + /* Vdc related methods */ xmlrpc_c::method * vdc_allocate_pt; diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index 3a2042c91d..c16f8d8fb5 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -1195,3 +1195,25 @@ Request::ErrorCode MarketPlaceAppAllocate::pool_allocate( return Request::SUCCESS; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +Request::ErrorCode VMGroupAllocate::pool_allocate( + xmlrpc_c::paramList const& paramList, + Template * tmpl, + int& id, + RequestAttributes& att) +{ + VMGroupPool * vmgpool = static_cast(pool); + + int rc = vmgpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask + ,tmpl, &id, att.resp_msg); + + if (rc < 0) + { + return Request::INTERNAL; + } + + return Request::SUCCESS; +} + diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index c9d7a5c4fd..663581daf0 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -322,6 +322,8 @@ error_common: int VMGroup::insert(SqlDB *db, string& error_str) { + int role_id; + vector::iterator it; vector roles; @@ -340,8 +342,10 @@ int VMGroup::insert(SqlDB *db, string& error_str) get_template_attribute("ROLE", roles); - for ( it = roles.begin(); it != roles.end(); it++ ) + for ( it = roles.begin(), role_id = 0; it != roles.end(); ++it, ++role_id ) { + (*it)->replace("ID", role_id); + if (add_role(*it, error_str) == -1) { return -1; diff --git a/src/vm_group/VMGroupPool.cc b/src/vm_group/VMGroupPool.cc new file mode 100644 index 0000000000..feb513fe60 --- /dev/null +++ b/src/vm_group/VMGroupPool.cc @@ -0,0 +1,61 @@ +/* -------------------------------------------------------------------------- */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + + +#include "VMGroupPool.h" + +int VMGroupPool::allocate(int uid, int gid, const string& uname, + const string& gname, int umask, Template * vmgroup_template, int * oid, + string& error_str) +{ + VMGroup * vmgrp; + VMGroup * vmgrp_aux = 0; + + string name; + + ostringstream os; + + vmgrp = new VMGroup(uid, gid, uname, gname, umask, vmgroup_template); + + vmgrp->get_template_attribute("NAME", name); + + if ( !PoolObjectSQL::name_is_valid(name, error_str) ) + { + goto error_name; + } + + vmgrp_aux = get(name, uid, false); + + if( vmgrp_aux != 0 ) + { + goto error_duplicated; + } + + *oid = PoolSQL::allocate(vmgrp, error_str); + + return *oid; + +error_duplicated: + os << "NAME is already taken by VMGroup " << vmgrp_aux->get_oid() << "."; + error_str = os.str(); + +error_name: + delete vmgrp; + *oid = -1; + + return *oid; +} + From ef25d1821fb33ed3a4a38bd12f7f5405ac26b71d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 04:06:51 +0100 Subject: [PATCH 03/26] F #2347: VMGroup Roles managed in a separate clas --- include/VMGroup.h | 158 +---------------- include/VMGroupRole.h | 226 ++++++++++++++++++++++++ src/cli/one_helper/onevmgroup_helper.rb | 4 +- src/vm_group/VMGroup.cc | 206 +++++++++++++-------- 4 files changed, 366 insertions(+), 228 deletions(-) create mode 100644 include/VMGroupRole.h diff --git a/include/VMGroup.h b/include/VMGroup.h index 28fe029e2f..8478f46d4c 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -18,56 +18,10 @@ #define VMGROUP_H_ #include "PoolObjectSQL.h" +#include "VMGroupRole.h" class VMGroupPool; -/** - * A VMGroupRole defines a VM type that typically implements a role in a - * multi-vm application. - * - * ROLE = [ - * NAME = "Web application servers", - * ID = 12, - * VMS = "1,2,45,21" - * ] - * - */ -class VMGroupRole -{ -public: - VMGroupRole(VectorAttribute *_va); - - virtual ~VMGroupRole(){}; - - /* ---------------------------------------------------------------------- */ - /* VMS set Interface */ - /* ---------------------------------------------------------------------- */ - const std::set& get_vms() - { - return vms; - }; - - void add_vm(int vm_id); - - void del_vm(int vm_id); - -private: - /** - * The set of vms in the role - */ - std::set vms; - - /** - * The associated vector attribute - */ - VectorAttribute * va; - - /** - * Set the VMS attribute for the role (list of VM IDs) - */ - void set_vms(); -}; - /** * A VM group is a set of related VMs that may impose placement constraints. * @@ -130,101 +84,6 @@ private: ~VMGroup(); - // ------------------------------------------------------------------------- - // Role Map management - // ------------------------------------------------------------------------- - /** - * A role map indexed by different key types - */ - template - class RoleMap - { - public: - /** - * Inserts a new role in the map - * @param k the key - * @param r pointer to yhe VMGroupRole - * @return true if the role was successfully inserted - */ - bool insert(const T& k, VMGroupRole * r) - { - std::pair rpair(k, r); - std::pair rc; - - rc = roles.insert(rpair); - - return rc.second; - } - - /** - * Frees the memory associated to the map and clears it - */ - void delete_roles() - { - for (roles_it it = roles.begin() ; it != roles.end() ; ++it ) - { - delete it->second; - } - - clear(); - } - - /** - * Clears the contents of the map - */ - void clear() - { - roles.clear(); - } - - size_t erase(const T& 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 key_set; - typename std::set::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 ) - { - if ( roles.find(*it) == roles.end() ) - { - return false; - } - } - - return true; - } - - private: - typedef typename std::map::iterator roles_it; - - std::map roles; - }; - - /** - * Add a new role to the VM group - * @param role to add as a vector attribute - * @param error if any - * - * @return 0 on success - */ - int add_role(VectorAttribute * vrole, string& error); - // ------------------------------------------------------------------------- // DataBase implementation // ------------------------------------------------------------------------- @@ -299,16 +158,11 @@ private: */ std::string name; - /** - * Map to access the roles by their name - */ - RoleMap by_name; - - /** - * Map to access the roles by their id - */ - RoleMap by_id; + /** + * The role set + */ + VMGroupRoles roles; }; -#endif /*SECURITYGROUP_H_*/ +#endif /*VMGROUP_H_*/ diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h new file mode 100644 index 0000000000..3411ab3928 --- /dev/null +++ b/include/VMGroupRole.h @@ -0,0 +1,226 @@ +/* ------------------------------------------------------------------------ */ +/* 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_ROLE_H_ +#define VMGROUP_ROLE_H_ + +#include "PoolObjectSQL.h" + +class VMGroupPool; + +/** + * A VMGroupRole defines a VM type that typically implements a role in a + * multi-vm application. + * + * ROLE = [ + * NAME = "Web application servers", + * ID = 12, + * VMS = "1,2,45,21" + * ] + * + */ +class VMGroupRole +{ +public: + VMGroupRole(VectorAttribute *_va); + + virtual ~VMGroupRole(){}; + + /* ---------------------------------------------------------------------- */ + /* VMS set Interface */ + /* ---------------------------------------------------------------------- */ + const std::set& get_vms() + { + return vms; + }; + + void add_vm(int vm_id); + + void del_vm(int vm_id); + +private: + /** + * The set of vms in the role + */ + std::set vms; + + /** + * The associated vector attribute + */ + VectorAttribute * va; + + /** + * Set the VMS attribute for the role (list of VM IDs) + */ + void set_vms(); +}; + +/** + * The VMGroupRoles class represents a set of ROLES stored in a Template + */ +class VMGroupRoles +{ +public: + VMGroupRoles():roles_template(false,'=',"ROLES"), next_role(0){}; + + ~VMGroupRoles() + { + by_id.delete_roles(); + }; + + /** + * Function to print the VMGroupRoles into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + std::string& to_xml(std::string& xml_str) const + { + return roles_template.to_xml(xml_str); + } + + /** + * Builds the object from an xml node + * @param node for the ROLES template + * @return 0 on success, -1 otherwise + */ + int from_xml_node(const xmlNodePtr node); + + /** + * Adds a new role to the set + * @param vrole VectorAttribute of the role + * @param error string if any + * + * @return 0 on success + */ + int add_role(VectorAttribute * vrole, string& error); + + /** + * Check that a key list is defined in the name map + * @param key_str separated list of keys + * @param true if the keys are in the map + */ + bool in_map(const std::string& key_str) + { + return by_name.in_map(key_str); + } + +private: + /** + * A role map indexed by different key types + */ + template + class RoleMap + { + public: + /** + * Inserts a new role in the map + * @param k the key + * @param r pointer to yhe VMGroupRole + * @return true if the role was successfully inserted + */ + bool insert(const T& k, VMGroupRole * r) + { + std::pair rpair(k, r); + std::pair rc; + + rc = roles.insert(rpair); + + return rc.second; + } + + /** + * Frees the memory associated to the map and clears it + */ + void delete_roles() + { + for (roles_it it = roles.begin() ; it != roles.end() ; ++it ) + { + delete it->second; + } + + clear(); + } + + /** + * Clears the contents of the map + */ + void clear() + { + roles.clear(); + } + + size_t erase(const T& 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 key_set; + typename std::set::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 ) + { + if ( roles.find(*it) == roles.end() ) + { + return false; + } + } + + return true; + } + + private: + typedef typename std::map::iterator roles_it; + + std::map roles; + }; + + /** + * The role template to store the VMGroupRole + */ + Template roles_template; + + /** + * The next role id + */ + int next_role; + + /** + * Map to access the roles by their name + */ + RoleMap by_name; + + /** + * Map to access the roles by their id + */ + RoleMap by_id; +}; + +#endif /*VMGROUP_ROLE_H*/ + diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index 3bd12a131a..42bf84d418 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -95,8 +95,8 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper CLIHelper.print_header(str_h1 % "ROLES", false) - if !vmgroup.to_hash['VM_GROUP']['TEMPLATE']['ROLE'].nil? - roles = [vmgroup.to_hash['VM_GROUP']['TEMPLATE']['ROLE']].flatten + if !vmgroup.to_hash['VM_GROUP']['ROLES']['ROLE'].nil? + roles = [vmgroup.to_hash['VM_GROUP']['ROLES']['ROLE']].flatten end CLIHelper::ShowTable.new(nil, self) do diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 663581daf0..defadb29f1 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -15,6 +15,7 @@ /* -------------------------------------------------------------------------*/ #include "VMGroup.h" +#include "VMGroupRole.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -60,7 +61,6 @@ void VMGroupRole::del_vm(int vm_id) set_vms(); } - void VMGroupRole::set_vms() { std::string vms_str = one_util::join(vms.begin(), vms.end(), ','); @@ -68,13 +68,108 @@ void VMGroupRole::set_vms() va->replace("VMS", vms_str); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::from_xml_node(const xmlNodePtr node) +{ + std::vector roles; + std::vector::iterator it; + + if ( roles_template.from_xml_node(node) == -1 ) + { + return -1; + } + + roles_template.get("ROLE", roles); + + for (it = roles.begin(); it != roles.end(); ++it) + { + std::string rname = (*it)->vector_value("NAME"); + + int rid; + int rc = (*it)->vector_value("ID", rid); + + if ( rname.empty() || rc == -1 ) + { + return -1; + } + + if ( rid >= next_role ) + { + next_role = rid + 1; + } + + VMGroupRole * role = new VMGroupRole((*it)); + + if ( by_id.insert(rid, role) == false ) + { + delete role; + return -1; + } + + if ( by_name.insert(rname, role) == false ) + { + by_id.erase(rid); + + delete role; + return -1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::add_role(VectorAttribute * vrole, string& error) +{ + std::string rname = vrole->vector_value("NAME"); + + if ( rname.empty() ) + { + error = "Missing NAME in VM group role"; + return -1; + } + + // Remove internal attributes before inserting + vrole->replace("ID", next_role); + + vrole->remove("VMS"); + + VMGroupRole * role = new VMGroupRole(vrole); + + if ( by_id.insert(next_role, role) == false ) + { + delete role; + + error = "Role ID already exists"; + return -1; + } + + if ( by_name.insert(rname, role) == false ) + { + by_id.erase(next_role); + + delete role; + + error = "Role NAME already exists"; + return -1; + } + + next_role += 1; + + roles_template.set(vrole); + + return 0; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroup */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ - const char * VMGroup::table = "vmgroup_pool"; const char * VMGroup::db_names = "oid, name, body, uid, gid, owner_u, group_u, " @@ -105,8 +200,6 @@ VMGroup::VMGroup(int _uid, int _gid, const string& _uname, const string& _gname, VMGroup::~VMGroup() { - by_id.delete_roles(); - delete obj_template; } @@ -116,8 +209,9 @@ VMGroup::~VMGroup() string& VMGroup::to_xml(string& xml) const { ostringstream oss; - string template_xml; - string perms_xml; + string template_xml; + string perms_xml; + string roles_xml; oss << "" << @@ -128,6 +222,7 @@ string& VMGroup::to_xml(string& xml) const "" << gname << "" << "" << name << "" << perms_to_xml(perms_xml) << + roles.to_xml(roles_xml) << obj_template->to_xml(template_xml) << ""; @@ -165,74 +260,29 @@ int VMGroup::from_xml(const string &xml_str) return -1; } - // Template contents rc += obj_template->from_xml_node(content[0]); ObjectXML::free_nodes(content); content.clear(); + // VMGroup roles + ObjectXML::get_nodes("/VM_GROUP/ROLES", content); + + if (!content.empty()) + { + rc += roles.from_xml_node(content[0]); + } + + ObjectXML::free_nodes(content); + + content.clear(); + if (rc != 0) { return -1; } - // VMGroup roles - vector roles; - vector::iterator it; - - std::string error; - - obj_template->get("ROLE", roles); - - for (it = roles.begin(); it != roles.end(); ++it) - { - if ( add_role(*it, error) == -1 ) - { - return -1; - } - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VMGroup::add_role(VectorAttribute * vrole, string& error) -{ - int rid; - std::string rname = vrole->vector_value("NAME"); - - if ( vrole->vector_value("ID", rid) == -1 ) - { - error = "Missing ID in VM group role"; - return -1; - } - else if ( rname.empty() ) - { - error = "Missing NAME in VM group role"; - return -1; - } - - VMGroupRole * role = new VMGroupRole(vrole); - - if ( by_id.insert(rid, role) == false ) - { - delete role; - error = "Role ID already exists"; - return -1; - } - - if ( by_name.insert(rname, role) == false ) - { - by_id.erase(rid); - - delete role; - error = "Role NAME already exists"; - return -1; - } - return 0; } @@ -322,10 +372,8 @@ error_common: int VMGroup::insert(SqlDB *db, string& error_str) { - int role_id; - + vector va_roles; vector::iterator it; - vector roles; vector affined; vector anti_affined; @@ -340,16 +388,26 @@ int VMGroup::insert(SqlDB *db, string& error_str) return -1; } - get_template_attribute("ROLE", roles); + remove_template_attribute("ROLE", va_roles); - for ( it = roles.begin(), role_id = 0; it != roles.end(); ++it, ++role_id ) + bool error = false; + + for ( it = va_roles.begin(); it != va_roles.end(); ++it ) { - (*it)->replace("ID", role_id); - - if (add_role(*it, error_str) == -1) + if ( error ) { - return -1; + delete *it; } + else if ( roles.add_role(*it, error_str) == -1 ) + { + delete *it; + error = true; + } + } + + if ( error ) + { + return -1; } get_template_attribute("AFFINED", affined); @@ -358,7 +416,7 @@ int VMGroup::insert(SqlDB *db, string& error_str) { std::string a_str = (*jt)->value(); - if ( !by_name.in_map(a_str) ) + if ( !roles.in_map(a_str) ) { error_str = "Some AFFINED roles: " + a_str + ", not defined"; return -1; @@ -371,7 +429,7 @@ int VMGroup::insert(SqlDB *db, string& error_str) { std::string a_str = (*jt)->value(); - if ( !by_name.in_map(a_str) ) + if ( !roles.in_map(a_str) ) { error_str = "Some ANTI_AFFINED roles: " + a_str + ", not defined"; return -1; From 973aac07fd6620ad8b7c4d5750eecd3bbe46b49f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 15:24:43 +0100 Subject: [PATCH 04/26] F #2347: Better parsing of VMGroup attributes --- include/VMGroup.h | 12 +++++++ src/vm_group/VMGroup.cc | 72 +++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/include/VMGroup.h b/include/VMGroup.h index 8478f46d4c..c2c597c9f8 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -84,6 +84,18 @@ private: ~VMGroup(); + // ------------------------------------------------------------------------- + // Role Management + // ------------------------------------------------------------------------- + /** + * Check if all the roles are defined in the group + * @param aname 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_affinity(const std::string& aname, std::string& error_str); + // ------------------------------------------------------------------------- // DataBase implementation // ------------------------------------------------------------------------- diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index defadb29f1..e968ed8466 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -370,17 +370,39 @@ error_common: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VMGroup::check_affinity(const std::string& aname, std::string& error_str) +{ + vector affined; + vector::const_iterator jt; + + obj_template->get(aname, affined); + + for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) + { + std::string a_str = (*jt)->value(); + + if ( !roles.in_map(a_str) ) + { + std::ostringstream oss; + oss << "Some roles used in " << aname << " attribute (" << a_str + << ") are not defined"; + + error_str = oss.str(); + return -1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + int VMGroup::insert(SqlDB *db, string& error_str) { - vector va_roles; - vector::iterator it; + vector va_roles; + vector::iterator it; - vector affined; - vector anti_affined; - - vector::const_iterator jt; - - erase_template_attribute("NAME",name); + erase_template_attribute("NAME", name); if (name.empty()) { @@ -388,17 +410,21 @@ int VMGroup::insert(SqlDB *db, string& error_str) return -1; } - remove_template_attribute("ROLE", va_roles); + obj_template->remove("ROLE", va_roles); bool error = false; for ( it = va_roles.begin(); it != va_roles.end(); ++it ) { - if ( error ) + VectorAttribute * vatt = dynamic_cast(*it); + + if (vatt == 0 || error) { delete *it; + continue; } - else if ( roles.add_role(*it, error_str) == -1 ) + + if ( roles.add_role(vatt, error_str) == -1 ) { delete *it; error = true; @@ -410,30 +436,14 @@ int VMGroup::insert(SqlDB *db, string& error_str) return -1; } - get_template_attribute("AFFINED", affined); - - for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) + if ( check_affinity("AFFINED", error_str) == -1 ) { - std::string a_str = (*jt)->value(); - - if ( !roles.in_map(a_str) ) - { - error_str = "Some AFFINED roles: " + a_str + ", not defined"; - return -1; - } + return -1; } - get_template_attribute("ANTI_AFFINED", anti_affined); - - for ( jt = anti_affined.begin() ; jt != anti_affined.end() ; ++jt ) + if ( check_affinity("ANTI_AFFINED", error_str) == -1 ) { - std::string a_str = (*jt)->value(); - - if ( !roles.in_map(a_str) ) - { - error_str = "Some ANTI_AFFINED roles: " + a_str + ", not defined"; - return -1; - } + return -1; } if ( insert_replace(db, false, error_str) != 0 ) From 202b47e9d8ef8dd14afcfde6b04871f4866b2d7d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 20:03:03 +0100 Subject: [PATCH 05/26] F #2347: Fix bugs. Show role names in vm group output --- include/NebulaUtil.h | 19 +++++++++---------- include/PoolObjectSQL.h | 1 + include/VMGroup.h | 5 ----- include/VMGroupRole.h | 5 ++++- src/cli/etc/onevmgroup.yaml | 8 +++++++- src/cli/one_helper/onevmgroup_helper.rb | 16 ++++++++++++++-- src/common/NebulaUtil.cc | 19 +++++++++++++++++++ src/oca/ruby/opennebula/vm_group.rb | 5 +++++ src/rm/Request.cc | 2 ++ 9 files changed, 61 insertions(+), 19 deletions(-) diff --git a/include/NebulaUtil.h b/include/NebulaUtil.h index 029faab109..1289d6623c 100644 --- a/include/NebulaUtil.h +++ b/include/NebulaUtil.h @@ -96,22 +96,14 @@ namespace one_util * @param st string to split * @param delim delimiter character * @param result where the result will be saved - * @param clean_empty true to clean empty split parts. - * Example for st "a::b:c" - * clean_empty true will return ["a", "b", "c"] - * clean_empty fase will return ["a", "", "b", "c"] */ template - void split_unique( - const std::string& st, - char delim, - std::set& result, - bool clean_empty=true) + void split_unique(const std::string& st, char delim, std::set& result) { T elem; std::vector::const_iterator it; - std::vector strings = split(st, delim, clean_empty); + std::vector strings = split(st, delim, true); for (it = strings.begin(); it != strings.end(); it++) { @@ -127,6 +119,13 @@ namespace one_util } } + /** + * Explicit specialization for strings + */ + template <> + void split_unique(const std::string& st, char delim, + std::set& result); + /** * Joins the given element with the delimiter * diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index 49c3927575..6139fdaeaf 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -91,6 +91,7 @@ public: case VROUTER: return "VROUTER" ; break; case MARKETPLACE: return "MARKETPLACE" ; break; case MARKETPLACEAPP: return "MARKETPLACEAPP" ; break; + case VMGROUP: return "VMGROUP" ; break; default: return ""; } }; diff --git a/include/VMGroup.h b/include/VMGroup.h index c2c597c9f8..c2ffb5ed66 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -165,11 +165,6 @@ private: // ------------------------------------------------------------------------- // VMGroup attributes // ------------------------------------------------------------------------- - /** - * Name of the VM Group - */ - std::string name; - /** * The role set */ diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 3411ab3928..3a0c494ff6 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -18,6 +18,7 @@ #define VMGROUP_ROLE_H_ #include "PoolObjectSQL.h" +#include "NebulaUtil.h" class VMGroupPool; @@ -186,7 +187,9 @@ private: for ( it = key_set.begin(); it != key_set.end() ; ++it ) { - if ( roles.find(*it) == roles.end() ) + string rname = one_util::trim(*it); + + if ( roles.find(rname) == roles.end() ) { return false; } diff --git a/src/cli/etc/onevmgroup.yaml b/src/cli/etc/onevmgroup.yaml index f164e8d358..fdf6ec3e6e 100644 --- a/src/cli/etc/onevmgroup.yaml +++ b/src/cli/etc/onevmgroup.yaml @@ -5,7 +5,7 @@ :NAME: :desc: Name of the VM Group - :size: 20 + :size: 15 :left: true :USER: @@ -18,8 +18,14 @@ :size: 15 :left: true +:ROLES: + :desc: Roles in the VM Group + :size: 31 + :left: true + :default: - :ID - :USER - :GROUP - :NAME +- :ROLES diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index 42bf84d418..e05d4be112 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -33,7 +33,7 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper d["ID"] end - column :NAME, "Name of the VM Group", :left, :size=>20 do |d| + column :NAME, "Name of the VM Group", :left, :size=>15 do |d| d["NAME"] end @@ -46,7 +46,19 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper helper.group_name(d, options) end - default :ID, :USER, :GROUP, :NAME + column :ROLES, "Roles in the VM Group", :left, :size=>31 do |d| + roles = d["ROLES"]["ROLE"] + roles_names = "" + + if !roles.nil? + rnames = roles.collect { |i| i["NAME"] } + roles_names = rnames.join(", ") if !rnames.empty? + end + + roles_names + end + + default :ID, :USER, :GROUP, :NAME, :ROLES end table diff --git a/src/common/NebulaUtil.cc b/src/common/NebulaUtil.cc index 8679c75cfa..247aafc0c3 100644 --- a/src/common/NebulaUtil.cc +++ b/src/common/NebulaUtil.cc @@ -339,6 +339,25 @@ std::string one_util::gsub(const std::string& st, const std::string& sfind, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +namespace one_util +{ +template<> +void split_unique(const std::string& st, char delim, std::set& res) +{ + std::vector::const_iterator it; + + std::vector strings = split(st, delim, true); + + for (it = strings.begin(); it != strings.end(); it++) + { + res.insert(*it); + } +} +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + /** * Buffer length for zlib inflate/deflate */ diff --git a/src/oca/ruby/opennebula/vm_group.rb b/src/oca/ruby/opennebula/vm_group.rb index c5f4bbf977..f51ff93652 100644 --- a/src/oca/ruby/opennebula/vm_group.rb +++ b/src/oca/ruby/opennebula/vm_group.rb @@ -169,5 +169,10 @@ module OpenNebula def owner_id self['UID'].to_i end + + # [return] _Array_ with the name of roles + def role_names + self.retrieve_elements('ROLES/ROLE/NAME') + end end end diff --git a/src/rm/Request.cc b/src/rm/Request.cc index 388fe02d05..88eff5c774 100644 --- a/src/rm/Request.cc +++ b/src/rm/Request.cc @@ -63,6 +63,8 @@ string Request::object_name(PoolObjectSQL::ObjectType ob) return "marketplace"; case PoolObjectSQL::MARKETPLACEAPP: return "marketplaceapp"; + case PoolObjectSQL::VMGROUP: + return "vm group"; default: return "-"; } From 8b3abfab09c90986fda22017943ffc1a8232bf13 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 21:12:27 +0100 Subject: [PATCH 06/26] F #2347: Mora API calls for VMGroup --- include/RequestManagerChmod.h | 15 +++++++ include/RequestManagerChown.h | 20 +++++++++ include/RequestManagerRename.h | 19 +++++++++ include/RequestManagerUpdateTemplate.h | 15 +++++++ include/VMGroup.h | 6 +-- src/cli/onevmgroup | 51 ++++------------------- src/oca/ruby/opennebula/vm_group.rb | 57 +++++++------------------- src/rm/RequestManager.cc | 8 ++++ src/vm_group/VMGroup.cc | 14 +++++++ 9 files changed, 116 insertions(+), 89 deletions(-) diff --git a/include/RequestManagerChmod.h b/include/RequestManagerChmod.h index ed8881f3c3..4e83b39369 100644 --- a/include/RequestManagerChmod.h +++ b/include/RequestManagerChmod.h @@ -250,4 +250,19 @@ public: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupChmod: public RequestManagerChmod +{ +public: + VMGroupChmod(): + RequestManagerChmod("VMGroupChmod", + "Changes permission bits of a vm group") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupChmod(){}; +}; + #endif diff --git a/include/RequestManagerChown.h b/include/RequestManagerChown.h index d7840b1904..6656c27d02 100644 --- a/include/RequestManagerChown.h +++ b/include/RequestManagerChown.h @@ -341,4 +341,24 @@ public: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupChown: public RequestManagerChown +{ +public: + VMGroupChown(): + RequestManagerChown("VMGroupChown", + "Changes ownership of a vm group") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupChown(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + #endif diff --git a/include/RequestManagerRename.h b/include/RequestManagerRename.h index 8433d63f29..83b47d51cb 100644 --- a/include/RequestManagerRename.h +++ b/include/RequestManagerRename.h @@ -405,4 +405,23 @@ public: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupRename: public RequestManagerRename +{ +public: + VMGroupRename(): + RequestManagerRename("VMGroupRename", "Renames a vm group") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + #endif diff --git a/include/RequestManagerUpdateTemplate.h b/include/RequestManagerUpdateTemplate.h index 30988e99a9..021a30cbe4 100644 --- a/include/RequestManagerUpdateTemplate.h +++ b/include/RequestManagerUpdateTemplate.h @@ -343,4 +343,19 @@ public: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VMGroupUpdateTemplate : public RequestManagerUpdateTemplate +{ +public: + VMGroupUpdateTemplate(): + RequestManagerUpdateTemplate("VMGroupUpdateTemplate", + "Updates a vm group template") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmgrouppool(); + auth_object = PoolObjectSQL::VMGROUP; + }; + + ~VMGroupUpdateTemplate(){}; +}; + #endif diff --git a/include/VMGroup.h b/include/VMGroup.h index c2ffb5ed66..02d3864d67 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -148,11 +148,7 @@ private: * @param error string describing the error if any * @return 0 on success */ - int post_update_template(string& error) - { - //TODO - return 0; - }; + int post_update_template(string& error); /** * Factory method for VMGroup templates diff --git a/src/cli/onevmgroup b/src/cli/onevmgroup index e0eeb05d3d..982fa4d7ca 100755 --- a/src/cli/onevmgroup +++ b/src/cli/onevmgroup @@ -120,38 +120,21 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.show_resource(args[0],options) end -=begin - clone_desc = <<-EOT.unindent - Creates a new Security Group from an existing one - EOT - - command :clone, clone_desc, :secgroupid, :name do - helper.perform_action(args[0],options,"cloned") do |obj| - res = obj.clone(args[1]) - - if !OpenNebula.is_error?(res) - puts "ID: #{res}" - else - puts res.message - end - end - end - chgrp_desc = <<-EOT.unindent - Changes the Security Group's group + Changes the VM Group's group EOT - command :chgrp, chgrp_desc,[:range, :secgroupid_list], :groupid do + command :chgrp, chgrp_desc,[:range, :vmgroupid_list], :groupid do helper.perform_actions(args[0],options,"Group changed") do |obj| obj.chown(-1, args[1].to_i) end end chown_desc = <<-EOT.unindent - Changes the Security Group's owner and group + Changes the VM Group's owner and group EOT - command :chown, chown_desc, [:range, :secgroupid_list], :userid, + command :chown, chown_desc, [:range, :vmgroupid_list], :userid, [:groupid,nil] do gid = args[2].nil? ? -1 : args[2].to_i helper.perform_actions(args[0],options,"Owner/Group changed") do |obj| @@ -160,10 +143,10 @@ cmd=CommandParser::CmdParser.new(ARGV) do end chmod_desc = <<-EOT.unindent - Changes the Security Group permissions + Changes the VM Group permissions EOT - command :chmod, chmod_desc, [:range, :secgroupid_list], :octet do + command :chmod, chmod_desc, [:range, :vmgroupid_list], :octet do helper.perform_actions(args[0],options, "Permissions changed") do |t| t.chmod_octet(args[1]) end @@ -174,7 +157,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do be launched to modify the current content. EOT - command :update, update_desc, :secgroupid, [:file, nil], + command :update, update_desc, :vmgroupid, [:file, nil], :options=>OpenNebulaHelper::APPEND do helper.perform_action(args[0],options,"modified") do |obj| if options[:append] @@ -191,28 +174,12 @@ cmd=CommandParser::CmdParser.new(ARGV) do end rename_desc = <<-EOT.unindent - Renames the Security Group + Renames the VM Group EOT - command :rename, rename_desc, :secgroupid, :name do + command :rename, rename_desc, :vmgroupid, :name do helper.perform_action(args[0],options,"renamed") do |o| o.rename(args[1]) end end - - commit_desc = <<-EOT.unindent - Commit SG changes to associated VMs. This command is to propagate - security group rules to VMs when they are updated. This operation takes - time to iterate over all VMs in the security group, progress can be - checked through the outdated, updating and error VM sets. - EOT - - command :commit, commit_desc, :secgroupid, - :options =>[OneSecurityGroupHelper::RECOVER] do - helper.perform_action(args[0], options, "commit") do |o| - o.commit(options[:recover]==true) - end - end - -=end end diff --git a/src/oca/ruby/opennebula/vm_group.rb b/src/oca/ruby/opennebula/vm_group.rb index f51ff93652..725977bd16 100644 --- a/src/oca/ruby/opennebula/vm_group.rb +++ b/src/oca/ruby/opennebula/vm_group.rb @@ -24,12 +24,11 @@ module OpenNebula VMGROUP_METHODS = { :allocate => "vmgroup.allocate", :info => "vmgroup.info", - #:update => "vmgroup.update", + :update => "vmgroup.update", :delete => "vmgroup.delete", - #:chown => "vmgroup.chown", - #:chmod => "vmgroup.chmod", - #:clone => "vmgroup.clone", - #:rename => "vmgroup.rename" + :chown => "vmgroup.chown", + :chmod => "vmgroup.chmod", + :rename => "vmgroup.rename" } # Creates a VMGroup description with just its identifier @@ -77,17 +76,17 @@ module OpenNebula def delete() super(VMGROUP_METHODS[:delete]) end -=begin - # Replaces the securitygroup contents + + # Replaces the vm group contents # - # @param new_securitygroup [String] New securitygroup contents + # @param new_vmgroup [String] New vmgroup contents # @param append [true, false] True to append new attributes instead of # replace the whole securitygroup # # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise - def update(new_securitygroup, append=false) - super(SECGROUP_METHODS[:update], new_securitygroup, append ? 1 : 0) + def update(new_vmgroup, append=false) + super(VMGROUP_METHODS[:update], new_vmgroup, append ? 1 : 0) end # Changes the owner/group @@ -97,7 +96,7 @@ module OpenNebula # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise def chown(uid, gid) - super(SECGROUP_METHODS[:chown], uid, gid) + super(VMGROUP_METHODS[:chown], uid, gid) end # Changes the SecurityGroup permissions. @@ -106,7 +105,7 @@ module OpenNebula # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise def chmod_octet(octet) - super(SECGROUP_METHODS[:chmod], octet) + super(VMGROUP_METHODS[:chmod], octet) end # Changes the SecurityGroup permissions. @@ -116,46 +115,20 @@ module OpenNebula # otherwise def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, other_m, other_a) - super(SECGROUP_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, + super(VMGROUP_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, other_m, other_a) end - # Clones this SecurityGroup into a new one + # Renames this VMGroup # - # @param [String] name for the new SecurityGroup. - # - # @return [Integer, OpenNebula::Error] The new SecurityGroup ID in case - # of success, Error otherwise - def clone(name) - return Error.new('ID not defined') if !@pe_id - - rc = @client.call(SECGROUP_METHODS[:clone], @pe_id, name) - - return rc - end - - # Renames this SecurityGroup - # - # @param name [String] New name for the SecurityGroup. + # @param name [String] New name for the VMGroup. # # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise def rename(name) - return call(SECGROUP_METHODS[:rename], @pe_id, name) + return call(VMGROUP_METHODS[:rename], @pe_id, name) end - # Commit SG changes to associated VMs - # - # @param recover [Bool] If true will only operate on outdated and error - # VMs. This is intended for retrying updates of VMs or reinitialize the - # updating process if oned stopped or fail. - # - # @return [nil, OpenNebula::Error] nil in case of success, Error - # otherwise - def commit(recover) - return call(SECGROUP_METHODS[:commit], @pe_id, recover) - end -=end ####################################################################### # Helpers to get VMGroup information ####################################################################### diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 8be0bbd0ea..0f726b4386 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -366,6 +366,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr cluster_update(new ClusterUpdateTemplate()); xmlrpc_c::methodPtr secg_update(new SecurityGroupUpdateTemplate()); xmlrpc_c::methodPtr vrouter_update(new VirtualRouterUpdateTemplate()); + xmlrpc_c::methodPtr vmg_update(new VMGroupUpdateTemplate()); // Allocate Methods xmlrpc_c::methodPtr vm_allocate(new VirtualMachineAllocate()); @@ -453,6 +454,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_chown(new DocumentChown()); xmlrpc_c::methodPtr secg_chown(new SecurityGroupChown()); xmlrpc_c::methodPtr vrouter_chown(new VirtualRouterChown()); + xmlrpc_c::methodPtr vmg_chown(new VMGroupChown()); // Chmod Methods xmlrpc_c::methodPtr vm_chmod(new VirtualMachineChmod()); @@ -463,6 +465,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_chmod(new DocumentChmod()); xmlrpc_c::methodPtr secg_chmod(new SecurityGroupChmod()); xmlrpc_c::methodPtr vrouter_chmod(new VirtualRouterChmod()); + xmlrpc_c::methodPtr vmg_chmod(new VMGroupChmod()); // Cluster Methods xmlrpc_c::methodPtr cluster_addhost(new ClusterAddHost()); @@ -487,6 +490,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr host_rename(new HostRename()); xmlrpc_c::methodPtr secg_rename(new SecurityGroupRename()); xmlrpc_c::methodPtr vrouter_rename(new VirtualRouterRename()); + xmlrpc_c::methodPtr vmg_rename(new VMGroupRename()); // Virtual Router Methods xmlrpc_c::methodPtr vrouter_instantiate(new VirtualRouterInstantiate()); @@ -838,6 +842,10 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vmgroup.allocate", vmg_allocate); RequestManagerRegistry.addMethod("one.vmgroup.delete", vmg_delete); RequestManagerRegistry.addMethod("one.vmgroup.info", vmg_info); + RequestManagerRegistry.addMethod("one.vmgroup.chown", vmg_chown); + RequestManagerRegistry.addMethod("one.vmgroup.chmod", vmg_chmod); + RequestManagerRegistry.addMethod("one.vmgroup.rename", vmg_rename); + RequestManagerRegistry.addMethod("one.vmgroup.update", vmg_update); RequestManagerRegistry.addMethod("one.vmgrouppool.info", vmgpool_info); diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index e968ed8466..1004eb7d91 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -457,3 +457,17 @@ int VMGroup::insert(SqlDB *db, string& error_str) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VMGroup::post_update_template(string& error) +{ + if ( check_affinity("AFFINED", error) == -1 ) + { + return -1; + } + + if ( check_affinity("ANTI_AFFINED", error) == -1 ) + { + return -1; + } + + return 0; +} From 1b4c543712c6981090405c0bfab5353b2812394f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 3 Jan 2017 23:08:47 +0100 Subject: [PATCH 07/26] F #2347: Add/del methods for VMGroup --- include/VMGroup.h | 24 ++++++++++++++++++++++++ include/VMGroupRole.h | 32 ++++++++++++++++++++++++++++++++ src/vm_group/VMGroup.cc | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/include/VMGroup.h b/include/VMGroup.h index 02d3864d67..4452f0cd0c 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -96,6 +96,30 @@ private: */ int check_affinity(const std::string& aname, std::string& error_str); + /** + * Adds a VM to a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int add_vm(const std::string& role_name, int vmid) + { + return roles.add_vm(role_name, vmid); + } + + /** + * Deletes a VM from a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int del_vm(const std::string& role_name, int vmid) + { + return roles.del_vm(role_name, vmid); + } + // ------------------------------------------------------------------------- // DataBase implementation // ------------------------------------------------------------------------- diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 3a0c494ff6..1c0c7f8086 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -118,6 +118,24 @@ public: return by_name.in_map(key_str); } + /** + * Adds a VM to a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int add_vm(const std::string& role_name, int vmid); + + /** + * Deletes a VM from a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int del_vm(const std::string& role_name, int vmid); + private: /** * A role map indexed by different key types @@ -155,6 +173,20 @@ private: clear(); } + VMGroupRole * get(T k) + { + typename std::map::iterator it; + + it = roles.find(k); + + if ( it == roles.end() ) + { + return 0; + } + + return it->second; + } + /** * Clears the contents of the map */ diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 1004eb7d91..890740a44b 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -164,6 +164,44 @@ int VMGroupRoles::add_role(VectorAttribute * vrole, string& error) return 0; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::add_vm(const std::string& role_name, int vmid) +{ + VMGroupRole * role; + + role = by_name.get(role_name); + + if ( role == 0 ) + { + return -1; + } + + role->add_vm(vmid); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::del_vm(const std::string& role_name, int vmid) +{ + VMGroupRole * role; + + role = by_name.get(role_name); + + if ( role == 0 ) + { + return -1; + } + + role->del_vm(vmid); + + return 0; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroup */ @@ -471,3 +509,4 @@ int VMGroup::post_update_template(string& error) return 0; } + From a6fc7b23cbd28ad6eaa3ab1987ec0ca0d9964fb5 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 4 Jan 2017 15:23:35 +0100 Subject: [PATCH 08/26] F #2347: VMs are added/removed from VMGROUP roles. VMGROUP with VMs cannot be updated --- include/VMGroup.h | 51 ++++++----- include/VMGroupRole.h | 70 +++++++++++++- include/VirtualMachine.h | 17 +++- src/dm/DispatchManagerActions.cc | 1 + src/dm/DispatchManagerStates.cc | 2 + src/vm/VirtualMachine.cc | 153 ++++++++++++++++++++++++++++++- src/vm_group/VMGroup.cc | 24 +++++ 7 files changed, 287 insertions(+), 31 deletions(-) diff --git a/include/VMGroup.h b/include/VMGroup.h index 4452f0cd0c..489008ed70 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -70,6 +70,33 @@ public: return new Template(*obj_template); }; + // ------------------------------------------------------------------------- + // Role Management + // ------------------------------------------------------------------------- + /** + * Adds a VM to a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int add_vm(const std::string& role_name, int vmid) + { + return roles.add_vm(role_name, vmid); + } + + /** + * Deletes a VM from a role + * @param role_name + * @param vmid + * + * @return 0 if VM was successfully added, -1 otherwise + */ + int del_vm(const std::string& role_name, int vmid) + { + return roles.del_vm(role_name, vmid); + } + private: // ------------------------------------------------------------------------- // Friends @@ -96,30 +123,6 @@ private: */ int check_affinity(const std::string& aname, std::string& error_str); - /** - * Adds a VM to a role - * @param role_name - * @param vmid - * - * @return 0 if VM was successfully added, -1 otherwise - */ - int add_vm(const std::string& role_name, int vmid) - { - return roles.add_vm(role_name, vmid); - } - - /** - * Deletes a VM from a role - * @param role_name - * @param vmid - * - * @return 0 if VM was successfully added, -1 otherwise - */ - int del_vm(const std::string& role_name, int vmid) - { - return roles.del_vm(role_name, vmid); - } - // ------------------------------------------------------------------------- // DataBase implementation // ------------------------------------------------------------------------- diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 1c0c7f8086..72de052760 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -136,6 +136,11 @@ public: */ int del_vm(const std::string& role_name, int vmid); + /** + * @return the total number of VMs in the group + */ + int vm_size(); + private: /** * A role map indexed by different key types @@ -230,12 +235,75 @@ private: return true; } - private: + /** + * Iterators for the map + */ typedef typename std::map::iterator roles_it; + roles_it begin() + { + return roles.begin(); + } + + roles_it end() + { + return roles.end(); + } + + private: std::map roles; }; + class RoleIterator + { + public: + RoleIterator& operator=(const RoleIterator& rhs) + { + role_it = rhs.role_it; + return *this; + } + + RoleIterator& operator++() + { + ++role_it; + return *this; + } + + bool operator!=(const RoleIterator& rhs) + { + return role_it != rhs.role_it; + } + + VMGroupRole * operator*() const + { + return role_it->second; + } + + RoleIterator(){}; + RoleIterator(const RoleIterator& rit):role_it(rit.role_it){}; + RoleIterator(const std::map::iterator& _role_it) + :role_it(_role_it){}; + + virtual ~RoleIterator(){}; + + private: + std::map::iterator role_it; + }; + + RoleIterator begin() + { + RoleIterator it(by_id.begin()); + return it; + } + + RoleIterator end() + { + RoleIterator it(by_id.end()); + return it; + } + + typedef class RoleIterator role_iterator; + /** * The role template to store the VMGroupRole */ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 3fa26008f7..aeb9f21b58 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -1085,6 +1085,14 @@ public: */ void remove_security_group(int sgid); + // ------------------------------------------------------------------------ + // Virtual Machine Groups + // ------------------------------------------------------------------------ + /** + * Remove this VM from its role and VM group if any + */ + void release_vmgroup(); + // ------------------------------------------------------------------------ // Imported VM interface // ------------------------------------------------------------------------ @@ -1999,7 +2007,7 @@ private: int parse_context_variables(VectorAttribute ** context, string& error_str); // ------------------------------------------------------------------------- - // NIC & DISK Management Helpers + // Management helpers: NIC, DISK and VMGROUP // ------------------------------------------------------------------------- /** * Get all network leases for this Virtual Machine @@ -2014,6 +2022,13 @@ private: */ int get_disk_images(string &error_str); + /** + * Adds the VM to the VM group if needed + * @param error_str Returns the error reason, if any + * @return 0 if success + */ + int get_vmgroup(string& error); + // ------------------------------------------------------------------------ // Public cloud templates related functions // ------------------------------------------------------------------------ diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index 05ff168b84..c5e4b588bf 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -223,6 +223,7 @@ void DispatchManager::free_vm_resources(VirtualMachine * vm) int vmid; vm->release_network_leases(); + vm->release_vmgroup(); vm->release_disk_images(ds_quotas); vm->set_exit_time(time(0)); diff --git a/src/dm/DispatchManagerStates.cc b/src/dm/DispatchManagerStates.cc index 276b6fcf9b..cb48a9f1a9 100644 --- a/src/dm/DispatchManagerStates.cc +++ b/src/dm/DispatchManagerStates.cc @@ -230,6 +230,8 @@ void DispatchManager::done_action(int vid) { vm->release_network_leases(); + vm->release_vmgroup(); + vm->release_disk_images(ds_quotas); vm->set_state(VirtualMachine::DONE); diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 22caf2a6f3..c697190062 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -741,12 +741,8 @@ int VirtualMachine::insert(SqlDB * db, string& error_str) // ------------------------------------------------------------------------ // Set a name if the VM has not got one and VM_ID // ------------------------------------------------------------------------ - - oss << oid; - value = oss.str(); - user_obj_template->erase("VMID"); - obj_template->add("VMID", value); + obj_template->add("VMID", oid); user_obj_template->get("TEMPLATE_ID", value); user_obj_template->erase("TEMPLATE_ID"); @@ -1019,6 +1015,14 @@ int VirtualMachine::insert(SqlDB * db, string& error_str) } } + // ------------------------------------------------------------------------ + // Associate to VM Group + // ------------------------------------------------------------------------ + if ( get_vmgroup(error_str) == -1 ) + { + goto error_rollback; + } + // ------------------------------------------------------------------------ parse_well_known_attributes(); @@ -2883,6 +2887,145 @@ int VirtualMachine::set_detach_nic(int nic_id) return 0; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* VirtualMachine VMGroup interface */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VirtualMachine::get_vmgroup(string& error) +{ + vector vmgroups; + vector::iterator it; + + bool found; + VectorAttribute * thegroup = 0; + + user_obj_template->remove("VMGROUP", vmgroups); + + for (it = vmgroups.begin(), found = false; it != vmgroups.end(); ) + { + if ( (*it)->type() != Attribute::VECTOR || found ) + { + delete *it; + it = vmgroups.erase(it); + } + else + { + thegroup = dynamic_cast(*it); + found = true; + + ++it; + } + } + + if ( thegroup == 0 ) + { + return 0; + } + + /* ------------------ Get the VMGroup by_name or by_id ------------------ */ + VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); + VMGroup * vmgroup; + + string vmg_role = thegroup->vector_value("ROLE"); + string vmg_name = thegroup->vector_value("VMGROUP"); + int vmg_id; + + if ( vmg_role.empty() ) + { + error = "Missing role name in VM Group definition"; + delete thegroup; + + return -1; + } + + if ( !vmg_name.empty() ) + { + int vmg_uid; + + if ( thegroup->vector_value("VMGROUP_UID", vmg_uid) == -1 ) + { + vmg_uid = get_uid(); + } + + vmgroup = vmgrouppool->get(gname, vmg_uid, true); + } + else if ( thegroup->vector_value("VMGROUP_ID", vmg_id) == 0 ) + { + vmgroup = vmgrouppool->get(vmg_id, true); + } + + if ( vmgroup == 0 ) + { + error = "Cannot find VM Group to associate the VM to"; + delete thegroup; + + return -1; + } + + /* ------------------ Add VM to the role in the vm group ---------------- */ + + thegroup->replace("VMGROUP_ID", vmgroup->get_oid()); + + int rc = vmgroup->add_vm(vmg_role, get_oid()); + + + if ( rc != 0 ) + { + error = "Role does not exist in VM Group"; + delete thegroup; + } + else + { + vmgrouppool->update(vmgroup); + + obj_template->set(thegroup); + } + + vmgroup->unlock(); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::release_vmgroup() +{ + VectorAttribute * thegroup = obj_template->get("VMGROUP"); + + if ( thegroup == 0 ) + { + return; + } + + int vmg_id; + + if ( thegroup->vector_value("VMGROUP_ID", vmg_id) == -1 ) + { + return; + } + + string vmg_role = thegroup->vector_value("ROLE"); + + if ( vmg_role.empty() ) + { + return; + } + + VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); + VMGroup * vmgroup = vmgrouppool->get(vmg_id, true); + + if ( vmgroup == 0 ) + { + return; + } + + vmgroup->del_vm(vmg_role, get_oid()); + + vmgrouppool->update(vmgroup); + + vmgroup->unlock(); +} + diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 890740a44b..21c01460d7 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -202,6 +202,18 @@ int VMGroupRoles::del_vm(const std::string& role_name, int vmid) return 0; } +int VMGroupRoles::vm_size() +{ + int total = 0; + + for ( role_iterator it = begin(); it != end() ; ++it ) + { + total += (*it)->get_vms().size(); + } + + return total; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroup */ @@ -497,6 +509,18 @@ int VMGroup::insert(SqlDB *db, string& error_str) int VMGroup::post_update_template(string& error) { + int vms = roles.vm_size(); + + if ( vms > 0 ) + { + ostringstream oss; + + oss << "VM Group has " << vms << " VMs"; + error = oss.str(); + + return -1; + } + if ( check_affinity("AFFINED", error) == -1 ) { return -1; From 20d10c7b12a868d34d21a0e3419bfaca3b2a8d41 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 5 Jan 2017 00:32:14 +0100 Subject: [PATCH 09/26] F #2347: Fixes some bugs to VMGroups --- src/vm/VirtualMachine.cc | 2 +- src/vm_group/VMGroup.cc | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index c697190062..5b12f85604 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -2949,7 +2949,7 @@ int VirtualMachine::get_vmgroup(string& error) vmg_uid = get_uid(); } - vmgroup = vmgrouppool->get(gname, vmg_uid, true); + vmgroup = vmgrouppool->get(vmg_name, vmg_uid, true); } else if ( thegroup->vector_value("VMGROUP_ID", vmg_id) == 0 ) { diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 21c01460d7..e18a298f60 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -63,6 +63,12 @@ void VMGroupRole::del_vm(int vm_id) void VMGroupRole::set_vms() { + if ( vms.empty() ) + { + va->remove("VMS"); + return; + } + std::string vms_str = one_util::join(vms.begin(), vms.end(), ','); va->replace("VMS", vms_str); @@ -521,6 +527,8 @@ int VMGroup::post_update_template(string& error) return -1; } + obj_template->erase("ROLE"); + if ( check_affinity("AFFINED", error) == -1 ) { return -1; From 0cd63c2d531136123bf09fc5d27b971f423eb2ae Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 5 Jan 2017 02:07:30 +0100 Subject: [PATCH 10/26] F #2347: ACL support for VMGroups --- src/acl/AclManager.cc | 5 +++-- src/acl/AclRule.cc | 10 ++++++---- src/cli/etc/oneacl.yaml | 6 +++--- src/cli/one_helper/oneacl_helper.rb | 10 ++++++---- src/oca/ruby/opennebula/acl.rb | 4 +++- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index c6edc990ea..b04c57724e 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -83,7 +83,7 @@ AclManager::AclManager( string error_str; // Users in group USERS can create standard resources - // @1 VM+IMAGE+TEMPLATE+DOCUMENT/* CREATE * + // @1 VM+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VMGROUP/* CREATE * add_rule(AclRule::GROUP_ID | 1, AclRule::ALL_ID | @@ -91,7 +91,8 @@ AclManager::AclManager( PoolObjectSQL::IMAGE | PoolObjectSQL::TEMPLATE | PoolObjectSQL::DOCUMENT | - PoolObjectSQL::SECGROUP, + PoolObjectSQL::SECGROUP | + PoolObjectSQL::VMGROUP, AuthRequest::CREATE, AclRule::ALL_ID, error_str); diff --git a/src/acl/AclRule.cc b/src/acl/AclRule.cc index 9a8dbb72b5..646261ab87 100644 --- a/src/acl/AclRule.cc +++ b/src/acl/AclRule.cc @@ -28,7 +28,7 @@ const long long AclRule::CLUSTER_ID = 0x0000000800000000LL; const long long AclRule::NONE_ID = 0x1000000000000000LL; -const int AclRule::num_pool_objects = 16; +const int AclRule::num_pool_objects = 17; const PoolObjectSQL::ObjectType AclRule::pool_objects[] = { PoolObjectSQL::VM, PoolObjectSQL::HOST, @@ -45,7 +45,8 @@ const PoolObjectSQL::ObjectType AclRule::pool_objects[] = { PoolObjectSQL::VDC, PoolObjectSQL::VROUTER, PoolObjectSQL::MARKETPLACE, - PoolObjectSQL::MARKETPLACEAPP + PoolObjectSQL::MARKETPLACEAPP, + PoolObjectSQL::VMGROUP }; const int AclRule::num_auth_operations = 4; @@ -61,7 +62,8 @@ const long long AclRule::INVALID_CLUSTER_OBJECTS = PoolObjectSQL::TEMPLATE | PoolObjectSQL::GROUP | PoolObjectSQL::ACL | PoolObjectSQL::CLUSTER | PoolObjectSQL::DOCUMENT | PoolObjectSQL::ZONE | PoolObjectSQL::SECGROUP | PoolObjectSQL::VDC | PoolObjectSQL::VROUTER | - PoolObjectSQL::MARKETPLACE | PoolObjectSQL::MARKETPLACEAPP; + PoolObjectSQL::MARKETPLACE | PoolObjectSQL::MARKETPLACEAPP | + PoolObjectSQL::VMGROUP; const long long AclRule::INVALID_GROUP_OBJECTS = PoolObjectSQL::HOST | PoolObjectSQL::GROUP | PoolObjectSQL::CLUSTER | @@ -237,7 +239,7 @@ bool AclRule::malformed(string& error_str) const oss << "[resource] type is missing"; } - if ( (resource & 0xFFE0000000000000LL) != 0 ) + if ( (resource & 0xFFC0000000000000LL) != 0 ) { if ( error ) { diff --git a/src/cli/etc/oneacl.yaml b/src/cli/etc/oneacl.yaml index f08817d68b..035116f78f 100644 --- a/src/cli/etc/oneacl.yaml +++ b/src/cli/etc/oneacl.yaml @@ -9,9 +9,9 @@ :size: 8 :right: true -:RES_VHNIUTGDCOZSvRMA: +:RES_VHNIUTGDCOZSvRMAP: :desc: Which resource the rule applies to - :size: 20 + :size: 21 :RID: :desc: Resource ID @@ -31,7 +31,7 @@ :default: - :ID - :USER -- :RES_VHNIUTGDCOZSvRMA +- :RES_VHNIUTGDCOZSvRMAP - :RID - :OPE_UMAC - :ZONE diff --git a/src/cli/one_helper/oneacl_helper.rb b/src/cli/one_helper/oneacl_helper.rb index bad52a9e4f..8c1ed2dfb0 100644 --- a/src/cli/one_helper/oneacl_helper.rb +++ b/src/cli/one_helper/oneacl_helper.rb @@ -44,7 +44,7 @@ private def self.resource_mask(str) resource_type=str.split("/")[0] - mask = "----------------" + mask = "-----------------" resource_type.split("+").each{|type| case type @@ -80,6 +80,8 @@ private mask[14] = "M" when "MARKETPLACEAPP" mask[15] = "A" + when "VMGROUP" + mask[16] = "P" end } mask @@ -119,8 +121,8 @@ private d['STRING'].split(" ")[0] end - column :RES_VHNIUTGDCOZSvRMA, "Resource to which the rule applies", - :size => 20 do |d| + column :RES_VHNIUTGDCOZSvRMAP, "Resource to which the rule applies", + :size => 21 do |d| OneAclHelper::resource_mask d['STRING'].split(" ")[1] end @@ -137,7 +139,7 @@ private OneAclHelper::right_mask d['STRING'].split(" ")[2] end - default :ID, :USER, :RES_VHNIUTGDCOZSvRMA, :RID, :OPE_UMAC, :ZONE + default :ID, :USER, :RES_VHNIUTGDCOZSvRMAP, :RID, :OPE_UMAC, :ZONE end table diff --git a/src/oca/ruby/opennebula/acl.rb b/src/oca/ruby/opennebula/acl.rb index 57e07fe1e0..9d54b12f88 100644 --- a/src/oca/ruby/opennebula/acl.rb +++ b/src/oca/ruby/opennebula/acl.rb @@ -36,6 +36,7 @@ module OpenNebula # VROUTER # MARKETPLACE # MARKETPLACEAPP + # VMGROUP # RIGHTS -> + separated list # USE # MANAGE @@ -67,7 +68,8 @@ module OpenNebula "VDC" => 0x2000000000000, "VROUTER" => 0x4000000000000, "MARKETPLACE" => 0x8000000000000, - "MARKETPLACEAPP"=> 0x10000000000000 + "MARKETPLACEAPP"=> 0x10000000000000, + "VMGROUP" => 0x20000000000000 } RIGHTS = From a85f4a6383ea9e91cbe8333aec1bf244d6508f18 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 5 Jan 2017 13:45:19 +0100 Subject: [PATCH 11/26] F #2347: Show the total number of VMs in Group in list --- src/cli/etc/onevmgroup.yaml | 12 +++++++++--- src/cli/one_helper/onevmgroup_helper.rb | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/cli/etc/onevmgroup.yaml b/src/cli/etc/onevmgroup.yaml index fdf6ec3e6e..a0f96ff19e 100644 --- a/src/cli/etc/onevmgroup.yaml +++ b/src/cli/etc/onevmgroup.yaml @@ -10,17 +10,22 @@ :USER: :desc: Username of the VM Group owner - :size: 15 + :size: 8 :left: true :GROUP: :desc: Group of the VM Group - :size: 15 + :size: 8 :left: true +:VMS: + :desc: Number of VMs in the VM Group + :size: 4 + :lef: true + :ROLES: :desc: Roles in the VM Group - :size: 31 + :size: 36 :left: true :default: @@ -28,4 +33,5 @@ - :USER - :GROUP - :NAME +- :VMS - :ROLES diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index e05d4be112..ec2883c271 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -38,15 +38,28 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper end column :USER, "Username of the VM Group owner", :left, - :size=>15 do |d| + :size=>8 do |d| helper.user_name(d, options) end - column :GROUP, "Group of the VM Group", :left, :size=>15 do |d| + column :GROUP, "Group of the VM Group", :left, :size=>8 do |d| helper.group_name(d, options) end - column :ROLES, "Roles in the VM Group", :left, :size=>31 do |d| + column :VMS, "Number of VMs in the VM Group", :left, :size=>4 do |d| + roles = d["ROLES"]["ROLE"] + vms = 0 + + if !roles.nil? + roles.each { |r| + vms += r["VMS"].split(',').size if !r["VMS"].nil? + } + end + + vms + end + + column :ROLES, "Roles in the VM Group", :left, :size=>36 do |d| roles = d["ROLES"]["ROLE"] roles_names = "" @@ -58,7 +71,7 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper roles_names end - default :ID, :USER, :GROUP, :NAME, :ROLES + default :ID, :USER, :GROUP, :NAME, :VMS, :ROLES end table From a1c1dee188a75d0375525d9045818ae72177efac Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 5 Jan 2017 16:51:30 +0100 Subject: [PATCH 12/26] F #2347: Moved VMGroup logic from VirtualMachine to VMGroupPool. Added authorization tests to VMGroup usage in VMs --- include/Template.h | 16 ++--- include/VMGroupPool.h | 37 ++++++++++- src/vm/VirtualMachine.cc | 92 +++++--------------------- src/vm_group/VMGroupPool.cc | 126 +++++++++++++++++++++++++++++++++++- 4 files changed, 184 insertions(+), 87 deletions(-) diff --git a/include/Template.h b/include/Template.h index 70157ef32f..4c45094931 100644 --- a/include/Template.h +++ b/include/Template.h @@ -326,15 +326,15 @@ public: * @param name the attribute name. * @return true first attribute or 0 if not found or wrong type */ - inline const VectorAttribute * get(const string& name) const - { - return __get(name); - } + inline const VectorAttribute * get(const string& name) const + { + return __get(name); + } - inline VectorAttribute * get(const string& name) - { - return __get(name); - } + inline VectorAttribute * get(const string& name) + { + return __get(name); + } /** * Gets the value of a SingleAttribute with the given name and converts diff --git a/include/VMGroupPool.h b/include/VMGroupPool.h index 51f471e4d0..ae31a50880 100644 --- a/include/VMGroupPool.h +++ b/include/VMGroupPool.h @@ -20,6 +20,8 @@ #include "PoolSQL.h" #include "VMGroup.h" +class AuthRequest; + class VMGroupPool : public PoolSQL { public: @@ -107,8 +109,34 @@ public: return PoolSQL::dump(os, "VM_GROUP_POOL", VMGroup::table, where, limit); }; -private: + /** + * Parse the VMGROUP definition in a VM and fills the ROLE attributes. It + * also adds the VM to the role if found. + * @param va the vector attribute + * @param uid VM owner, used as default to look for the VMGroup + * @param vid of the VM + * @param err if any + * + * @return 0 on success + */ + int vmgroup_attribute(VectorAttribute * va, int uid, int vid, string& err); + /** + * Removes VM from the VMGroup + * @param va with VMGROUP + * @param vid of the VM to be removed + */ + void del_vm(const VectorAttribute * va, int vid); + + /** + * Builds the AuthRequest for the VMGroup + * @param va with the VMGROUP + * @param uid VM owber, used as default to look for the VMGroup + * @param ar the authrequest + */ + void authorize(const VectorAttribute * va, int uid, AuthRequest* ar); + +private: /** * Factory method to produce objects * @return a pointer to the new object @@ -117,6 +145,13 @@ private: { return new VMGroup(-1,-1,"","",0,0); }; + + /** + * Gest a VMGroup from its vector attribute description + * @param va the VectorAttribute + * @param _uid default uid to look for the VMGroup + */ + VMGroup * get_from_attribute(const VectorAttribute *va, int _uid); }; #endif /*VMGROUP_POOL_H_*/ diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 5b12f85604..017d7a9bab 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -1913,6 +1913,15 @@ void VirtualMachine::set_auth_request(int uid, { (*nic)->authorize(uid, &ar); } + + const VectorAttribute * vmgroup = tmpl->get("VMGROUP"); + + if ( vmgroup != 0 ) + { + VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); + + vmgrouppool->authorize(vmgroup, uid, &ar); + } } /* -------------------------------------------------------------------------- */ @@ -2924,68 +2933,21 @@ int VirtualMachine::get_vmgroup(string& error) return 0; } - /* ------------------ Get the VMGroup by_name or by_id ------------------ */ VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); - VMGroup * vmgroup; - - string vmg_role = thegroup->vector_value("ROLE"); - string vmg_name = thegroup->vector_value("VMGROUP"); - int vmg_id; - - if ( vmg_role.empty() ) - { - error = "Missing role name in VM Group definition"; - delete thegroup; - - return -1; - } - - if ( !vmg_name.empty() ) - { - int vmg_uid; - - if ( thegroup->vector_value("VMGROUP_UID", vmg_uid) == -1 ) - { - vmg_uid = get_uid(); - } - - vmgroup = vmgrouppool->get(vmg_name, vmg_uid, true); - } - else if ( thegroup->vector_value("VMGROUP_ID", vmg_id) == 0 ) - { - vmgroup = vmgrouppool->get(vmg_id, true); - } - - if ( vmgroup == 0 ) - { - error = "Cannot find VM Group to associate the VM to"; - delete thegroup; - - return -1; - } - - /* ------------------ Add VM to the role in the vm group ---------------- */ - - thegroup->replace("VMGROUP_ID", vmgroup->get_oid()); - - int rc = vmgroup->add_vm(vmg_role, get_oid()); + int rc; + rc = vmgrouppool->vmgroup_attribute(thegroup, get_uid(), get_oid(), error); if ( rc != 0 ) { - error = "Role does not exist in VM Group"; delete thegroup; - } - else - { - vmgrouppool->update(vmgroup); - obj_template->set(thegroup); + return -1; } - vmgroup->unlock(); + obj_template->set(thegroup); - return rc; + return 0; } /* -------------------------------------------------------------------------- */ @@ -3000,32 +2962,8 @@ void VirtualMachine::release_vmgroup() return; } - int vmg_id; - - if ( thegroup->vector_value("VMGROUP_ID", vmg_id) == -1 ) - { - return; - } - - string vmg_role = thegroup->vector_value("ROLE"); - - if ( vmg_role.empty() ) - { - return; - } - VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); - VMGroup * vmgroup = vmgrouppool->get(vmg_id, true); - if ( vmgroup == 0 ) - { - return; - } - - vmgroup->del_vm(vmg_role, get_oid()); - - vmgrouppool->update(vmgroup); - - vmgroup->unlock(); + vmgrouppool->del_vm(thegroup, get_oid()); } diff --git a/src/vm_group/VMGroupPool.cc b/src/vm_group/VMGroupPool.cc index feb513fe60..14a2ea3cab 100644 --- a/src/vm_group/VMGroupPool.cc +++ b/src/vm_group/VMGroupPool.cc @@ -14,8 +14,8 @@ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ - #include "VMGroupPool.h" +#include "AuthRequest.h" int VMGroupPool::allocate(int uid, int gid, const string& uname, const string& gname, int umask, Template * vmgroup_template, int * oid, @@ -59,3 +59,127 @@ error_name: return *oid; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +VMGroup * VMGroupPool::get_from_attribute(const VectorAttribute *va, int _uid) +{ + VMGroup * vmgroup = 0; + + string vmg_name = va->vector_value("VMGROUP_NAME"); + int vmg_id; + + if ( !vmg_name.empty() ) + { + int vmg_uid; + + if ( va->vector_value("VMGROUP_UID", vmg_uid) == -1 ) + { + vmg_uid = _uid; + } + + vmgroup = get(vmg_name, vmg_uid, true); + } + else if ( va->vector_value("VMGROUP_ID", vmg_id) == 0 ) + { + vmgroup = get(vmg_id, true); + } + + return vmgroup; +} + +/* -------------------------------------------------------------------------- */ + +int VMGroupPool::vmgroup_attribute(VectorAttribute * va, int uid, int vid, + string& error) +{ + string vmg_role = va->vector_value("ROLE"); + + if ( vmg_role.empty() ) + { + error = "Missing role name in VM Group definition"; + return -1; + } + + VMGroup * vmgroup = get_from_attribute(va, uid); + + if ( vmgroup == 0 ) + { + error = "Cannot find VM Group to associate the VM"; + return -1; + } + + va->replace("VMGROUP_ID", vmgroup->get_oid()); + + int rc = vmgroup->add_vm(vmg_role, vid); + + if ( rc != 0 ) + { + error = "Role does not exist in VM Group"; + } + else + { + update(vmgroup); + } + + vmgroup->unlock(); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VMGroupPool::del_vm(const VectorAttribute * va, int vid) +{ + int vmg_id; + + if ( va->vector_value("VMGROUP_ID", vmg_id) == -1 ) + { + return; + } + + string vmg_role = va->vector_value("ROLE"); + + if ( vmg_role.empty() ) + { + return; + } + + VMGroup * vmgroup = get(vmg_id, true); + + if ( vmgroup == 0 ) + { + return; + } + + vmgroup->del_vm(vmg_role, vid); + + update(vmgroup); + + vmgroup->unlock(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VMGroupPool::authorize(const VectorAttribute * va, int uid,AuthRequest* ar) +{ + PoolObjectAuth perm; + + VMGroup * vmgroup = get_from_attribute(va, uid); + + if ( vmgroup == 0 ) + { + return; + } + + vmgroup->get_permissions(perm); + + vmgroup->unlock(); + + ar->add_auth(AuthRequest::USE, perm); +} + + From 97c5fcd2f257d93f6f154f7a9500f454f62d64a3 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 13 Jan 2017 01:56:25 +0100 Subject: [PATCH 13/26] F #2347: VMGroupRule class. Methods to check rule consistency --- include/VMGroup.h | 9 ++- include/VMGroupRole.h | 84 +++++++++++--------- include/VMGroupRule.h | 138 ++++++++++++++++++++++++++++++++ src/vm/VirtualMachine.cc | 4 +- src/vm_group/VMGroup.cc | 168 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 353 insertions(+), 50 deletions(-) create mode 100644 include/VMGroupRule.h diff --git a/include/VMGroup.h b/include/VMGroup.h index 489008ed70..663179bea1 100644 --- a/include/VMGroup.h +++ b/include/VMGroup.h @@ -19,6 +19,7 @@ #include "PoolObjectSQL.h" #include "VMGroupRole.h" +#include "VMGroupRule.h" class VMGroupPool; @@ -39,6 +40,7 @@ class VMGroupPool; * ROLE = [ * NAME = "db", * ID = 1, + * POLICY = ANTI_AFFINED, * VMS = "2,3,4,5" * ] * @@ -121,7 +123,12 @@ private: * * @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 diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 72de052760..c029da52f6 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -29,6 +29,7 @@ class VMGroupPool; * ROLE = [ * NAME = "Web application servers", * ID = 12, + * POLICY = AFFINED, * VMS = "1,2,45,21" * ] * @@ -36,10 +37,35 @@ 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(){}; + /** + * @return the role id + */ + int id() + { + int rid; + + va->vector_value("ID", rid); + + return rid; + } + /* ---------------------------------------------------------------------- */ /* VMS set Interface */ /* ---------------------------------------------------------------------- */ @@ -52,6 +78,17 @@ public: 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: /** * The set of vms in the role @@ -109,14 +146,12 @@ public: int add_role(VectorAttribute * vrole, string& error); /** - * Check that a key list is defined in the name map - * @param key_str separated list of keys - * @param true if the keys are in the map + * Generates the ids corresponding to a set of role names + * @param keys the set of names + * @param keyi the set of ids + * @return 0 if all the names were successfully translated */ - bool in_map(const std::string& key_str) - { - return by_name.in_map(key_str); - } + int names_to_ids(const std::set keys, std::set& keyi); /** * Adds a VM to a role @@ -141,6 +176,11 @@ public: */ int vm_size(); + /** + * Max number of roles in a VMGroup + */ + const static int MAX_ROLES = 32; + private: /** * A role map indexed by different key types @@ -205,36 +245,6 @@ private: 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 key_set; - typename std::set::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 */ diff --git a/include/VMGroupRule.h b/include/VMGroupRule.h new file mode 100644 index 0000000000..a7e07e9f5f --- /dev/null +++ b/include/VMGroupRule.h @@ -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 +#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 roles_id):policy(p) + { + std::set::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 _roles) + :policy(p), roles(_roles){}; + + VMGroupRule(const VMGroupRule& other) + { + policy = other.policy; + roles = other.roles; + } + + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + + typedef std::set 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 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_*/ + diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 017d7a9bab..7b9af2dd9f 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -1918,9 +1918,9 @@ void VirtualMachine::set_auth_request(int uid, if ( vmgroup != 0 ) { - VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); + VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool(); - vmgrouppool->authorize(vmgroup, uid, &ar); + vmgrouppool->authorize(vmgroup, uid, &ar); } } diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index e18a298f60..205dd7a497 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -16,6 +16,35 @@ #include "VMGroup.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; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::names_to_ids(const std::set keys, + std::set& keyi) +{ + std::set::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 */ @@ -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 affined; vector::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 ) { - std::string a_str = (*jt)->value(); + std::set a_set, key_set; + std::set::iterator s_it; - if ( !roles.in_map(a_str) ) + std::set 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; - oss << "Some roles used in " << aname << " attribute (" << a_str - << ") are not defined"; + oss << "Some roles used in " << aname << " attribute (" + << (*jt)->value() << ") are not defined"; error_str = oss.str(); return -1; @@ -451,6 +514,81 @@ int VMGroup::check_affinity(const std::string& aname, std::string& error_str) return 0; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroup::get_rules(const std::string& aname, VMGroupRule::Policy policy, + VMGroupRule::rule_set& rules, std::string& error_str) +{ + vector affined; + vector::const_iterator jt; + + obj_template->get(aname, affined); + + for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) + { + std::set a_set, key_set; + std::set::iterator s_it; + + std::set id_set; + + std::pair::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) @@ -466,7 +604,17 @@ int VMGroup::insert(SqlDB *db, string& error_str) 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; @@ -492,12 +640,12 @@ int VMGroup::insert(SqlDB *db, string& error_str) return -1; } - if ( check_affinity("AFFINED", error_str) == -1 ) + if ( check_rule_names("AFFINED", error_str) == -1 ) { return -1; } - if ( check_affinity("ANTI_AFFINED", error_str) == -1 ) + if ( check_rule_names("ANTI_AFFINED", error_str) == -1 ) { return -1; } @@ -529,12 +677,12 @@ int VMGroup::post_update_template(string& error) obj_template->erase("ROLE"); - if ( check_affinity("AFFINED", error) == -1 ) + if ( check_rule_names("AFFINED", error) == -1 ) { return -1; } - if ( check_affinity("ANTI_AFFINED", error) == -1 ) + if ( check_rule_names("ANTI_AFFINED", error) == -1 ) { return -1; } From b2f15970c9789c4e1dc92e00e4c90345213d479f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 13 Jan 2017 18:32:37 +0100 Subject: [PATCH 14/26] F #2347: Add placement rules consistency checks --- include/VMGroup.h | 27 +++++++++----- include/VMGroupRole.h | 44 +++++++++++++++++++++++ include/VMGroupRule.h | 74 +++++++++++++++++++++++++++++++++----- src/vm_group/VMGroup.cc | 78 ++++++++++++++++++++++++++++++++++------- 4 files changed, 194 insertions(+), 29 deletions(-) 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; } From 9fd82d980c9a18d323ef31bd7bc2c62760108d88 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 13 Jan 2017 21:08:55 +0100 Subject: [PATCH 15/26] F #2347: Base classes for Scheduler to gather VMGroup information --- src/scheduler/include/Scheduler.h | 5 +++ src/scheduler/include/VMGroupPoolXML.h | 51 ++++++++++++++++++++++++ src/scheduler/include/VMGroupXML.h | 46 +++++++++++++++++++++ src/scheduler/src/pool/SConstruct | 2 + src/scheduler/src/pool/VMGroupPoolXML.cc | 50 +++++++++++++++++++++++ src/scheduler/src/pool/VMGroupXML.cc | 23 +++++++++++ src/scheduler/src/sched/Scheduler.cc | 35 +++++----------- 7 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 src/scheduler/include/VMGroupPoolXML.h create mode 100644 src/scheduler/include/VMGroupXML.h create mode 100644 src/scheduler/src/pool/VMGroupPoolXML.cc create mode 100644 src/scheduler/src/pool/VMGroupXML.cc diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 0067f3f462..88fea7f65f 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -19,6 +19,7 @@ #include "Log.h" #include "HostPoolXML.h" +#include "VMGroupPoolXML.h" #include "UserPoolXML.h" #include "ClusterPoolXML.h" #include "DatastorePoolXML.h" @@ -56,6 +57,7 @@ protected: dspool(0), img_dspool(0), upool(0), + vmgpool(0), acls(0), timer(0), one_xmlrpc(""), @@ -78,6 +80,7 @@ protected: delete img_dspool; delete upool; + delete vmgpool; delete acls; }; @@ -95,6 +98,8 @@ protected: ImageDatastorePoolXML * img_dspool; UserPoolXML * upool; + VMGroupPoolXML * vmgpool; + AclXML * acls; // --------------------------------------------------------------- diff --git a/src/scheduler/include/VMGroupPoolXML.h b/src/scheduler/include/VMGroupPoolXML.h new file mode 100644 index 0000000000..742d5db939 --- /dev/null +++ b/src/scheduler/include/VMGroupPoolXML.h @@ -0,0 +1,51 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* 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_POOL_XML_H_ +#define VMGROUP_POOL_XML_H_ + +#include + +#include "PoolXML.h" +#include "VMGroupXML.h" + +class VMGroupPoolXML : public PoolXML +{ +public: + + VMGroupPoolXML(Client* client):PoolXML(client){}; + + ~VMGroupPoolXML(){}; + + VMGroupXML * get(int oid) const + { + return static_cast(PoolXML::get(oid)); + }; + +protected: + + int get_suitable_nodes(std::vector& content) + { + return get_nodes("/VM_GROUP_POOL/VM_GROUP", content); + }; + + void add_object(xmlNodePtr node); + + int load_info(xmlrpc_c::value &result); +}; + +#endif /* VMGROUP_POOL_XML_H_ */ diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h new file mode 100644 index 0000000000..ed3d9ca29b --- /dev/null +++ b/src/scheduler/include/VMGroupXML.h @@ -0,0 +1,46 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* 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_XML_H_ +#define VMGROUP_XML_H_ + +#include "ObjectXML.h" + +class VMGroupXML : public ObjectXML +{ +public: + VMGroupXML(const std::string &xml_doc):ObjectXML(xml_doc) + { + init_attributes(); + }; + + VMGroupXML(const xmlNodePtr node):ObjectXML(node) + { + init_attributes(); + }; + + int get_oid() const + { + return oid; + }; + +private: + int oid; + + void init_attributes(); +}; + +#endif /* VMGROUP_XML_H_ */ diff --git a/src/scheduler/src/pool/SConstruct b/src/scheduler/src/pool/SConstruct index 80216447bc..b0380c9e46 100644 --- a/src/scheduler/src/pool/SConstruct +++ b/src/scheduler/src/pool/SConstruct @@ -28,6 +28,8 @@ source_files=[ 'VirtualMachineXML.cc', 'ClusterPoolXML.cc', 'UserPoolXML.cc', + 'VMGroupPoolXML.cc', + 'VMGroupXML.cc', 'DatastorePoolXML.cc', 'DatastoreXML.cc'] diff --git a/src/scheduler/src/pool/VMGroupPoolXML.cc b/src/scheduler/src/pool/VMGroupPoolXML.cc new file mode 100644 index 0000000000..a1c558f2e0 --- /dev/null +++ b/src/scheduler/src/pool/VMGroupPoolXML.cc @@ -0,0 +1,50 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +#include "VMGroupPoolXML.h" + +void VMGroupPoolXML::add_object(xmlNodePtr node) +{ + if ( node == 0 || node->children == 0 ) + { + NebulaLog::log("VM_GROUP", Log::ERROR, "XML Node does not represent a " + "valid user"); + return; + } + + VMGroupXML * vmg = new VMGroupXML(node); + + objects.insert( pair(vmg->get_oid(), vmg) ); +} + +int VMGroupPoolXML::load_info(xmlrpc_c::value &result) +{ + try + { + client->call("one.vmgrouppool.info", "iii", &result, -2, -1, -1); + + return 0; + } + catch (exception const& e) + { + ostringstream oss; + oss << "Exception raised: " << e.what(); + + NebulaLog::log("VMGROUP", Log::ERROR, oss); + + return -1; + } +} diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc new file mode 100644 index 0000000000..e4f962a832 --- /dev/null +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -0,0 +1,23 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +#include "VMGroupXML.h" + +void VMGroupXML::init_attributes() +{ + xpath(oid, "/VM_GROUP/ID", -1); +}; + diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index e60c0bc5e1..04d0159aae 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -320,6 +320,8 @@ void Scheduler::start() dspool = new SystemDatastorePoolXML(Client::client()); img_dspool = new ImageDatastorePoolXML(Client::client()); + vmgpool = new VMGroupPoolXML(Client::client()); + acls = new AclXML(Client::client(), zone_id); // ----------------------------------------------------------- @@ -407,7 +409,7 @@ int Scheduler::set_up_pools() map shares; //-------------------------------------------------------------------------- - //Cleans the cache and get the pending VMs + //Cleans the cache and get the pools //-------------------------------------------------------------------------- rc = vmpool->set_up(); @@ -417,10 +419,6 @@ int Scheduler::set_up_pools() return rc; } - //-------------------------------------------------------------------------- - //Cleans the cache and get the datastores - //-------------------------------------------------------------------------- - rc = dspool->set_up(); if ( rc != 0 ) @@ -435,10 +433,6 @@ int Scheduler::set_up_pools() return rc; } - //-------------------------------------------------------------------------- - //Cleans the cache and get the hosts ids - //-------------------------------------------------------------------------- - rc = upool->set_up(); if ( rc != 0 ) @@ -446,10 +440,6 @@ int Scheduler::set_up_pools() return rc; } - //-------------------------------------------------------------------------- - //Cleans the cache and get the hosts ids - //-------------------------------------------------------------------------- - rc = hpool->set_up(); if ( rc != 0 ) @@ -457,10 +447,6 @@ int Scheduler::set_up_pools() return rc; } - //-------------------------------------------------------------------------- - //Cleans the cache and get the cluster information - //-------------------------------------------------------------------------- - rc = clpool->set_up(); if ( rc != 0 ) @@ -468,16 +454,8 @@ int Scheduler::set_up_pools() return rc; } - //-------------------------------------------------------------------------- - //Add to each host the corresponding cluster template - //-------------------------------------------------------------------------- - hpool->merge_clusters(clpool); - //-------------------------------------------------------------------------- - //Cleans the cache and get the ACLs - //-------------------------------------------------------------------------- - rc = acls->set_up(); if ( rc != 0 ) @@ -485,6 +463,13 @@ int Scheduler::set_up_pools() return rc; } + rc = vmgpool->set_up(); + + if ( rc != 0 ) + { + return rc; + } + return 0; }; From 184bd79eafdbeb1fd92bcadd8a79468e165568ce Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 14 Jan 2017 18:33:26 +0100 Subject: [PATCH 16/26] F #2347: Split rule and role logic in different objects and libraries to reuse it in scheduler --- include/VMGroupRule.h | 22 +-- src/scheduler/include/VMGroupXML.h | 3 + src/scheduler/src/pool/VMGroupXML.cc | 16 +- src/scheduler/src/sched/SConstruct | 1 + src/vm_group/SConstruct | 14 +- src/vm_group/VMGroup.cc | 255 --------------------------- src/vm_group/VMGroupRole.cc | 245 +++++++++++++++++++++++++ src/vm_group/VMGroupRule.cc | 72 ++++++++ 8 files changed, 350 insertions(+), 278 deletions(-) create mode 100644 src/vm_group/VMGroupRole.cc create mode 100644 src/vm_group/VMGroupRule.cc diff --git a/include/VMGroupRule.h b/include/VMGroupRule.h index 5bdb0840c5..edb44a5eee 100644 --- a/include/VMGroupRule.h +++ b/include/VMGroupRule.h @@ -47,27 +47,7 @@ public: /** * @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; - } + static std::string policy_to_s(Policy policy); /** * A specialized set for rules diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index ed3d9ca29b..5ce001f1d2 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -18,6 +18,7 @@ #define VMGROUP_XML_H_ #include "ObjectXML.h" +#include "VMGroupRole.h" class VMGroupXML : public ObjectXML { @@ -40,6 +41,8 @@ public: private: int oid; + VMGroupRoles roles; + void init_attributes(); }; diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index e4f962a832..b1cdcec2b5 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -18,6 +18,20 @@ void VMGroupXML::init_attributes() { - xpath(oid, "/VM_GROUP/ID", -1); + vector content; + + xpath(oid, "/VM_GROUP/ID", -1); + + // VMGroup roles + get_nodes("/VM_GROUP/ROLES", content); + + if (!content.empty()) + { + roles.from_xml_node(content[0]); + } + + free_nodes(content); + + content.clear(); }; diff --git a/src/scheduler/src/sched/SConstruct b/src/scheduler/src/sched/SConstruct index 6518152b2e..72dcda9357 100644 --- a/src/scheduler/src/sched/SConstruct +++ b/src/scheduler/src/sched/SConstruct @@ -30,6 +30,7 @@ sched_env.StaticLibrary(lib_name, source_files) sched_env.Prepend(LIBS=[ 'scheduler_sched', 'scheduler_pool', + 'nebula_vmgroup_roles', 'nebula_log', 'nebula_client', 'nebula_acl', diff --git a/src/vm_group/SConstruct b/src/vm_group/SConstruct index 89900acafe..dc6f285495 100644 --- a/src/vm_group/SConstruct +++ b/src/vm_group/SConstruct @@ -23,8 +23,20 @@ lib_name='nebula_vmgroup' # Sources to generate the library source_files=[ 'VMGroupPool.cc', - 'VMGroup.cc' + 'VMGroup.cc', + 'VMGroupRole.cc', + 'VMGroupRule.cc' ] # Build library env.StaticLibrary(lib_name, source_files) + +# Stripped library for scheduler with role logic +lib_name='nebula_vmgroup_roles' + +source_files=[ + 'VMGroupRole.cc', + 'VMGroupRule.cc' +] + +env.StaticLibrary(lib_name, source_files) diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 0b411bdacb..6c7cfa1ee9 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -18,261 +18,6 @@ #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(); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* VMGroupRole */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va) -{ - string vms_str = va->vector_value("VMS"); - - if ( !vms_str.empty() ) - { - one_util::split_unique(vms_str, ',', vms); - } -} - -/* -------------------------------------------------------------------------- */ - -void VMGroupRole::add_vm(int vm_id) -{ - std::pair::iterator, bool> rc; - - rc = vms.insert(vm_id); - - if ( rc.second == false ) - { - return; - } - - set_vms(); -} - -void VMGroupRole::del_vm(int vm_id) -{ - size_t rc = vms.erase(vm_id); - - if ( rc == 0 ) - { - return; - } - - set_vms(); -} - -void VMGroupRole::set_vms() -{ - if ( vms.empty() ) - { - va->remove("VMS"); - return; - } - - std::string vms_str = one_util::join(vms.begin(), vms.end(), ','); - - va->replace("VMS", vms_str); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VMGroupRoles::from_xml_node(const xmlNodePtr node) -{ - std::vector roles; - std::vector::iterator it; - - if ( roles_template.from_xml_node(node) == -1 ) - { - return -1; - } - - roles_template.get("ROLE", roles); - - for (it = roles.begin(); it != roles.end(); ++it) - { - std::string rname = (*it)->vector_value("NAME"); - - int rid; - int rc = (*it)->vector_value("ID", rid); - - if ( rname.empty() || rc == -1 ) - { - return -1; - } - - if ( rid >= next_role ) - { - next_role = rid + 1; - } - - VMGroupRole * role = new VMGroupRole((*it)); - - if ( by_id.insert(rid, role) == false ) - { - delete role; - return -1; - } - - if ( by_name.insert(rname, role) == false ) - { - by_id.erase(rid); - - delete role; - return -1; - } - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -int VMGroupRoles::add_role(VectorAttribute * vrole, string& error) -{ - std::string rname = vrole->vector_value("NAME"); - - if ( rname.empty() ) - { - error = "Missing NAME in VM group role"; - return -1; - } - - // Remove internal attributes before inserting - vrole->replace("ID", next_role); - - vrole->remove("VMS"); - - VMGroupRole * role = new VMGroupRole(vrole); - - if ( by_id.insert(next_role, role) == false ) - { - delete role; - - error = "Role ID already exists"; - return -1; - } - - if ( by_name.insert(rname, role) == false ) - { - by_id.erase(next_role); - - delete role; - - error = "Role NAME already exists"; - return -1; - } - - next_role += 1; - - roles_template.set(vrole); - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VMGroupRoles::add_vm(const std::string& role_name, int vmid) -{ - VMGroupRole * role; - - role = by_name.get(role_name); - - if ( role == 0 ) - { - return -1; - } - - role->add_vm(vmid); - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VMGroupRoles::del_vm(const std::string& role_name, int vmid) -{ - VMGroupRole * role; - - role = by_name.get(role_name); - - if ( role == 0 ) - { - return -1; - } - - role->del_vm(vmid); - - return 0; -} - -int VMGroupRoles::vm_size() -{ - int total = 0; - - for ( role_iterator it = begin(); it != end() ; ++it ) - { - total += (*it)->get_vms().size(); - } - - return total; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VMGroupRoles::names_to_ids(const std::set keys, - std::set& keyi) -{ - std::set::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 */ diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc new file mode 100644 index 0000000000..e24636d0f5 --- /dev/null +++ b/src/vm_group/VMGroupRole.cc @@ -0,0 +1,245 @@ +/* ------------------------------------------------------------------------ */ +/* 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. */ +/* -------------------------------------------------------------------------*/ + +#include "VMGroupRole.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* VMGroupRole */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va) +{ + string vms_str = va->vector_value("VMS"); + + if ( !vms_str.empty() ) + { + one_util::split_unique(vms_str, ',', vms); + } +} + +/* -------------------------------------------------------------------------- */ + +void VMGroupRole::add_vm(int vm_id) +{ + std::pair::iterator, bool> rc; + + rc = vms.insert(vm_id); + + if ( rc.second == false ) + { + return; + } + + set_vms(); +} + +void VMGroupRole::del_vm(int vm_id) +{ + size_t rc = vms.erase(vm_id); + + if ( rc == 0 ) + { + return; + } + + set_vms(); +} + +void VMGroupRole::set_vms() +{ + if ( vms.empty() ) + { + va->remove("VMS"); + return; + } + + std::string vms_str = one_util::join(vms.begin(), vms.end(), ','); + + va->replace("VMS", vms_str); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::from_xml_node(const xmlNodePtr node) +{ + std::vector roles; + std::vector::iterator it; + + if ( roles_template.from_xml_node(node) == -1 ) + { + return -1; + } + + roles_template.get("ROLE", roles); + + for (it = roles.begin(); it != roles.end(); ++it) + { + std::string rname = (*it)->vector_value("NAME"); + + int rid; + int rc = (*it)->vector_value("ID", rid); + + if ( rname.empty() || rc == -1 ) + { + return -1; + } + + if ( rid >= next_role ) + { + next_role = rid + 1; + } + + VMGroupRole * role = new VMGroupRole((*it)); + + if ( by_id.insert(rid, role) == false ) + { + delete role; + return -1; + } + + if ( by_name.insert(rname, role) == false ) + { + by_id.erase(rid); + + delete role; + return -1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::add_role(VectorAttribute * vrole, string& error) +{ + std::string rname = vrole->vector_value("NAME"); + + if ( rname.empty() ) + { + error = "Missing NAME in VM group role"; + return -1; + } + + // Remove internal attributes before inserting + vrole->replace("ID", next_role); + + vrole->remove("VMS"); + + VMGroupRole * role = new VMGroupRole(vrole); + + if ( by_id.insert(next_role, role) == false ) + { + delete role; + + error = "Role ID already exists"; + return -1; + } + + if ( by_name.insert(rname, role) == false ) + { + by_id.erase(next_role); + + delete role; + + error = "Role NAME already exists"; + return -1; + } + + next_role += 1; + + roles_template.set(vrole); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::add_vm(const std::string& role_name, int vmid) +{ + VMGroupRole * role; + + role = by_name.get(role_name); + + if ( role == 0 ) + { + return -1; + } + + role->add_vm(vmid); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::del_vm(const std::string& role_name, int vmid) +{ + VMGroupRole * role; + + role = by_name.get(role_name); + + if ( role == 0 ) + { + return -1; + } + + role->del_vm(vmid); + + return 0; +} + +int VMGroupRoles::vm_size() +{ + int total = 0; + + for ( role_iterator it = begin(); it != end() ; ++it ) + { + total += (*it)->get_vms().size(); + } + + return total; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VMGroupRoles::names_to_ids(const std::set keys, + std::set& keyi) +{ + std::set::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; +} + diff --git a/src/vm_group/VMGroupRule.cc b/src/vm_group/VMGroupRule.cc new file mode 100644 index 0000000000..245601135c --- /dev/null +++ b/src/vm_group/VMGroupRule.cc @@ -0,0 +1,72 @@ +/* ------------------------------------------------------------------------ */ +/* 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. */ +/* -------------------------------------------------------------------------*/ + +#include "VMGroup.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(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +std::string VMGroupRule::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; +} From 70ce34693769d67c475532ab3485b694aa4b5df3 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 16 Jan 2017 19:19:05 +0100 Subject: [PATCH 17/26] F #2347: Load roles and rules in the scheduler. Helper methods to generate requirement expressions --- include/VMGroupRole.h | 132 ++++++++++-------- src/scheduler/include/PoolXML.h | 85 +++++++---- src/scheduler/include/Scheduler.h | 22 +-- src/scheduler/include/VMGroupXML.h | 8 ++ src/scheduler/include/VirtualMachinePoolXML.h | 9 ++ src/scheduler/src/pool/VMGroupXML.cc | 34 ++++- src/scheduler/src/sched/Scheduler.cc | 16 ++- src/vm_group/VMGroup.cc | 34 ++--- src/vm_group/VMGroupRole.cc | 72 +++++++++- 9 files changed, 288 insertions(+), 124 deletions(-) diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 4928acbc42..c57c007f66 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -108,12 +108,20 @@ public: /* Placement constraints */ /* ---------------------------------------------------------------------- */ /** - * Generates a string with the boolean expresion to conform the role - * policy + * Generates a string with the boolean expression to conform the role + * internal policy * @param vm_id of the VM to generate the requirements for * @param requirements */ - void vm_requirements(int vm_id, std::string requirements); + void vm_role_requirements(int vm_id, std::string& requirements); + + /** + * Generates a string with the boolean expression to conform an affinity + * constraint policy + * @param policy to place VMs respect to this role VMs + * @param requirements + */ + void role_requirements(Policy policy, std::string& requirements); private: /** @@ -145,6 +153,15 @@ public: by_id.delete_roles(); }; + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /** + * Max number of roles in a VMGroup + */ + const static int MAX_ROLES = 32; + + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ /** * Function to print the VMGroupRoles into a string in XML format * @param xml the resulting XML string @@ -173,11 +190,12 @@ public: /** * Generates the ids corresponding to a set of role names - * @param keys the set of names + * @param rnames string with a comma separated list of role names * @param keyi the set of ids + * * @return 0 if all the names were successfully translated */ - int names_to_ids(const std::set keys, std::set& keyi); + int names_to_ids(const std::string& rnames, std::set& keyi); /** * Adds a VM to a role @@ -220,10 +238,60 @@ public: return by_id.get(id); } + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ /** - * Max number of roles in a VMGroup + * Iterator for the roles in the group */ - const static int MAX_ROLES = 32; + class RoleIterator + { + public: + RoleIterator& operator=(const RoleIterator& rhs) + { + role_it = rhs.role_it; + return *this; + } + + RoleIterator& operator++() + { + ++role_it; + return *this; + } + + bool operator!=(const RoleIterator& rhs) + { + return role_it != rhs.role_it; + } + + VMGroupRole * operator*() const + { + return role_it->second; + } + + RoleIterator(){}; + RoleIterator(const RoleIterator& rit):role_it(rit.role_it){}; + RoleIterator(const std::map::iterator& _role_it) + :role_it(_role_it){}; + + virtual ~RoleIterator(){}; + + private: + std::map::iterator role_it; + }; + + RoleIterator begin() + { + RoleIterator it(by_id.begin()); + return it; + } + + RoleIterator end() + { + RoleIterator it(by_id.end()); + return it; + } + + typedef class RoleIterator role_iterator; private: /** @@ -308,56 +376,6 @@ private: std::map roles; }; - class RoleIterator - { - public: - RoleIterator& operator=(const RoleIterator& rhs) - { - role_it = rhs.role_it; - return *this; - } - - RoleIterator& operator++() - { - ++role_it; - return *this; - } - - bool operator!=(const RoleIterator& rhs) - { - return role_it != rhs.role_it; - } - - VMGroupRole * operator*() const - { - return role_it->second; - } - - RoleIterator(){}; - RoleIterator(const RoleIterator& rit):role_it(rit.role_it){}; - RoleIterator(const std::map::iterator& _role_it) - :role_it(_role_it){}; - - virtual ~RoleIterator(){}; - - private: - std::map::iterator role_it; - }; - - RoleIterator begin() - { - RoleIterator it(by_id.begin()); - return it; - } - - RoleIterator end() - { - RoleIterator it(by_id.end()); - return it; - } - - typedef class RoleIterator role_iterator; - /** * The role template to store the VMGroupRole */ diff --git a/src/scheduler/include/PoolXML.h b/src/scheduler/include/PoolXML.h index 70d867097c..bd4fab99d4 100644 --- a/src/scheduler/include/PoolXML.h +++ b/src/scheduler/include/PoolXML.h @@ -46,15 +46,15 @@ public: { int rc; - // ------------------------------------------------------------------------- + // --------------------------------------------------------------------- // Clean the pool to get updated data from OpenNebula - // ------------------------------------------------------------------------- + // --------------------------------------------------------------------- flush(); - // ------------------------------------------------------------------------- + // --------------------------------------------------------------------- // Load the ids (to get an updated list of the pool) - // ------------------------------------------------------------------------- + // --------------------------------------------------------------------- xmlrpc_c::value result; @@ -124,8 +124,49 @@ public: } }; -protected: + /** + * Gets an object and removes it from the pool. The calling function + * needs to free the object memory + * @param oid of the object + * + * @return pointer of the object 0 if not found + */ + virtual ObjectXML * erase(int oid) + { + map::iterator it; + it = objects.find(oid); + + if ( it == objects.end() ) + { + return 0; + } + else + { + ObjectXML * obj = it->second; + + objects.erase(it); + + return obj; + } + } + + /** + * Inserts a new object in the pool + * @param obj pointer to the XML object to be inserted + * + * @return true if the object was successfully inserted + */ + virtual bool insert(int oid, ObjectXML * obj) + { + pair::iterator, bool> rc; + + rc = objects.insert(pair(oid, obj)); + + return rc.second; + } + +protected: // ------------------------------------------------------------------------ PoolXML(Client* client, unsigned int pool_limit = 0):ObjectXML() @@ -140,7 +181,6 @@ protected: }; // ------------------------------------------------------------------------ - /** * Inserts a new ObjectXML into the objects map */ @@ -156,10 +196,24 @@ protected: */ virtual int load_info(xmlrpc_c::value &result) = 0; + /** + * Deletes pool objects and frees resources. + */ + void flush() + { + map::iterator it; + + for (it=objects.begin();it!=objects.end();it++) + { + delete it->second; + } + + objects.clear(); + } + // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ - /** * XML-RPC client */ @@ -175,23 +229,6 @@ protected: * Hash map contains the suitable [id, object] pairs. */ map objects; - - -private: - /** - * Deletes pool objects and frees resources. - */ - void flush() - { - map::iterator it; - - for (it=objects.begin();it!=objects.end();it++) - { - delete it->second; - } - - objects.clear(); - } }; #endif /* POOL_XML_H_ */ diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 88fea7f65f..35165e16df 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -50,15 +50,16 @@ public: protected: Scheduler(): + acls(0), + upool(0), hpool(0), clpool(0), - vmpool(0), - vmapool(0), dspool(0), img_dspool(0), - upool(0), + vmpool(0), + vm_roles_pool(0), vmgpool(0), - acls(0), + vmapool(0), timer(0), one_xmlrpc(""), machines_limit(0), @@ -74,6 +75,7 @@ protected: delete clpool; delete vmpool; + delete vm_roles_pool; delete vmapool; delete dspool; @@ -88,19 +90,21 @@ protected: // --------------------------------------------------------------- // Pools // --------------------------------------------------------------- + AclXML * acls; + UserPoolXML * upool; HostPoolXML * hpool; ClusterPoolXML * clpool; - VirtualMachinePoolXML * vmpool; - VirtualMachineActionsPoolXML* vmapool; SystemDatastorePoolXML * dspool; - ImageDatastorePoolXML * img_dspool; - UserPoolXML * upool; + ImageDatastorePoolXML * img_dspool; + + VirtualMachinePoolXML * vmpool; + VirtualMachinePoolXML * vm_roles_pool; VMGroupPoolXML * vmgpool; - AclXML * acls; + VirtualMachineActionsPoolXML* vmapool; // --------------------------------------------------------------- // Scheduler Policies diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index 5ce001f1d2..e0f834f5c8 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -19,6 +19,7 @@ #include "ObjectXML.h" #include "VMGroupRole.h" +#include "VMGroupRule.h" class VMGroupXML : public ObjectXML { @@ -39,10 +40,17 @@ public: }; private: + // ------------------------------------------------------------------------ + // VMGroup Attributes + // ------------------------------------------------------------------------ int oid; + std::string name; + VMGroupRoles roles; + VMGroupRule::rule_set rules; + void init_attributes(); }; diff --git a/src/scheduler/include/VirtualMachinePoolXML.h b/src/scheduler/include/VirtualMachinePoolXML.h index e73a806bdb..1001fa8eb2 100644 --- a/src/scheduler/include/VirtualMachinePoolXML.h +++ b/src/scheduler/include/VirtualMachinePoolXML.h @@ -84,6 +84,15 @@ public: return update(vm->get_oid(), vm->get_template(xml)); }; + /** + * + * + * */ + void clear() + { + flush(); + } + protected: int get_suitable_nodes(vector& content) diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index b1cdcec2b5..7a13f684db 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -18,9 +18,13 @@ void VMGroupXML::init_attributes() { - vector content; + vector content; + std::vector srules; + + std::vector::iterator it; xpath(oid, "/VM_GROUP/ID", -1); + xpath(name,"/VM_GROUP/NAME", "undefined"); // VMGroup roles get_nodes("/VM_GROUP/ROLES", content); @@ -33,5 +37,33 @@ void VMGroupXML::init_attributes() free_nodes(content); content.clear(); + + xpaths(srules, "/VM_GROUP/TEMPLATE/AFFINED"); + + for ( it = srules.begin() ; it != srules.end(); ++it ) + { + std::set id_set; + + roles.names_to_ids(*it, id_set); + + VMGroupRule rule(VMGroupRule::AFFINED, id_set); + + rules.insert(rule); + } + + rules.clear(); + + xpaths(srules, "/VM_GROUP/TEMPLATE/ANTI_AFFINED"); + + for ( it = srules.begin() ; it != srules.end(); ++it ) + { + std::set id_set; + + roles.names_to_ids(*it, id_set); + + VMGroupRule rule(VMGroupRule::ANTI_AFFINED, id_set); + + rules.insert(rule); + } }; diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 04d0159aae..ac0f28b91a 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -308,21 +308,23 @@ void Scheduler::start() // ------------------------------------------------------------------------- // Pools // ------------------------------------------------------------------------- + acls = new AclXML(Client::client(), zone_id); + upool = new UserPoolXML(Client::client()); hpool = new HostPoolXML(Client::client()); - upool = new UserPoolXML(Client::client()); clpool = new ClusterPoolXML(Client::client()); - vmpool = new VirtualMachinePoolXML(Client::client(), machines_limit, - live_rescheds==1); - - vmapool = new VirtualMachineActionsPoolXML(Client::client(), machines_limit); dspool = new SystemDatastorePoolXML(Client::client()); img_dspool = new ImageDatastorePoolXML(Client::client()); + vmpool = new VirtualMachinePoolXML(Client::client(), machines_limit, + live_rescheds==1); + vm_roles_pool = new VirtualMachinePoolXML(Client::client(), machines_limit, + live_rescheds==1); + vmgpool = new VMGroupPoolXML(Client::client()); - acls = new AclXML(Client::client(), zone_id); + vmapool = new VirtualMachineActionsPoolXML(Client::client(), machines_limit); // ----------------------------------------------------------- // Load scheduler policies @@ -470,6 +472,8 @@ int Scheduler::set_up_pools() return rc; } + vm_roles_pool->clear(); + return 0; }; diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index 6c7cfa1ee9..68d22e1cd2 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -235,25 +235,17 @@ int VMGroup::check_rule_names(VMGroupRule::Policy policy, std::string& error) for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) { - std::set a_set, key_set; - std::set::iterator s_it; - std::set 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 ) + if ( roles.names_to_ids((*jt)->value(), id_set) != 0 ) { std::ostringstream oss; + oss << "Some roles used in " << aname << " attribute (" << (*jt)->value() << ") are not defined"; error = oss.str(); + return -1; } } @@ -276,21 +268,11 @@ int VMGroup::get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules, for ( jt = affined.begin() ; jt != affined.end() ; ++jt ) { - std::set a_set, key_set; - std::set::iterator s_it; - std::set id_set; std::pair::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); + roles.names_to_ids((*jt)->value(), id_set); VMGroupRule rule(policy, id_set); @@ -298,8 +280,12 @@ int VMGroup::get_rules(VMGroupRule::Policy policy, VMGroupRule::rule_set& rules, if ( rc.second == false ) { - error_str = "Duplicated " + aname + " rule (" + - (*jt)->value() + ") detected."; + std::ostringstream oss; + + oss << "Duplicated " << aname << " rule (" << (*jt)->value() + << ") detected."; + + error_str = oss.str(); return -1; } diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index e24636d0f5..9a3eddd0b0 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -32,6 +32,7 @@ VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va) } } +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void VMGroupRole::add_vm(int vm_id) @@ -76,6 +77,60 @@ void VMGroupRole::set_vms() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +static void affinity_requirements(int vm_id, std::string& requirements, + VMGroupRole::Policy policy, const std::set& vms) +{ + string op; + + requirements = ""; + + switch(policy) + { + case VMGroupRole::AFFINED: + op = "="; + break; + case VMGroupRole::ANTI_AFFINED: + op = "!="; + break; + case VMGroupRole::NONE: + return; + } + + std::ostringstream oss; + std::set::const_iterator it; + + for ( it = vms.begin(); it != vms.end(); ++it ) + { + if ( vm_id == -1 || vm_id != *it ) + { + if ( it != vms.begin() ) + { + oss << " & "; + } + + oss << "( CURRENT_VMS " << op << " " << *it << ") "; + } + } + + requirements = oss.str(); +} + +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) +{ + affinity_requirements(-1, requirements, policy, vms); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* VMGroupRoles */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + int VMGroupRoles::from_xml_node(const xmlNodePtr node) { std::vector roles; @@ -125,6 +180,7 @@ int VMGroupRoles::from_xml_node(const xmlNodePtr node) return 0; } +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int VMGroupRoles::add_role(VectorAttribute * vrole, string& error) @@ -207,6 +263,9 @@ int VMGroupRoles::del_vm(const std::string& role_name, int vmid) return 0; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + int VMGroupRoles::vm_size() { int total = 0; @@ -222,12 +281,19 @@ int VMGroupRoles::vm_size() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VMGroupRoles::names_to_ids(const std::set keys, - std::set& keyi) +int VMGroupRoles::names_to_ids(const std::string& rnames, std::set& keyi) { + std::set a_set, key_set; std::set::iterator it; - for ( it = keys.begin(); it != keys.end(); ++it ) + one_util::split_unique(rnames, ',', a_set); + + for ( it = a_set.begin(); it != a_set.end() ; ++it ) + { + key_set.insert(one_util::trim(*it)); + } + + for ( it = key_set.begin(); it != key_set.end(); ++it ) { VMGroupRole *r = by_name.get(*it); From d73a57dab72ec843490eeb527f92b055f3ed058a Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 18 Jan 2017 00:31:50 +0100 Subject: [PATCH 18/26] F #2347: Dump VMGroups in scheduler output for DEBUG --- include/VMGroupRole.h | 29 ++++++++---------- include/VMGroupRule.h | 12 ++++++-- src/scheduler/include/Scheduler.h | 2 ++ src/scheduler/include/VMGroupXML.h | 2 ++ src/scheduler/src/pool/VMGroupXML.cc | 46 +++++++++++++++++++++++++++- src/scheduler/src/sched/Scheduler.cc | 29 ++++++++++++++++++ src/vm_group/VMGroupRole.cc | 40 ++++++++++++++++++++++++ src/vm_group/VMGroupRule.cc | 23 ++++++++++++++ 8 files changed, 164 insertions(+), 19 deletions(-) diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index c57c007f66..3a44abb4c0 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -74,23 +74,15 @@ public: return va->vector_value("NAME"); } - Policy policy() - { - string p = va->vector_value("POLICY"); + /** + * @return the policy of this role + */ + Policy policy(); - if ( p == "AFFINED" ) - { - return AFFINED; - } - else if ( p == "ANTI_AFFINED" ) - { - return ANTI_AFFINED; - } - else - { - return NONE; - } - } + std::string policy_s() + { + return va->vector_value("POLICY"); + }; /* ---------------------------------------------------------------------- */ /* VMS set Interface */ @@ -238,6 +230,11 @@ 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 edb44a5eee..d434062222 100644 --- a/include/VMGroupRule.h +++ b/include/VMGroupRule.h @@ -29,7 +29,6 @@ struct VMGroupRule_compare; class VMGroupRule { public: - /** * Placement policy rules for roles * AFFINED: VMs of all roles are placed in the same hypervisor @@ -43,7 +42,6 @@ public: ANTI_AFFINED= 0x02 }; - /** * @return policy name */ @@ -145,6 +143,16 @@ public: return roles; } + std::string get_policy() const + { + return policy_to_s(policy); + } + + /** + * Function to write a the rule in an output stream + */ + friend ostream& operator<<(ostream& os, const VMGroupRule& rule); + private: friend class VMGroupRule_compare; diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 35165e16df..eb8a3669c4 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -144,6 +144,8 @@ protected: virtual int do_scheduled_actions(); + virtual void do_vm_groups(); + private: Scheduler(Scheduler const&){}; diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index e0f834f5c8..45843ef16d 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -39,6 +39,8 @@ public: return oid; }; + friend ostream& operator<<(ostream& os, VMGroupXML& vmg); + private: // ------------------------------------------------------------------------ // VMGroup Attributes diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 7a13f684db..7fd37f03d7 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -15,6 +15,7 @@ /* -------------------------------------------------------------------------- */ #include "VMGroupXML.h" +#include void VMGroupXML::init_attributes() { @@ -51,7 +52,7 @@ void VMGroupXML::init_attributes() rules.insert(rule); } - rules.clear(); + srules.clear(); xpaths(srules, "/VM_GROUP/TEMPLATE/ANTI_AFFINED"); @@ -67,3 +68,46 @@ void VMGroupXML::init_attributes() } }; +ostream& operator<<(ostream& os, VMGroupXML& vmg) +{ + VMGroupRule::rule_set::iterator rit; + VMGroupRoles::role_iterator it; + + os << left << setw(4) << vmg.oid << " " + << left << setw(8) << vmg.name<< " " + << left << setw(26)<< "ROLES" << "\n" + << setfill(' ') << setw(14) << " " << setfill('-') << setw(26) << '-' + << "\n"; + + for ( it = vmg.roles.begin() ; it != vmg.roles.end() ; ++it ) + { + os << setfill(' ') << setw(14) << ' ' + << left << setw(3) << (*it)->id() << " " + << left << setw(8) << (*it)->name() << " " + << left << setw(12)<< (*it)->policy_s() << "\n"; + } + + os << setfill(' ') << setw(14) << ' ' << left << "RULES" << "\n" + << setfill(' ') << setw(14) << ' ' << setfill('-') << setw(26) << '-' + << "\n"; + + for ( rit = vmg.rules.begin() ; rit != vmg.rules.end(); ++rit ) + { + const std::bitset& rroles = (*rit).get_roles(); + + os << setfill(' ') << setw(14) << ' ' << left << setw(14) + << (*rit).get_policy() << " "; + + for (int i = 0 ; i #include +#include #include "Scheduler.h" #include "SchedulerTemplate.h" @@ -1394,6 +1395,30 @@ int Scheduler::do_scheduled_actions() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void Scheduler::do_vm_groups() +{ + map::const_iterator it; + const map vmgrps = vmgpool->get_objects(); + + ostringstream 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; + } + + NebulaLog::log("VMGRP", Log::DEBUG, oss); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void Scheduler::do_action(const string &name, void *args) { int rc; @@ -1420,6 +1445,10 @@ void Scheduler::do_action(const string &name, void *args) return; } + profile(true); + do_vm_groups(); + profile(false,"Setting VM groups placement constraints."); + match_schedule(); profile(true); diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index 9a3eddd0b0..afc9d6ea8e 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -16,6 +16,8 @@ #include "VMGroupRole.h" +#include + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroupRole */ @@ -35,6 +37,27 @@ VMGroupRole::VMGroupRole(VectorAttribute *_va):va(_va) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +VMGroupRole::Policy VMGroupRole::policy() +{ + string p = va->vector_value("POLICY"); + + if ( p == "AFFINED" ) + { + return AFFINED; + } + else if ( p == "ANTI_AFFINED" ) + { + return ANTI_AFFINED; + } + else + { + return NONE; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void VMGroupRole::add_vm(int vm_id) { std::pair::iterator, bool> rc; @@ -309,3 +332,20 @@ 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 245601135c..03b1643cfb 100644 --- a/src/vm_group/VMGroupRule.cc +++ b/src/vm_group/VMGroupRule.cc @@ -18,6 +18,8 @@ #include "VMGroupRole.h" #include "VMGroupRule.h" +#include + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroupRule */ @@ -70,3 +72,24 @@ std::string VMGroupRule::policy_to_s(Policy policy) return name; } + +/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +ostream& operator<<(ostream& os, const VMGroupRule& rule) +{ + os << right << setw(14) << VMGroupRule::policy_to_s(rule.policy) << " "; + + for (int i = 0 ; i Date: Fri, 20 Jan 2017 20:46:50 +0100 Subject: [PATCH 19/26] F #2347: Set antiaffinity placement constraints for VMs --- include/VMGroup.h | 13 +- include/VMGroupRole.h | 31 ++-- include/VMGroupRule.h | 55 +++---- src/scheduler/include/VMGroupXML.h | 23 +++ src/scheduler/include/VirtualMachinePoolXML.h | 2 +- src/scheduler/include/VirtualMachineXML.h | 22 ++- src/scheduler/src/pool/VMGroupXML.cc | 144 +++++++++++++++++- src/scheduler/src/sched/Scheduler.cc | 26 +++- src/vm_group/VMGroup.cc | 34 +++-- src/vm_group/VMGroupRole.cc | 48 +++--- src/vm_group/VMGroupRule.cc | 39 +---- 11 files changed, 289 insertions(+), 148 deletions(-) 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 Date: Sun, 22 Jan 2017 02:18:02 +0100 Subject: [PATCH 20/26] F #2347: Host affinity rules --- include/VMGroupRole.h | 12 ++ src/scheduler/include/VMGroupXML.h | 7 ++ src/scheduler/include/VirtualMachineXML.h | 2 +- src/scheduler/src/pool/VMGroupXML.cc | 103 +++++++++++++++++- .../src/pool/VirtualMachinePoolXML.cc | 14 ++- src/scheduler/src/sched/Scheduler.cc | 2 + src/vm_group/VMGroupRole.cc | 30 ++++- 7 files changed, 160 insertions(+), 10 deletions(-) diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 8088adf561..d171a24a78 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -73,6 +73,18 @@ public: return va->vector_value("POLICY"); }; + /** + * Gets the sets of hosts affined to this role + * @param ahosts set of ids of affined hosts + */ + void get_affined_hosts(std::set& ahosts); + + /** + * Gets the sets of hosts anti-affined to this role + * @param ahosts set of ids of anti-affined hosts + */ + void get_antiaffined_hosts(std::set& ahosts); + /* ---------------------------------------------------------------------- */ /* VMS set Interface */ /* ---------------------------------------------------------------------- */ diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index b1084cd20f..ba9a3d12a8 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -59,6 +59,13 @@ public: */ void set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool); + /** + * Adds host affinity rules to each VM in the roles + * @params vmp the VM set of pending VMs + */ + void set_host_requirements(VirtualMachinePoolXML * vmp); + + private: // ------------------------------------------------------------------------ // VMGroup Attributes diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index 374afda904..6d599d1702 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -145,7 +145,7 @@ public: } else { - requirements += " & " + reqs; + requirements += " & (" + reqs + ")"; } } diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 967d2ee661..78f767ec5f 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -77,7 +77,7 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) VMGroupRoles::role_iterator it; std::ostringstream oss; - oss << "Placement rules for VMGroup " << get_name() << "\n"; + oss << "Anti-affinity 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"; @@ -153,6 +153,12 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) } VMGroupRole * r = roles.get(j); + + if ( r == 0 ) + { + continue; + } + std::string reqs; r->role_requirements(VMGroupPolicy::ANTI_AFFINED, reqs); @@ -189,14 +195,107 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) vm->add_requirements(role_reqs); oss << left << setw(8) << r->id() << left << setw(8) << *vt - << role_reqs << "\n"; + << vm->get_requirements() << "\n"; } } } NebulaLog::log("VMGRP", Log::DEBUG, oss); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +static void host_requirements(std::set& hosts, const std::string& op1, + const std::string& op2, std::ostringstream& oss) +{ + std::set::const_iterator jt; + bool empty = true; + + for ( jt = hosts.begin() ; jt != hosts.end() ; ++jt ) + { + if ( empty == true ) + { + empty = false; + + oss << "(ID" << op1 << *jt << ")"; + } + else + { + oss << " " << op2 << " (ID" << op1 << *jt << ")"; + } + } +} + +void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) +{ + VMGroupRoles::role_iterator it; + + std::ostringstream doss; + + doss << "Host affinity rules for VMGroup " << get_name() << "\n"; + doss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM" + << " " << left << "AFFINITY REQUIRMENTS\n" + << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + + for ( it = roles.begin(); it != roles.end() ; ++it ) + { + std::ostringstream oss; + + std::set ahosts; + std::set aahosts; + + std::set::const_iterator jt; + + VMGroupRole * r = *it; + + r->get_affined_hosts(ahosts); + + r->get_antiaffined_hosts(aahosts); + + if ( r->size_vms() == 0 || (ahosts.size() == 0 && aahosts.size() == 0) ) + { + continue; + } + + host_requirements(ahosts, "=", "|", oss); + + std::string areqs = oss.str(); + + oss.str(""); + + host_requirements(aahosts, "!=", "&", oss); + + std::string aareqs = oss.str(); + const std::set vms = r->get_vms(); + + for ( jt = vms.begin() ; jt != vms.end(); ++jt ) + { + VirtualMachineXML * vm = vmpool->get(*jt); + + if ( vm == 0 ) + { + continue; + } + + if ( !areqs.empty() ) + { + vm->add_requirements(areqs); + } + + if ( !aareqs.empty() ) + { + vm->add_requirements(aareqs); + } + + doss << left << setw(8) << r->id() << left << setw(8) << *jt + << vm->get_requirements() << "\n"; + } + } + + NebulaLog::log("VMGRP", Log::DEBUG, doss); } /* -------------------------------------------------------------------------- */ diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index 136ebcdbf7..d802e63fc8 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -33,6 +33,8 @@ int VirtualMachinePoolXML::set_up() if (NebulaLog::log_level() >= Log::DDDEBUG) { + map::iterator it; + oss << "Pending/rescheduling VM and capacity requirements:" << endl; oss << right << setw(8) << "ACTION" << " " @@ -44,7 +46,7 @@ int VirtualMachinePoolXML::set_up() << " Image DS" << endl << setw(60) << setfill('-') << "-" << setfill(' ') << endl; - for (map::iterator it=objects.begin();it!=objects.end();it++) + for (it = objects.begin() ; it != objects.end() ; ++it) { int cpu, mem; long long disk; @@ -52,7 +54,9 @@ int VirtualMachinePoolXML::set_up() string action = "DEPLOY"; - VirtualMachineXML * vm = static_cast(it->second); + VirtualMachineXML * vm; + + vm = static_cast(it->second); vm->get_requirements(cpu, mem, disk, pci); @@ -73,11 +77,11 @@ int VirtualMachinePoolXML::set_up() << right << setw(11) << disk << " "; map ds_usage = vm->get_storage_usage(); + map::const_iterator ds_it; - for (map::const_iterator ds_it = ds_usage.begin(); - ds_it != ds_usage.end(); ds_it++) + for ( ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ds_it++) { - oss << " DS " << ds_it->first << ": " << ds_it->second << " "; + oss << " DS " << ds_it->first << ": " << ds_it->second <<" "; } oss << endl; diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 1906295ffe..bcd2a14a5d 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -1423,6 +1423,8 @@ void Scheduler::do_vm_groups() VMGroupXML * grp = static_cast(it->second); grp->set_antiaffinity_requirements(vmpool); + + grp->set_host_requirements(vmpool); } } diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index 01e865a5f0..73c46eba5c 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -133,12 +133,12 @@ static void affinity_requirements(int vm_id, std::string& requirements, { if ( !first ) { - oss << "& "; + oss << " & "; } first = false; - oss << "( CURRENT_VMS " << op << " " << *it << ") "; + oss << "(CURRENT_VMS " << op << " " << *it << ")"; } } @@ -155,6 +155,32 @@ void VMGroupRole::role_requirements(VMGroupPolicy pol, std::string& reqs) affinity_requirements(-1, reqs, pol, vms); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VMGroupRole::get_affined_hosts(std::set& ahosts) +{ + string shosts = va->vector_value("HOST_AFFINED"); + + if ( !shosts.empty() ) + { + one_util::split_unique(shosts, ',', ahosts); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VMGroupRole::get_antiaffined_hosts(std::set& ahosts) +{ + string shosts = va->vector_value("HOST_ANTI_AFFINED"); + + if ( !shosts.empty() ) + { + one_util::split_unique(shosts, ',', ahosts); + } +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* VMGroupRoles */ From 09fafc3b0bdd1fef2d2701037728aa4f0f40b804 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sun, 22 Jan 2017 22:30:39 +0100 Subject: [PATCH 21/26] F #2347: Get information about VMs in VMGroups --- include/VMGroupRole.h | 12 ++--- src/scheduler/include/Scheduler.h | 4 +- src/scheduler/include/VirtualMachinePoolXML.h | 32 +++++++++++ src/scheduler/src/pool/VMGroupXML.cc | 47 ++-------------- .../src/pool/VirtualMachinePoolXML.cc | 29 ++++++++++ src/scheduler/src/pool/VirtualMachineXML.cc | 16 +++--- src/scheduler/src/sched/Scheduler.cc | 52 +++++++++++------- src/vm_group/VMGroupRole.cc | 54 ++++++++++++++++--- 8 files changed, 160 insertions(+), 86 deletions(-) diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index d171a24a78..51ca3a047b 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -74,16 +74,16 @@ public: }; /** - * Gets the sets of hosts affined to this role - * @param ahosts set of ids of affined hosts + * Gets the placement requirements for the affined HOSTS + * @param reqs string with the requirements expression */ - void get_affined_hosts(std::set& ahosts); + void affined_host_requirements(std::string& reqs); /** - * Gets the sets of hosts anti-affined to this role - * @param ahosts set of ids of anti-affined hosts + * Gets the placement requirements for the antiaffined HOSTS + * @param reqs string with the requirements expression */ - void get_antiaffined_hosts(std::set& ahosts); + void antiaffined_host_requirements(std::string& reqs); /* ---------------------------------------------------------------------- */ /* VMS set Interface */ diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index eb8a3669c4..7baa7e7351 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -99,8 +99,8 @@ protected: SystemDatastorePoolXML * dspool; ImageDatastorePoolXML * img_dspool; - VirtualMachinePoolXML * vmpool; - VirtualMachinePoolXML * vm_roles_pool; + VirtualMachinePoolXML * vmpool; + VirtualMachineRolePoolXML * vm_roles_pool; VMGroupPoolXML * vmgpool; diff --git a/src/scheduler/include/VirtualMachinePoolXML.h b/src/scheduler/include/VirtualMachinePoolXML.h index 14ce5b42df..f2418636c9 100644 --- a/src/scheduler/include/VirtualMachinePoolXML.h +++ b/src/scheduler/include/VirtualMachinePoolXML.h @@ -158,4 +158,36 @@ protected: } }; +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualMachineRolePoolXML : public VirtualMachinePoolXML +{ +public: + + VirtualMachineRolePoolXML(Client * client, unsigned int machines_limit): + VirtualMachinePoolXML(client, machines_limit, false){}; + + virtual ~VirtualMachineRolePoolXML(){}; + + /** + * Retrieves the VMs part of a role + * + * @return 0 on success + * -1 on error + * -2 if no VMs in a role + */ + int set_up(); + +protected: + + int get_suitable_nodes(vector& content) + { + ostringstream oss; + + oss << "/VM_POOL/VM[TEMPLATE/VMGROUP/ROLE]"; + + return get_nodes(oss.str().c_str(), content); + } +}; #endif /* VM_POOL_XML_H_ */ diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 78f767ec5f..c2af1e418c 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -206,27 +206,6 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -static void host_requirements(std::set& hosts, const std::string& op1, - const std::string& op2, std::ostringstream& oss) -{ - std::set::const_iterator jt; - bool empty = true; - - for ( jt = hosts.begin() ; jt != hosts.end() ; ++jt ) - { - if ( empty == true ) - { - empty = false; - - oss << "(ID" << op1 << *jt << ")"; - } - else - { - oss << " " << op2 << " (ID" << op1 << *jt << ")"; - } - } -} - void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) { VMGroupRoles::role_iterator it; @@ -240,38 +219,22 @@ void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) for ( it = roles.begin(); it != roles.end() ; ++it ) { - std::ostringstream oss; - - std::set ahosts; - std::set aahosts; - - std::set::const_iterator jt; + std::string areqs, aareqs; VMGroupRole * r = *it; - r->get_affined_hosts(ahosts); + r->affined_host_requirements(areqs); - r->get_antiaffined_hosts(aahosts); + r->antiaffined_host_requirements(aareqs); - if ( r->size_vms() == 0 || (ahosts.size() == 0 && aahosts.size() == 0) ) + if ( r->size_vms() == 0 || (areqs.empty() && aareqs.empty()) ) { continue; } - host_requirements(ahosts, "=", "|", oss); - - std::string areqs = oss.str(); - - oss.str(""); - - host_requirements(aahosts, "!=", "&", oss); - - std::string aareqs = oss.str(); - - const std::set vms = r->get_vms(); - for ( jt = vms.begin() ; jt != vms.end(); ++jt ) + for (std::set::const_iterator jt=vms.begin(); jt!=vms.end(); ++jt) { VirtualMachineXML * vm = vmpool->get(*jt); diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index d802e63fc8..8188237264 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -235,6 +235,7 @@ int VirtualMachinePoolXML::update(int vid, const string &st) const return 0; } + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -267,6 +268,7 @@ int VirtualMachineActionsPoolXML::set_up() return rc; } + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -308,3 +310,30 @@ int VirtualMachineActionsPoolXML::action( return 0; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachineRolePoolXML::set_up() +{ + int rc = PoolXML::set_up(); + + if ( rc == 0 ) + { + ostringstream oss; + + oss << "VMs in VMGroups:" << endl; + + map::iterator it; + + for (it=objects.begin();it!=objects.end();it++) + { + oss << " " << it->first; + } + + NebulaLog::log("VM", Log::DEBUG, oss); + } + + return rc; +} + diff --git a/src/scheduler/src/pool/VirtualMachineXML.cc b/src/scheduler/src/pool/VirtualMachineXML.cc index d4f9638e03..6e3dd46e86 100644 --- a/src/scheduler/src/pool/VirtualMachineXML.cc +++ b/src/scheduler/src/pool/VirtualMachineXML.cc @@ -406,14 +406,14 @@ int VirtualMachineXML::parse_action_name(string& action_st) bool VirtualMachineXML::test_image_datastore_capacity( ImageDatastorePoolXML * img_dspool, string & error_msg) const { - map::const_iterator ds_usage_it; + map::const_iterator ds_it; DatastoreXML* ds; - for (ds_usage_it = ds_usage.begin(); ds_usage_it != ds_usage.end(); ds_usage_it++) + for (ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it) { - ds = img_dspool->get(ds_usage_it->first); + ds = img_dspool->get(ds_it->first); - if (ds == 0 || !ds->test_capacity(ds_usage_it->second)) + if (ds == 0 || !ds->test_capacity(ds_it->second)) { ostringstream oss; @@ -434,20 +434,20 @@ bool VirtualMachineXML::test_image_datastore_capacity( void VirtualMachineXML::add_image_datastore_capacity( ImageDatastorePoolXML * img_dspool) { - map::const_iterator ds_usage_it; + map::const_iterator ds_it; DatastoreXML *ds; - for (ds_usage_it = ds_usage.begin(); ds_usage_it != ds_usage.end(); ds_usage_it++) + for (ds_it = ds_usage.begin(); ds_it != ds_usage.end(); ++ds_it) { - ds = img_dspool->get(ds_usage_it->first); + ds = img_dspool->get(ds_it->first); if (ds == 0) //Should never reach here { continue; } - ds->add_capacity(ds_usage_it->second); + ds->add_capacity(ds_it->second); } } diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index bcd2a14a5d..00fb6347e3 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -309,23 +309,23 @@ void Scheduler::start() // ------------------------------------------------------------------------- // Pools // ------------------------------------------------------------------------- - acls = new AclXML(Client::client(), zone_id); - upool = new UserPoolXML(Client::client()); + Client * client = Client::client(); - hpool = new HostPoolXML(Client::client()); - clpool = new ClusterPoolXML(Client::client()); + acls = new AclXML(client, zone_id); + upool = new UserPoolXML(client); - dspool = new SystemDatastorePoolXML(Client::client()); - img_dspool = new ImageDatastorePoolXML(Client::client()); + hpool = new HostPoolXML(client); + clpool = new ClusterPoolXML(client); - vmpool = new VirtualMachinePoolXML(Client::client(), machines_limit, - live_rescheds==1); - vm_roles_pool = new VirtualMachinePoolXML(Client::client(), machines_limit, - live_rescheds==1); + dspool = new SystemDatastorePoolXML(client); + img_dspool = new ImageDatastorePoolXML(client); - vmgpool = new VMGroupPoolXML(Client::client()); + vm_roles_pool = new VirtualMachineRolePoolXML(client, machines_limit); + vmpool = new VirtualMachinePoolXML(client, machines_limit, live_rescheds==1); - vmapool = new VirtualMachineActionsPoolXML(Client::client(), machines_limit); + vmgpool = new VMGroupPoolXML(client); + + vmapool = new VirtualMachineActionsPoolXML(client, machines_limit); // ----------------------------------------------------------- // Load scheduler policies @@ -473,7 +473,12 @@ int Scheduler::set_up_pools() return rc; } - vm_roles_pool->clear(); + rc = vm_roles_pool->set_up(); + + if ( rc != 0 ) + { + return rc; + } return 0; }; @@ -1012,13 +1017,20 @@ void Scheduler::match_schedule() ostringstream oss; oss << "Match Making statistics:\n" - << "\tNumber of VMs: " << pending_vms.size() << endl - << "\tTotal time: " << one_util::float_to_str(time(0) - stime) << "s" << endl - << "\tTotal Cluster Match time: " << one_util::float_to_str(total_cl_match_time) << "s" << endl - << "\tTotal Host Match time: " << one_util::float_to_str(total_host_match_time) << "s" << endl - << "\tTotal Host Ranking time: " << one_util::float_to_str(total_host_rank_time) << "s" << endl - << "\tTotal DS Match time: " << one_util::float_to_str(total_ds_match_time) << "s" << endl - << "\tTotal DS Ranking time: " << one_util::float_to_str(total_ds_rank_time) << "s" << endl; + << "\tNumber of VMs: " + << pending_vms.size() << endl + << "\tTotal time: " + << one_util::float_to_str(time(0) - stime) << "s" << endl + << "\tTotal Cluster Match time: " + << one_util::float_to_str(total_cl_match_time) << "s" << endl + << "\tTotal Host Match time: " + << one_util::float_to_str(total_host_match_time) << "s" << endl + << "\tTotal Host Ranking time: " + << one_util::float_to_str(total_host_rank_time) << "s" << endl + << "\tTotal DS Match time: " + << one_util::float_to_str(total_ds_match_time) << "s" << endl + << "\tTotal DS Ranking time: " + << one_util::float_to_str(total_ds_rank_time) << "s" << endl; NebulaLog::log("SCHED", Log::DDEBUG, oss); } diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index 73c46eba5c..e5a2d669de 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -106,7 +106,7 @@ void VMGroupRole::set_vms() static void affinity_requirements(int vm_id, std::string& requirements, VMGroupPolicy policy, const std::set& vms) { - string op; + string op, op2; requirements = ""; @@ -114,9 +114,11 @@ static void affinity_requirements(int vm_id, std::string& requirements, { case VMGroupPolicy::AFFINED: op = "="; + op2= " | "; break; case VMGroupPolicy::ANTI_AFFINED: op = "!="; + op2= " & "; break; case VMGroupPolicy::NONE: return; @@ -133,7 +135,7 @@ static void affinity_requirements(int vm_id, std::string& requirements, { if ( !first ) { - oss << " & "; + oss << op2; } first = false; @@ -158,27 +160,63 @@ void VMGroupRole::role_requirements(VMGroupPolicy pol, std::string& reqs) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VMGroupRole::get_affined_hosts(std::set& ahosts) +static void host_requirements(std::set& hosts, const std::string& op1, + const std::string& op2, std::ostringstream& oss) { - string shosts = va->vector_value("HOST_AFFINED"); + std::set::const_iterator jt; + bool empty = true; - if ( !shosts.empty() ) + for ( jt = hosts.begin() ; jt != hosts.end() ; ++jt ) { - one_util::split_unique(shosts, ',', ahosts); + if ( empty == true ) + { + empty = false; + + oss << "(ID" << op1 << *jt << ")"; + } + else + { + oss << " " << op2 << " (ID" << op1 << *jt << ")"; + } } } /* -------------------------------------------------------------------------- */ + +void VMGroupRole::affined_host_requirements(std::string& reqs) +{ + std::ostringstream oss; + std::set hosts; + + string shosts = va->vector_value("HOST_AFFINED"); + + if ( !shosts.empty() ) + { + one_util::split_unique(shosts, ',', hosts); + } + + host_requirements(hosts, "=", "|", oss); + + reqs = oss.str(); +} + /* -------------------------------------------------------------------------- */ -void VMGroupRole::get_antiaffined_hosts(std::set& ahosts) +void VMGroupRole::antiaffined_host_requirements(std::string& reqs) { + std::ostringstream oss; + std::set hosts; + string shosts = va->vector_value("HOST_ANTI_AFFINED"); if ( !shosts.empty() ) { - one_util::split_unique(shosts, ',', ahosts); + one_util::split_unique(shosts, ',', hosts); } + + host_requirements(hosts, "!=", "&", oss); + + reqs = oss.str(); } /* -------------------------------------------------------------------------- */ From 5bd214ab004ccb639be3d98a4e0326f856721170 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 25 Jan 2017 20:08:12 +0100 Subject: [PATCH 22/26] F #2347: Schedule affined groups --- include/VMGroupRole.h | 42 ++- include/VMGroupRule.h | 16 +- src/scheduler/include/HostXML.h | 67 ++++- src/scheduler/include/VMGroupXML.h | 20 +- src/scheduler/include/VirtualMachineXML.h | 34 ++- src/scheduler/src/pool/VMGroupXML.cc | 297 +++++++++++++++++--- src/scheduler/src/pool/VirtualMachineXML.cc | 22 ++ src/scheduler/src/sched/Scheduler.cc | 41 +-- src/vm_group/VMGroupRole.cc | 2 +- src/vm_group/VMGroupRule.cc | 48 +++- 10 files changed, 483 insertions(+), 106 deletions(-) diff --git a/include/VMGroupRole.h b/include/VMGroupRole.h index 51ca3a047b..aefd15d09b 100644 --- a/include/VMGroupRole.h +++ b/include/VMGroupRole.h @@ -63,6 +63,14 @@ public: return va->vector_value("NAME"); } + /** + * @return the set of VMs in a string in a comma separated list + */ + std::string vms_s() + { + return va->vector_value("VMS"); + } + /** * @return the policy of this role */ @@ -73,18 +81,6 @@ public: return va->vector_value("POLICY"); }; - /** - * Gets the placement requirements for the affined HOSTS - * @param reqs string with the requirements expression - */ - void affined_host_requirements(std::string& reqs); - - /** - * Gets the placement requirements for the antiaffined HOSTS - * @param reqs string with the requirements expression - */ - void antiaffined_host_requirements(std::string& reqs); - /* ---------------------------------------------------------------------- */ /* VMS set Interface */ /* ---------------------------------------------------------------------- */ @@ -121,6 +117,28 @@ public: */ void role_requirements(VMGroupPolicy p, std::string& requirements); + /** + * Gets the placement requirements for the affined HOSTS + * @param reqs string with the requirements expression + */ + void affined_host_requirements(std::string& reqs); + + /** + * Gets the placement requirements for the antiaffined HOSTS + * @param reqs string with the requirements expression + */ + void antiaffined_host_requirements(std::string& reqs); + + /** + * Generate generic requirements for a set of hosts + * @param hosts the set + * @param op1 operator for each host requirement = or != + * @param op2 operator to join host requirements & or | + * @param oss stream where the requirement expression is output + */ + static void host_requirements(std::set& hosts, const std::string& op1, + const std::string& op2, std::ostringstream& oss); + private: /** * The set of vms in the role diff --git a/include/VMGroupRule.h b/include/VMGroupRule.h index e678b0faa9..e083ce5f56 100644 --- a/include/VMGroupRule.h +++ b/include/VMGroupRule.h @@ -97,7 +97,7 @@ public: return *this; } - VMGroupRule operator& (const VMGroupRule& other) + VMGroupRule operator& (const VMGroupRule& other) const { return VMGroupRule(policy, other.roles & roles ); } @@ -108,7 +108,7 @@ public: return *this; } - VMGroupRule operator| (const VMGroupRule& other) + VMGroupRule operator| (const VMGroupRule& other) const { return VMGroupRule(policy, other.roles | roles ); } @@ -133,6 +133,18 @@ public: */ static bool compatible(rule_set& affined, rule_set& anti, VMGroupRule& err); + /** + * Reduce a set of affinity rules merging rules affecting the same roles + * Example: + * AFFINED = a, b + * AFFINED = b, c -------> AFFINED = a, b, c + * AFFINED = e, d AFFINED = e, d + * + * @param affined set of rules to be reduced + * @param reduced set + */ + static void reduce(rule_set affined, rule_set& reduced); + /** * @return the roles in the rule as a bitset (1 roles is in) */ diff --git a/src/scheduler/include/HostXML.h b/src/scheduler/include/HostXML.h index 08206bbcf4..965e268f4f 100644 --- a/src/scheduler/include/HostXML.h +++ b/src/scheduler/include/HostXML.h @@ -19,6 +19,7 @@ #define HOST_XML_H_ #include +#include #include "ObjectXML.h" #include "HostShare.h" #include "PoolObjectAuth.h" @@ -48,6 +49,11 @@ public: return cluster_id; }; + unsigned int dispatched() const + { + return dispatched_vms.size(); + } + /** * Tests whether a new VM can be hosted by the host or not * @param cpu needed by the VM (percentage) @@ -56,8 +62,8 @@ public: * @param error error message * @return true if the share can host the VM */ - bool test_capacity(long long cpu, long long mem, vector &pci, - string & error); + bool test_capacity(long long cpu, long long mem, + vector &pci, string & error); /** * Tests whether a new VM can be hosted by the host or not @@ -87,6 +93,8 @@ public: pci.add(p, vmid); + dispatched_vms.insert(vmid); + running_vms++; }; @@ -171,28 +179,51 @@ private: int cluster_id; // Host share values - long long mem_usage; /**< Memory allocated to VMs (in KB) */ - long long cpu_usage; /**< CPU allocated to VMs (in percentage) */ + long long mem_usage; /**< Memory allocated to VMs (in KB) */ + long long cpu_usage; /**< CPU allocated to VMs (in percentage)*/ - long long max_mem; /**< Total memory capacity (in KB) */ - long long max_cpu; /**< Total cpu capacity (in percentage) */ + long long max_mem; /**< Total memory capacity (in KB) */ + long long max_cpu; /**< Total cpu capacity (in percentage)*/ - long long free_disk; /**< Free disk capacity (in MB) */ + HostSharePCI pci; /**< PCI devices of the host */ + + long long free_disk; /**< Free disk capacity (in MB)*/ map ds_free_disk; /**< Free MB for local system DS */ - long long running_vms; /**< Number of running VMs in this Host */ + long long running_vms; /**< Number of running VMs in this Host */ + set dispatched_vms; /**< Dispatched VMs to this host in this cycle */ - bool public_cloud; - - HostSharePCI pci; + bool public_cloud; /**< This host is a public cloud */ // Configuration attributes static const char *host_paths[]; /**< paths for search function */ + static int host_num_paths; /**< number of paths */ - static int host_num_paths; /**< number of paths*/ + /* ---------------------------------------------------------------------- */ + /* Functions to search for values in the HostXML object */ + /* ---------------------------------------------------------------------- */ + bool is_dispatched(const std::string& vm_id) const + { + std::istringstream iss(vm_id); - void init_attributes(); + int vm_id_i; + + iss >> vm_id_i; + + return dispatched_vms.find(vm_id_i) != dispatched_vms.end(); + } + + bool is_dispatched(int vm_id) const + { + return dispatched_vms.find(vm_id) != dispatched_vms.end(); + } + + template + bool is_dispatched(const T& vm_id) const + { + return false; + } /** * Search the Object for a given attribute in a set of object specific @@ -221,6 +252,11 @@ private: } } + if ( is_dispatched(value) ) + { + return 0; + } + value = -1; //VMID not found in VMS value is -1 return 0; @@ -230,6 +266,11 @@ private: return ObjectXML::search(name, value); } }; + + /** + * Bootstrap the HostXML internal attributes + */ + void init_attributes(); }; #endif /* HOST_XML_H_ */ diff --git a/src/scheduler/include/VMGroupXML.h b/src/scheduler/include/VMGroupXML.h index ba9a3d12a8..39ad15c1b9 100644 --- a/src/scheduler/include/VMGroupXML.h +++ b/src/scheduler/include/VMGroupXML.h @@ -22,6 +22,7 @@ #include "VMGroupRule.h" class VirtualMachinePoolXML; +class VirtualMachineRolePoolXML; class VMGroupXML : public ObjectXML { @@ -56,14 +57,26 @@ public: /** * Adds the internal role placement rules to each VM in the role * @params vmpool VM set of pending VMs + * @params oss stream to output debug information */ - void set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool); + void set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool, + std::ostringstream& oss); + + /** + * Adds the internal role placement rules to each VM in the role + * @params vmpool VM set of pending VMs + * @params oss stream to output debug information + */ + void set_affinity_requirements(VirtualMachinePoolXML * vmpool, + VirtualMachineRolePoolXML * vm_roles_pool, std::ostringstream& oss); /** * Adds host affinity rules to each VM in the roles * @params vmp the VM set of pending VMs + * @params oss stream to output debug information */ - void set_host_requirements(VirtualMachinePoolXML * vmp); + void set_host_requirements(VirtualMachinePoolXML * vmp, + std::ostringstream& oss); private: @@ -76,7 +89,8 @@ private: VMGroupRoles roles; - VMGroupRule::rule_set rules; + VMGroupRule::rule_set affined; + VMGroupRule::rule_set anti_affined; // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index 6d599d1702..4d25809815 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -115,9 +115,23 @@ public: return ds_requirements; } - void get_requirements (int& cpu, int& memory, long long& disk, + /** + * Return VM usage requirments + */ + void get_requirements(int& cpu, int& memory, long long& disk, vector &pci); + /** + * Return the requirements of this VM (as is) + * @param cpu in unit + * @param memory in kb + * @param disk in mb (system ds usage) + */ + void get_raw_requirements(float& cpu, int& memory, long long& disk); + + /** + * @return the usage requirements in image ds. + */ map get_storage_usage(); /** @@ -129,6 +143,14 @@ public: return public_cloud; }; + /** + * Adds usage requirements to this VM + * @param cpu in unit form + * @param m memory in kb + * @param d in mb (system ds usage) + */ + void add_requirements(float c, int m, long long d); + /** * Adds (logical AND) new placement requirements to the current ones * @param reqs additional requirements @@ -149,6 +171,14 @@ public: } } + /** + * Check if the VM is ACTIVE state + */ + bool is_active() const + { + return state == 3; + } + //-------------------------------------------------------------------------- // Matched Resources Interface //-------------------------------------------------------------------------- @@ -349,6 +379,8 @@ protected: int resched; bool resume; + int state; + int memory; float cpu; long long system_ds_usage; diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index c2af1e418c..60a496e4cd 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -18,6 +18,8 @@ #include "VirtualMachinePoolXML.h" #include +static ostream& operator<<(ostream& os, VMGroupRule::rule_set rules); + void VMGroupXML::init_attributes() { vector content; @@ -50,7 +52,7 @@ void VMGroupXML::init_attributes() VMGroupRule rule(VMGroupPolicy::AFFINED, id_set); - rules.insert(rule); + affined.insert(rule); } srules.clear(); @@ -65,19 +67,21 @@ void VMGroupXML::init_attributes() VMGroupRule rule(VMGroupPolicy::ANTI_AFFINED, id_set); - rules.insert(rule); + anti_affined.insert(rule); } }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) +void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool, + std::ostringstream& oss) { VMGroupRoles::role_iterator it; - std::ostringstream oss; - oss << "Anti-affinity rules for VMGroup " << get_name() << "\n"; + oss << "\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "Intra-role Anti-affinity rules \n"; oss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM" << " " << left << "ANTI_AFFINITY REQUIRMENTS\n" << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; @@ -94,7 +98,7 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) continue; } - const std::set vms = r->get_vms(); + const std::set& vms = r->get_vms(); std::set::const_iterator jt; for ( jt = vms.begin() ; jt != vms.end(); ++jt ) @@ -120,20 +124,20 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) } } - oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; /* ---------------------------------------------------------------------- */ /* Inter-role anti-affinity placement rule */ /* ---------------------------------------------------------------------- */ + oss << "\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "Inter-role Anti-affinity rules \n"; + oss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM" + << " " << left << "ANTI_AFFINITY REQUIRMENTS\n" + << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; VMGroupRule::rule_set::iterator rt; - for ( rt = rules.begin() ; rt != rules.end() ; ++rt ) + for ( rt = anti_affined.begin() ; rt != anti_affined.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) @@ -180,7 +184,7 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) VMGroupRole * r = roles.get(i); - const std::set vms = r->get_vms(); + const std::set& vms = r->get_vms(); std::set::const_iterator vt; for ( vt=vms.begin() ; vt!=vms.end(); ++vt ) @@ -206,16 +210,17 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) +void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool, + std::ostringstream& oss) { VMGroupRoles::role_iterator it; - std::ostringstream doss; - - doss << "Host affinity rules for VMGroup " << get_name() << "\n"; - doss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM" - << " " << left << "AFFINITY REQUIRMENTS\n" - << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "Host affinity rules \n"; + oss << left << setw(8)<< "ROLE" << " " << left << setw(8) <<"VM" + << " " << left << "AFFINITY REQUIRMENTS\n" + << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; for ( it = roles.begin(); it != roles.end() ; ++it ) { @@ -232,7 +237,7 @@ void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) continue; } - const std::set vms = r->get_vms(); + const std::set& vms = r->get_vms(); for (std::set::const_iterator jt=vms.begin(); jt!=vms.end(); ++jt) { @@ -253,41 +258,206 @@ void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool) vm->add_requirements(aareqs); } - doss << left << setw(8) << r->id() << left << setw(8) << *jt - << vm->get_requirements() << "\n"; + oss << left << setw(8) << r->id() << left << setw(8) << *jt + << vm->get_requirements() << "\n"; } } - - NebulaLog::log("VMGRP", Log::DEBUG, doss); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -ostream& operator<<(ostream& os, VMGroupXML& vmg) +static void schecule_affined_set(std::set vms, + VirtualMachinePoolXML * vmpool, VirtualMachineRolePoolXML * vm_roles_pool, + std::ostringstream& oss) { - VMGroupRule::rule_set::iterator rit; - VMGroupRoles::role_iterator it; + std::set::iterator it; + std::set hosts; - os << left << setw(4) << vmg.oid << " " - << left << setw(8) << vmg.name<< " " - << left << setw(26)<< "ROLES" << "\n" - << setfill(' ') << setw(14) << " " << setfill('-') << setw(26) << '-' - << setfill(' ') << "\n"; - - for ( it = vmg.roles.begin() ; it != vmg.roles.end() ; ++it ) + if ( vms.size() == 0 ) { - os << setfill(' ') << setw(14) << ' ' - << left << setw(3) << (*it)->id() << " " - << left << setw(8) << (*it)->name() << " " - << left << setw(12)<< (*it)->policy_s() << "\n"; + return; } - os << setfill(' ') << setw(14) << ' ' << left << "RULES" << "\n" - << setfill(' ') << setw(14) << ' ' << setfill('-') << setw(26) << '-' - << setfill(' ') << "\n"; + for ( it = vms.begin() ; it != vms.end() ; ++it ) + { + VirtualMachineXML * vm = vm_roles_pool->get(*it); - for ( rit = vmg.rules.begin() ; rit != vmg.rules.end(); ++rit ) + if ( vm == 0 ) + { + continue; + } + + int hid = vm->get_hid(); + + if ( vm->is_active() && hid != -1 ) + { + hosts.insert(hid); + } + } + + if ( hosts.size() == 0 ) + { + VirtualMachineXML * vm; + + for ( it = vms.begin(); it != vms.end() ; ++it ) + { + vm = vmpool->get(*it); + + if ( vm != 0 ) + { + break; + } + } + + if ( vm == 0 ) + { + return; + } + + std::ostringstream areqs; + std::string areqs_s; + + areqs << "CURRENT_VMS = " << *it; + areqs_s = areqs.str(); + + for ( ++it ; it != vms.end() ; ++it ) + { + float cpu; + int memory; + + long long disk; + + VirtualMachineXML * tmp = vmpool->get(*it); + + if ( tmp == 0 ) + { + continue; + } + + tmp->get_raw_requirements(cpu, memory, disk); + + vm->add_requirements(cpu, memory, disk); + vm->add_requirements(tmp->get_requirements()); + + tmp->add_requirements(areqs_s); + + oss << left << setw(8) << tmp->get_oid() << " " + << tmp->get_requirements() << "\n"; + } + + oss << left << setw(8) << vm->get_oid() << " " + << vm->get_requirements() << "\n"; + } + else + { + std::ostringstream oss; + std::string reqs; + + VMGroupRole::host_requirements(hosts, "=", "|", oss); + + reqs = oss.str(); + + for ( it = vms.begin() ; it != vms.end() ; ++it ) + { + VirtualMachineXML * vm = vmpool->get(*it); + + if ( vm == 0 || reqs.empty()) + { + continue; + } + + vm->add_requirements(reqs); + + oss << left << setw(8) << vm->get_oid() << " " + << vm->get_requirements() << "\n"; + } + } +} + +/* -------------------------------------------------------------------------- */ + +void VMGroupXML::set_affinity_requirements(VirtualMachinePoolXML * vmpool, + VirtualMachineRolePoolXML * vm_roles_pool, std::ostringstream& oss) +{ + VMGroupRoles::role_iterator it; + + /* ---------------------------------------------------------------------- */ + /* Intra-role affinity placement rule */ + /* ---------------------------------------------------------------------- */ + oss << "\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "Intra-role affinity requirements\n"; + oss << left << setw(8) << "VMID" << " " << left << "REQUIREMENTS\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + + for ( it = roles.begin(); it != roles.end() ; ++it ) + { + VMGroupRole * r = *it; + + if ( r->policy() != VMGroupPolicy::AFFINED || r->size_vms() <= 1 ) + { + continue; + } + + const std::set& vms = r->get_vms(); + + schecule_affined_set(vms, vmpool, vm_roles_pool, oss); + } + + /* ---------------------------------------------------------------------- */ + /* Inter-role affinity placement rule */ + /* 1. Build the reduced set of affinity rules */ + /* 2. Build the set of VMs affected by each rule */ + /* 3. Schedule the resulting set */ + /* ---------------------------------------------------------------------- */ + VMGroupRule::rule_set reduced; + VMGroupRule::rule_set::iterator rit; + + oss << "\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + oss << "Inter-role affinity requirements\n"; + oss << left << setw(8) << "VMID" << " " << left << "REQUIREMENTS\n"; + oss << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; + + VMGroupRule::reduce(affined, reduced); + + for ( rit = reduced.begin() ; rit != reduced.end(); ++rit ) + { + const VMGroupRule::role_bitset rroles = (*rit).get_roles(); + std::set rule_vms; + + for (int i = 0 ; i & role_vms = r->get_vms(); + + rule_vms.insert(role_vms.begin(), role_vms.end()); + } + + schecule_affined_set(rule_vms, vmpool, vm_roles_pool, oss); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +static ostream& operator<<(ostream& os, VMGroupRule::rule_set rules) +{ + VMGroupRule::rule_set::iterator rit; + + for ( rit = rules.begin() ; rit != rules.end(); ++rit ) { const VMGroupRule::role_bitset rroles = (*rit).get_roles(); @@ -307,3 +477,42 @@ ostream& operator<<(ostream& os, VMGroupXML& vmg) return os; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +ostream& operator<<(ostream& os, VMGroupXML& vmg) +{ + VMGroupRoles::role_iterator it; + + os << left << setw(4) << vmg.oid << " " + << left << setw(8) << vmg.name<< " " + << left << setw(12)<< "ROLES" << " " << setw(12) << "POLICY" << " " + << left << "VMS\n" + << setfill(' ') << setw(14) << " " << setfill('-') << setw(50) << '-' + << setfill(' ') << "\n"; + + for ( it = vmg.roles.begin() ; it != vmg.roles.end() ; ++it ) + { + os << setfill(' ') << setw(14) << " " + << left << setw(3) << (*it)->id() << " " + << left << setw(8) << (*it)->name() << " " + << left << setw(12)<< (*it)->policy_s() << " " + << left << (*it)->vms_s() << "\n"; + } + + os << "\n"; + os << setfill(' ') << setw(14) << ' ' << left << "RULES" << "\n" + << setfill(' ') << setw(14) << ' ' << setfill('-') << setw(50) << '-' + << setfill(' ') << "\n"; + + os << vmg.affined; + + os << vmg.anti_affined; + + return os; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/scheduler/src/pool/VirtualMachineXML.cc b/src/scheduler/src/pool/VirtualMachineXML.cc index 6e3dd46e86..1303fbec07 100644 --- a/src/scheduler/src/pool/VirtualMachineXML.cc +++ b/src/scheduler/src/pool/VirtualMachineXML.cc @@ -36,6 +36,8 @@ void VirtualMachineXML::init_attributes() xpath(uid, "/VM/UID", -1); xpath(gid, "/VM/GID", -1); + xpath(state, "/VM/STATE", -1); + xpath(memory, "/VM/TEMPLATE/MEMORY", 0); xpath(cpu, "/VM/TEMPLATE/CPU", 0); @@ -202,6 +204,26 @@ ostream& operator<<(ostream& os, VirtualMachineXML& vm) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void VirtualMachineXML::add_requirements(float c, int m, long long d) +{ + cpu += c; + memory += m; + system_ds_usage += d; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineXML::get_raw_requirements (float& c, int& m, long long& d) +{ + c = cpu; + m = memory; + d = system_ds_usage; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void VirtualMachineXML::get_requirements (int& cpu, int& memory, long long& disk, vector &pci) { diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 00fb6347e3..0217969cf0 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -1074,9 +1074,6 @@ void Scheduler::dispatch() unsigned int dispatched_vms = 0; bool dispatched; - map host_vms; - pair::iterator, bool> rc; - map::const_iterator vm_it; vector::const_reverse_iterator i, j; @@ -1157,11 +1154,9 @@ void Scheduler::dispatch() } //------------------------------------------------------------------ - // Test host dispatch limit (init counter if needed) + // Test host dispatch limit //------------------------------------------------------------------ - rc = host_vms.insert(make_pair(hid,0)); - - if (rc.first->second >= host_dispatch_limit) + if (host->dispatched() >= host_dispatch_limit) { continue; } @@ -1281,8 +1276,6 @@ void Scheduler::dispatch() host->add_capacity(vm->get_oid(), cpu, mem, pci); - host_vms[hid]++; - dispatched_vms++; dispatched = true; @@ -1412,32 +1405,24 @@ void Scheduler::do_vm_groups() map::const_iterator it; const map vmgrps = vmgpool->get_objects(); - 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); - } + ostringstream oss; for (it = vmgrps.begin(); it != vmgrps.end() ; ++it) { VMGroupXML * grp = static_cast(it->second); - grp->set_antiaffinity_requirements(vmpool); + oss << "\nSCHEDULING RESULTS FOR VM GROUP: " << grp->get_name() <<"\n"; - grp->set_host_requirements(vmpool); + oss << *grp << "\n"; + + grp->set_antiaffinity_requirements(vmpool, oss); + + grp->set_host_requirements(vmpool, oss); + + grp->set_affinity_requirements(vmpool, vm_roles_pool, oss); } + + NebulaLog::log("VMGRP", Log::DDDEBUG, oss); } /* -------------------------------------------------------------------------- */ diff --git a/src/vm_group/VMGroupRole.cc b/src/vm_group/VMGroupRole.cc index e5a2d669de..811d9e86bb 100644 --- a/src/vm_group/VMGroupRole.cc +++ b/src/vm_group/VMGroupRole.cc @@ -160,7 +160,7 @@ void VMGroupRole::role_requirements(VMGroupPolicy pol, std::string& reqs) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -static void host_requirements(std::set& hosts, const std::string& op1, +void VMGroupRole::host_requirements(std::set& hosts, const std::string& op1, const std::string& op2, std::ostringstream& oss) { std::set::const_iterator jt; diff --git a/src/vm_group/VMGroupRule.cc b/src/vm_group/VMGroupRule.cc index a627520d54..2d3e21ae42 100644 --- a/src/vm_group/VMGroupRule.cc +++ b/src/vm_group/VMGroupRule.cc @@ -26,8 +26,7 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -bool VMGroupRule::compatible(VMGroupRule::rule_set& affined, - VMGroupRule::rule_set& anti, VMGroupRule& err) +bool VMGroupRule::compatible(rule_set& affined, rule_set& anti,VMGroupRule& err) { VMGroupRule ta, taa; @@ -48,6 +47,51 @@ bool VMGroupRule::compatible(VMGroupRule::rule_set& affined, return err.none(); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VMGroupRule::reduce(rule_set affined, rule_set& reduced_set) +{ + VMGroupRule::rule_set::iterator it, jt; + + VMGroupRule reduced_rule; + + for ( it = affined.begin(), reduced_rule = (*it) ; it != affined.end() ; ) + { + bool reduced = false; + + for ( jt = affined.begin() ; jt != affined.end() ; ) + { + VMGroupRule tmp = *it; + + tmp &= *jt; + + if ( it == jt || (reduced_rule & *jt).none() ) + { + ++jt; + } + else + { + reduced_rule |= *jt; + + jt = affined.erase(jt); + + reduced = true; + } + } + + if (!reduced) + { + reduced_set.insert(reduced_rule); + + reduced_rule = *(++it); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + std::ostream& operator<<(std::ostream& os, VMGroupPolicy policy) { switch(policy) From 90ed2f5c28e7b6f10b0798be81d23f71a19c262f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 25 Jan 2017 23:37:50 +0100 Subject: [PATCH 23/26] F #2347: Re-evaluate host requirements in dispatch loop to fulfil anti-affinity rules --- src/scheduler/src/pool/VMGroupXML.cc | 6 ++--- src/scheduler/src/sched/Scheduler.cc | 33 +++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 60a496e4cd..60ddcbe11d 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -351,12 +351,12 @@ static void schecule_affined_set(std::set vms, } else { - std::ostringstream oss; + std::ostringstream oss_reqs; std::string reqs; - VMGroupRole::host_requirements(hosts, "=", "|", oss); + VMGroupRole::host_requirements(hosts, "=", "|", oss_reqs); - reqs = oss.str(); + reqs = oss_reqs.str(); for ( it = vms.begin() ; it != vms.end() ; ++it ) { diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 0217969cf0..1d96d72a38 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -598,7 +598,8 @@ static bool match_host(AclXML * acls, UserPoolXML * upool, VirtualMachineXML* vm if (matched == false) { - error = "It does not fulfill SCHED_REQUIREMENTS."; + error = "It does not fulfill SCHED_REQUIREMENTS: " + + vm->get_requirements(); return false; } } @@ -873,7 +874,8 @@ void Scheduler::match_schedule() vmpool->update(vm); - log_match(vm->get_oid(), "Cannot schedule VM, there is no suitable host."); + log_match(vm->get_oid(), + "Cannot schedule VM, there is no suitable host."); continue; } @@ -1072,7 +1074,8 @@ void Scheduler::dispatch() int hid, dsid, cid; unsigned int dispatched_vms = 0; - bool dispatched; + bool dispatched, matched; + char * estr; map::const_iterator vm_it; @@ -1137,6 +1140,26 @@ void Scheduler::dispatch() cid = host->get_cid(); + //------------------------------------------------------------------ + // Check host still match requirements for ANTI_AFFINITY rules + //------------------------------------------------------------------ + if ( host->eval_bool(vm->get_requirements(), matched, &estr) != 0 ) + { + free(estr); + continue; + } + + if (matched == false) + { + std::ostringstream mss; + + mss << "Host " << hid << " no longer meets requirements for VM " + << vm->get_oid() << "\n"; + + NebulaLog::log("SCHED", Log::DEBUG, mss); + continue; + } + //------------------------------------------------------------------ // Test host capacity //------------------------------------------------------------------ @@ -1415,11 +1438,11 @@ void Scheduler::do_vm_groups() oss << *grp << "\n"; + grp->set_affinity_requirements(vmpool, vm_roles_pool, oss); + grp->set_antiaffinity_requirements(vmpool, oss); grp->set_host_requirements(vmpool, oss); - - grp->set_affinity_requirements(vmpool, vm_roles_pool, oss); } NebulaLog::log("VMGRP", Log::DDDEBUG, oss); From a845425a1d027f709c67648088cb5d3857d73711 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 26 Jan 2017 17:06:46 +0100 Subject: [PATCH 24/26] F #2347: Fix minor bugs in CLI. Better dispatching for affined groups, fix issue for anti-affined sets --- src/cli/one_helper/onevmgroup_helper.rb | 4 +- src/scheduler/include/VirtualMachineXML.h | 26 ++++++++++- src/scheduler/src/pool/VMGroupXML.cc | 44 ++++++++++-------- src/scheduler/src/pool/VirtualMachineXML.cc | 6 ++- src/scheduler/src/sched/Scheduler.cc | 49 ++++++++++++++++++--- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index ec2883c271..7ff03699af 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -47,7 +47,7 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper end column :VMS, "Number of VMs in the VM Group", :left, :size=>4 do |d| - roles = d["ROLES"]["ROLE"] + roles = [d["ROLES"]["ROLE"]].flatten vms = 0 if !roles.nil? @@ -60,7 +60,7 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper end column :ROLES, "Roles in the VM Group", :left, :size=>36 do |d| - roles = d["ROLES"]["ROLE"] + roles = [d["ROLES"]["ROLE"]].flatten roles_names = "" if !roles.nil? diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index 4d25809815..d02aefb34f 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -122,12 +122,12 @@ public: vector &pci); /** - * Return the requirements of this VM (as is) + * Return the requirements of this VM (as is) and reset them * @param cpu in unit * @param memory in kb * @param disk in mb (system ds usage) */ - void get_raw_requirements(float& cpu, int& memory, long long& disk); + void reset_requirements(float& cpu, int& memory, long long& disk); /** * @return the usage requirements in image ds. @@ -262,6 +262,23 @@ public: */ bool is_only_public_cloud() const; + /** + * Add a VM to the set of affined VMs. This is used for the VM leader + * when scheduling a group. + * + * @param vmid of the affined vm + * + */ + void add_affined(int vmid) + { + affined_vms.insert(vmid); + } + + const set& get_affined_vms() const + { + return affined_vms; + } + //-------------------------------------------------------------------------- // Capacity Interface //-------------------------------------------------------------------------- @@ -361,12 +378,16 @@ protected: void init_storage_usage(); + /* ------------------- SCHEDULER INFORMATION --------------------------- */ + ResourceMatch match_hosts; ResourceMatch match_datastores; bool only_public_cloud; + set affined_vms; + /* ----------------------- VIRTUAL MACHINE ATTRIBUTES ------------------- */ int oid; @@ -397,6 +418,7 @@ protected: VirtualMachineTemplate * vm_template; /**< The VM template */ VirtualMachineTemplate * user_template; /**< The VM user template */ + }; #endif /* VM_XML_H_ */ diff --git a/src/scheduler/src/pool/VMGroupXML.cc b/src/scheduler/src/pool/VMGroupXML.cc index 60ddcbe11d..1a6ed2349c 100644 --- a/src/scheduler/src/pool/VMGroupXML.cc +++ b/src/scheduler/src/pool/VMGroupXML.cc @@ -203,8 +203,6 @@ void VMGroupXML::set_antiaffinity_requirements(VirtualMachinePoolXML * vmpool, } } } - - NebulaLog::log("VMGRP", Log::DEBUG, oss); } /* -------------------------------------------------------------------------- */ @@ -267,18 +265,21 @@ void VMGroupXML::set_host_requirements(VirtualMachinePoolXML * vmpool, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -static void schecule_affined_set(std::set vms, +static void schecule_affined_set(const std::set& vms, VirtualMachinePoolXML * vmpool, VirtualMachineRolePoolXML * vm_roles_pool, std::ostringstream& oss) { std::set::iterator it; std::set hosts; - if ( vms.size() == 0 ) + if ( vms.size() <= 1 ) { return; } + /* ---------------------------------------------------------------------- */ + /* Get hosts where the affined set is running */ + /* ---------------------------------------------------------------------- */ for ( it = vms.begin() ; it != vms.end() ; ++it ) { VirtualMachineXML * vm = vm_roles_pool->get(*it); @@ -298,6 +299,12 @@ static void schecule_affined_set(std::set vms, if ( hosts.size() == 0 ) { + /* ------------------------------------------------------------------ */ + /* No VMs of the set are running: */ + /* 1. Select a set leader */ + /* 2. Allocate VMs in the same host as the leader */ + /* 3. Aggregate requirements in the leader for scheduling */ + /* ------------------------------------------------------------------ */ VirtualMachineXML * vm; for ( it = vms.begin(); it != vms.end() ; ++it ) @@ -335,10 +342,11 @@ static void schecule_affined_set(std::set vms, continue; } - tmp->get_raw_requirements(cpu, memory, disk); + tmp->reset_requirements(cpu, memory, disk); vm->add_requirements(cpu, memory, disk); vm->add_requirements(tmp->get_requirements()); + vm->add_affined(*it); tmp->add_requirements(areqs_s); @@ -351,6 +359,10 @@ static void schecule_affined_set(std::set vms, } else { + /* ------------------------------------------------------------------ */ + /* VMs in the group already running */ + /* 1. Assign VMs to one of the hosts used by the affined set */ + /* ------------------------------------------------------------------ */ std::ostringstream oss_reqs; std::string reqs; @@ -461,14 +473,13 @@ static ostream& operator<<(ostream& os, VMGroupRule::rule_set rules) { const VMGroupRule::role_bitset rroles = (*rit).get_roles(); - os << setfill(' ') << setw(14) << ' ' << left << setw(14) - << (*rit).get_policy() << " "; + os << left << setw(14) << (*rit).get_policy() << " "; for (int i = 0 ; i id() << " " + os << left << setw(7) << (*it)->id() << " " << left << setw(8) << (*it)->name() << " " << left << setw(12)<< (*it)->policy_s() << " " << left << (*it)->vms_s() << "\n"; } os << "\n"; - os << setfill(' ') << setw(14) << ' ' << left << "RULES" << "\n" - << setfill(' ') << setw(14) << ' ' << setfill('-') << setw(50) << '-' - << setfill(' ') << "\n"; + os << left << "RULES" << "\n" + << setfill('-') << setw(80) << '-' << setfill(' ') << "\n"; os << vmg.affined; diff --git a/src/scheduler/src/pool/VirtualMachineXML.cc b/src/scheduler/src/pool/VirtualMachineXML.cc index 1303fbec07..33ec5ff23a 100644 --- a/src/scheduler/src/pool/VirtualMachineXML.cc +++ b/src/scheduler/src/pool/VirtualMachineXML.cc @@ -214,11 +214,15 @@ void VirtualMachineXML::add_requirements(float c, int m, long long d) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachineXML::get_raw_requirements (float& c, int& m, long long& d) +void VirtualMachineXML::reset_requirements(float& c, int& m, long long& d) { c = cpu; m = memory; d = system_ds_usage; + + cpu = 0; + memory = 0; + system_ds_usage = 0; } /* -------------------------------------------------------------------------- */ diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 1d96d72a38..9fc157640f 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -1141,12 +1141,18 @@ void Scheduler::dispatch() cid = host->get_cid(); //------------------------------------------------------------------ - // Check host still match requirements for ANTI_AFFINITY rules + // Check host still match requirements with CURRENT_VMS //------------------------------------------------------------------ - if ( host->eval_bool(vm->get_requirements(), matched, &estr) != 0 ) + matched = true; + + if ( one_util::regex_match("CURRENT_VMS", + vm->get_requirements().c_str()) == 0 ) { - free(estr); - continue; + if (host->eval_bool(vm->get_requirements(), matched, &estr)!=0) + { + free(estr); + continue; + } } if (matched == false) @@ -1154,7 +1160,7 @@ void Scheduler::dispatch() std::ostringstream mss; mss << "Host " << hid << " no longer meets requirements for VM " - << vm->get_oid() << "\n"; + << vm->get_oid(); NebulaLog::log("SCHED", Log::DEBUG, mss); continue; @@ -1297,6 +1303,32 @@ void Scheduler::dispatch() } } + //------------------------------------------------------------------ + // VM leaders needs to add the select host to the affined VMs + //------------------------------------------------------------------ + const set& affined_vms = vm->get_affined_vms(); + + if ( affined_vms.size() > 0 ) + { + set::const_iterator it; + + for ( it = affined_vms.begin(); it != affined_vms.end(); ++it ) + { + VirtualMachineXML * avm = vmpool->get(*it); + + if ( avm == 0 ) + { + continue; + } + + avm->add_match_host(hid); + avm->add_match_datastore(dsid); + } + } + + //------------------------------------------------------------------ + // Update usage and statistics counters + //------------------------------------------------------------------ host->add_capacity(vm->get_oid(), cpu, mem, pci); dispatched_vms++; @@ -1430,11 +1462,16 @@ void Scheduler::do_vm_groups() ostringstream oss; + oss << "VM Group Scheduling information\n"; + for (it = vmgrps.begin(); it != vmgrps.end() ; ++it) { VMGroupXML * grp = static_cast(it->second); - oss << "\nSCHEDULING RESULTS FOR VM GROUP: " << grp->get_name() <<"\n"; + oss << setfill('*') << setw(80) << '*' << setfill(' ') << "\n" + << "SCHEDULING RESULTS FOR VM GROUP " << grp->get_oid() << ", " + << grp->get_name() <<"\n" + << setfill('*') << setw(80) << '*' << setfill(' ') << "\n"; oss << *grp << "\n"; From f3a3f9cde1b5b73b656e76d65d28361a1a7e1b39 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 27 Jan 2017 12:11:26 +0100 Subject: [PATCH 25/26] F #2347: Update default ACLS to grant VMGroup create permission --- src/group/Group.cc | 6 ++++-- src/oca/ruby/opennebula/acl.rb | 7 +++++-- src/oca/ruby/opennebula/group.rb | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/group/Group.cc b/src/group/Group.cc index 3e6930c0cc..6882a8bd23 100644 --- a/src/group/Group.cc +++ b/src/group/Group.cc @@ -353,7 +353,7 @@ void Group::add_admin_rules(int user_id) NebulaLog::log("GROUP",Log::ERROR,error_msg); } - // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@ USE+MANAGE * + // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP/@ USE+MANAGE * if ( aclm->add_rule( AclRule::INDIVIDUAL_ID | user_id, @@ -365,6 +365,7 @@ void Group::add_admin_rules(int user_id) PoolObjectSQL::DOCUMENT | PoolObjectSQL::SECGROUP | PoolObjectSQL::VROUTER | + PoolObjectSQL::VMGROUP | AclRule::GROUP_ID | oid, @@ -449,7 +450,7 @@ void Group::del_admin_rules(int user_id) NebulaLog::log("GROUP",Log::ERROR,error_msg); } - // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@ USE+MANAGE * + // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP/@ USE+MANAGE * if ( aclm->del_rule( AclRule::INDIVIDUAL_ID | user_id, @@ -461,6 +462,7 @@ void Group::del_admin_rules(int user_id) PoolObjectSQL::DOCUMENT | PoolObjectSQL::SECGROUP | PoolObjectSQL::VROUTER | + PoolObjectSQL::VMGROUP | AclRule::GROUP_ID | oid, diff --git a/src/oca/ruby/opennebula/acl.rb b/src/oca/ruby/opennebula/acl.rb index 9d54b12f88..2680689dbf 100644 --- a/src/oca/ruby/opennebula/acl.rb +++ b/src/oca/ruby/opennebula/acl.rb @@ -23,14 +23,17 @@ module OpenNebula # @ # ALL # RESOURCE -> + separated list and "/{#,@,%}|ALL" - # VM, + # VM # HOST # NET # IMAGE # USER # TEMPLATE # GROUP - # ACL + # DATASTORE + # CLUSTER + # DOCUMENT + # ZONE # SECGROUP # VDC # VROUTER diff --git a/src/oca/ruby/opennebula/group.rb b/src/oca/ruby/opennebula/group.rb index f31809ca92..0232db71bb 100644 --- a/src/oca/ruby/opennebula/group.rb +++ b/src/oca/ruby/opennebula/group.rb @@ -37,7 +37,7 @@ module OpenNebula SELF = -1 # Default resource ACL's for group users (create) - GROUP_DEFAULT_ACLS = "VM+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER" + GROUP_DEFAULT_ACLS = "VM+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP" # The default view for group and group admins, must be defined in # sunstone_views.yaml From 4c1d4de436efc006063f0551c2fd388e05ae1f6e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 27 Jan 2017 12:23:12 +0100 Subject: [PATCH 26/26] F #2347: Add more information in onevmgroup show command for each role --- src/cli/one_helper/onevmgroup_helper.rb | 28 +++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index 7ff03699af..4fc82f64dc 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -129,11 +129,35 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper d["ID"] end - column :NAME, "", :left, :size=>16 do |d| + column :NAME, "", :left, :size=>8 do |d| d["NAME"] end - column :VIRTUAL_MACHINES, "", :left, :size=>32 do |d| + column :POLICY, "", :left, :size=>12 do |d| + if d["POLICY"].nil? + '-' + else + d["POLICY"] + end + end + + column :AFFINED_HOSTS, "", :left, :size=>18 do |d| + if d["HOST_AFFINED"].nil? + '-' + else + d["HOST_AFFINED"] + end + end + + column :ANTI_AFFINED_HOST, "", :left, :size=>18 do |d| + if d["HOST_ANTI_AFFINED"].nil? + '-' + else + d["HOST_ANTI_AFFINED"] + end + end + + column :VIRTUAL_MACHINES, "", :left, :size=>20 do |d| d["VMS"] end end.show(roles, {})