/* -------------------------------------------------------------------------- */ /* Copyright 2002-2017, 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 #include #include #include #include #include "PoolSQL.h" #include "RequestManagerPoolInfoFilter.h" #include /* ************************************************************************** */ /* PoolSQL constructor/destructor */ /* ************************************************************************** */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ static int _get_lastOID(SqlDB * db, const string& table) { ostringstream oss; int _last_oid = -1; single_cb cb; cb.set_callback(&_last_oid); oss << "SELECT last_oid FROM pool_control WHERE tablename='" << table <<"'"; db->exec_rd(oss, &cb); cb.unset_callback(); return _last_oid; } int PoolSQL::get_lastOID() { int _last_oid; lock(); _last_oid = _get_lastOID(db, table); unlock(); return _last_oid; } /* -------------------------------------------------------------------------- */ static void _set_lastOID(int _last_oid, SqlDB * db, const string& table) { ostringstream oss; oss << "REPLACE INTO pool_control (tablename, last_oid) VALUES ('" << table << "'," << _last_oid << ")"; db->exec_wr(oss); } void PoolSQL::set_lastOID(int _last_oid) { lock(); _set_lastOID(_last_oid, db, table); unlock(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ PoolSQL::PoolSQL(SqlDB * _db, const char * _table): db(_db), table(_table) { pthread_mutex_init(&mutex,0); }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ PoolSQL::~PoolSQL() { vector::iterator it; pthread_mutex_lock(&mutex); for ( it = pool.begin(); it != pool.end(); ++it) { (*it)->lock(); delete *it; } pthread_mutex_unlock(&mutex); pthread_mutex_destroy(&mutex); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* PoolSQL public interface */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int PoolSQL::allocate(PoolObjectSQL *objsql, string& error_str) { int rc; int lastOID; lock(); lastOID = _get_lastOID(db, table); if (lastOID == INT_MAX) { lastOID = -1; } objsql->lock(); objsql->oid = ++lastOID; rc = objsql->insert(db, error_str); if ( rc != 0 ) { rc = -1; } else { rc = lastOID; do_hooks(objsql, Hook::ALLOCATE); } delete objsql; if( rc != -1 ) { _set_lastOID(lastOID, db, table); } unlock(); return rc; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ PoolObjectSQL * PoolSQL::get(int oid, bool olock) { if ( oid < 0 ) { return 0; } lock(); flush_cache(oid); PoolObjectSQL * objectsql = create(); objectsql->oid = oid; int rc = objectsql->select(db); if ( rc != 0 ) { objectsql->lock(); delete objectsql; unlock(); return 0; } pool.push_back(objectsql); if ( olock == true ) { objectsql->lock(); } unlock(); return objectsql; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock) { lock(); string name_key = key(name, ouid); flush_cache(name_key); PoolObjectSQL * objectsql = create(); int rc = objectsql->select(db, name, ouid); if ( rc != 0 ) { objectsql->lock(); delete objectsql; unlock(); return 0; } pool.push_back(objectsql); if ( olock == true ) { objectsql->lock(); } unlock(); return objectsql; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void PoolSQL::flush_cache(int oid) { for (vector::iterator it = pool.begin(); it != pool.end();) { // The object we are looking for in ::get(). Wait until it is unlocked() if ((*it)->oid == oid) { (*it)->lock(); } else { // Any other locked object is just ignored int rc = pthread_mutex_trylock(&((*it)->mutex)); if ( rc == EBUSY ) // In use by other thread { it++; continue; } } delete *it; it = pool.erase(it); } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void PoolSQL::flush_cache(const string& name_key) { for (vector::iterator it = pool.begin(); it != pool.end();) { string okey = key((*it)->name, (*it)->uid); // The object we are looking for in ::get(). Wait until it is unlocked() if ( name_key == okey) { (*it)->lock(); } else { // Any other locked object is just ignored int rc = pthread_mutex_trylock(&((*it)->mutex)); if ( rc == EBUSY ) // In use by other thread { it++; continue; } } delete *it; it = pool.erase(it); } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void PoolSQL::clean() { vector::iterator it; lock(); for (it = pool.begin(); it != pool.end(); ++it) { (*it)->lock(); delete *it; } pool.clear(); unlock(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int PoolSQL::dump_cb(void * _oss, int num, char **values, char **names) { ostringstream * oss; oss = static_cast(_oss); if ( (!values[0]) || (num != 1) ) { return -1; } *oss << values[0]; return 0; } /* -------------------------------------------------------------------------- */ int PoolSQL::dump(ostringstream& oss, const string& elem_name, const char* table, const string& where, const string& limit) { ostringstream cmd; cmd << "SELECT body FROM " << table; if ( !where.empty() ) { cmd << " WHERE " << where; } cmd << " ORDER BY oid"; if ( !limit.empty() ) { cmd << " LIMIT " << limit; } return dump(oss, elem_name, cmd); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int PoolSQL::dump(ostringstream& oss, const string& root_elem_name, ostringstream& sql_query) { int rc; oss << "<" << root_elem_name << ">"; set_callback(static_cast(&PoolSQL::dump_cb), static_cast(&oss)); rc = db->exec_rd(sql_query, this); add_extra_xml(oss); oss << ""; unset_callback(); return rc; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int PoolSQL:: search_cb(void * _oids, int num, char **values, char **names) { vector * oids; oids = static_cast *>(_oids); if ( num == 0 || values == 0 || values[0] == 0 ) { return -1; } oids->push_back(atoi(values[0])); return 0; } /* -------------------------------------------------------------------------- */ int PoolSQL::search( vector& oids, const char * table, const string& where) { ostringstream sql; int rc; set_callback(static_cast(&PoolSQL::search_cb), static_cast(&oids)); sql << "SELECT oid FROM " << table; if (!where.empty()) { sql << " WHERE " << where; } rc = db->exec_rd(sql, this); unset_callback(); return rc; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void PoolSQL::acl_filter(int uid, const set& user_groups, PoolObjectSQL::ObjectType auth_object, bool& all, bool disable_all_acl, bool disable_cluster_acl, bool disable_group_acl, string& filter) { filter.clear(); if ( uid == UserPool::ONEADMIN_ID || user_groups.count( GroupPool::ONEADMIN_ID ) == 1 ) { all = true; return; } Nebula& nd = Nebula::instance(); AclManager* aclm = nd.get_aclm(); ostringstream acl_filter; vector::iterator it; vector oids; vector gids; vector cids; aclm->reverse_search(uid, user_groups, auth_object, AuthRequest::USE, disable_all_acl, disable_cluster_acl, disable_group_acl, all, oids, gids, cids); for ( it = oids.begin(); it < oids.end(); it++ ) { acl_filter << " OR oid = " << *it; } for ( it = gids.begin(); it < gids.end(); it++ ) { acl_filter << " OR gid = " << *it; } ClusterPool::cluster_acl_filter(acl_filter, auth_object, cids); filter = acl_filter.str(); } /* -------------------------------------------------------------------------- */ void PoolSQL::usr_filter(int uid, int gid, const set& user_groups, int filter_flag, bool all, const string& acl_str, string& filter) { ostringstream uid_filter; set::iterator g_it; if ( filter_flag == RequestManagerPoolInfoFilter::MINE ) { uid_filter << "uid = " << uid; } else if ( filter_flag == RequestManagerPoolInfoFilter::GROUP ) { uid_filter << "gid = " << gid; } else if ( filter_flag == RequestManagerPoolInfoFilter::MINE_GROUP ) { uid_filter << "uid = " << uid << " OR ( ("; string sep = " "; for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++) { uid_filter << sep << "( gid = " << *g_it << " )"; sep = " OR "; } uid_filter << ")"; if ( !all ) { uid_filter << " AND ( other_u = 1"; for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++) { uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )"; } uid_filter << acl_str << ")"; } uid_filter << ")"; } else if ( filter_flag == RequestManagerPoolInfoFilter::ALL ) { if (!all) { uid_filter << " uid = " << uid << " OR other_u = 1"; for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++) { uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )"; } uid_filter << acl_str; } } else { uid_filter << "uid = " << filter_flag; if ( filter_flag != uid && !all ) { uid_filter << " AND ( other_u = 1"; for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++) { uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )"; } uid_filter << acl_str << ")"; } } filter = uid_filter.str(); } /* -------------------------------------------------------------------------- */ void PoolSQL::oid_filter(int start_id, int end_id, string& filter) { ostringstream idfilter; if ( end_id >= -1 && start_id != -1 ) { idfilter << "oid >= " << start_id; if ( end_id != -1 ) { idfilter << " AND oid <= " << end_id; } } filter = idfilter.str(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void PoolSQL::register_hooks(vector hook_mads, const string& remotes_location) { string name; string on; string cmd; string arg; for (unsigned int i = 0 ; i < hook_mads.size() ; i++ ) { name = hook_mads[i]->vector_value("NAME"); on = hook_mads[i]->vector_value("ON"); cmd = hook_mads[i]->vector_value("COMMAND"); arg = hook_mads[i]->vector_value("ARGUMENTS"); one_util::toupper(on); if ( on.empty() || cmd.empty() ) { NebulaLog::log("VM", Log::WARNING, "Empty ON or COMMAND attribute" " in Hook, not registered!"); continue; } if ( name.empty() ) { name = cmd; } if (cmd[0] != '/') { ostringstream cmd_os; cmd_os << remotes_location << "/hooks/" << cmd; cmd = cmd_os.str(); } if ( on == "CREATE" ) { AllocateHook * hook; hook = new AllocateHook(name, cmd, arg, false); add_hook(hook); } else if ( on == "REMOVE" ) { RemoveHook * hook; hook = new RemoveHook(name, cmd, arg, false); add_hook(hook); } } }