From 3ed14a9f680bd0ec8f864ef03e3a98af6809026e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tino=20V=C3=A1zquez?= Date: Tue, 3 Aug 2010 19:22:13 +0200 Subject: [PATCH] bug #295: Adding persistence to images --- include/Image.h | 64 ++++++++-- include/RequestManager.h | 25 ++++ src/image/Image.cc | 100 ++++++++++----- src/rm/RequestManager.cc | 20 +-- src/rm/RequestManagerImagePersistent.cc | 157 ++++++++++++++++++++++++ src/rm/RequestManagerImagePublish.cc | 14 ++- src/rm/SConstruct | 1 + 7 files changed, 337 insertions(+), 44 deletions(-) create mode 100644 src/rm/RequestManagerImagePersistent.cc diff --git a/include/Image.h b/include/Image.h index 1fba0dafe5..d487d7bee1 100644 --- a/include/Image.h +++ b/include/Image.h @@ -108,6 +108,15 @@ public: { return (public_img == 1); }; + + /** + * Returns true if the image is persistent + * @return true if the image is persistent + */ + bool isPersistent() + { + return (persistent_img == 1); + }; /** * Set enum type @@ -183,16 +192,51 @@ public: * @param pub true to publish the image * @return 0 on success */ - void publish(bool pub) + bool publish(bool pub) { + bool success = false; + if (pub == true) { - public_img = 1; + if (!isPersistent()) + { + public_img = 1; + success = true; + } } else { public_img = 0; + success = true; } + + return success; + } + + /** + * Set/Unset an image as persistant + * @param persistent true to make an image persistant + * @return 0 on success + */ + bool persistent(bool persis) + { + bool success = false; + + if (persis == true) + { + if (!isPublic() && running_vms == 0) + { + persistent_img = 1; + success = true; + } + } + else + { + persistent_img = 0; + success = true; + } + + return success; } /** @@ -309,6 +353,11 @@ private: * Public scope of the Image */ int public_img; + + /** + * Persistency of the Image + */ + int persistent_img; /** * Registration time @@ -402,12 +451,13 @@ protected: NAME = 2, /* Image name */ TYPE = 3, /* 0) OS 1) CDROM 2) DATABLOCK */ PUBLIC = 4, /* Public scope (YES OR NO) */ - REGTIME = 5, /* Time of registration */ - SOURCE = 6, /* Path to the image */ - STATE = 7, /* 0) INIT 1) ALLOCATED */ + PERSISTENT = 5, /* Peristency (YES OR NO) */ + REGTIME = 6, /* Time of registration */ + SOURCE = 7, /* Path to the image */ + STATE = 8, /* 0) INIT 1) ALLOCATED */ /* 2) READY 3) USED */ - RUNNING_VMS = 8, /* Number of VMs using the img */ - LIMIT = 9 + RUNNING_VMS = 9, /* Number of VMs using the img */ + LIMIT = 10 }; static const char * db_names; diff --git a/include/RequestManager.h b/include/RequestManager.h index 8035b90fe5..50c4d97fb8 100644 --- a/include/RequestManager.h +++ b/include/RequestManager.h @@ -1156,6 +1156,31 @@ private: /* ---------------------------------------------------------------------- */ + class ImagePersistent: public xmlrpc_c::method + { + public: + ImagePersistent(ImagePool * _ipool, + UserPool * _upool): + ipool(_ipool), + upool(_upool) + { + _signature="A:sib"; + _help="Make an Image (non)persistent"; + }; + + ~ImagePersistent(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + ImagePool * ipool; + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + class ImageEnable: public xmlrpc_c::method { public: diff --git a/src/image/Image.cc b/src/image/Image.cc index a90beefd8b..a2e4bd88a3 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -71,7 +71,7 @@ const char * Image::db_names = "(oid, uid, name, type, public, regtime, " const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool (" "oid INTEGER PRIMARY KEY, uid INTEGER, name VARCHAR(128), " - "type INTEGER, public INTEGER, regtime INTEGER, source TEXT, state INTEGER, " + "type INTEGER, public INTEGER, persistent INTEGER, regtime INTEGER, source TEXT, state INTEGER, " "running_vms INTEGER, UNIQUE(name) )"; /* ------------------------------------------------------------------------ */ @@ -84,6 +84,7 @@ int Image::select_cb(void * nil, int num, char **values, char ** names) (!values[NAME]) || (!values[TYPE]) || (!values[PUBLIC]) || + (!values[PERSISTENT]) || (!values[REGTIME]) || (!values[SOURCE]) || (!values[STATE]) || @@ -98,9 +99,10 @@ int Image::select_cb(void * nil, int num, char **values, char ** names) name = values[NAME]; - type = static_cast(atoi(values[TYPE])); - public_img = atoi(values[PUBLIC]); - regtime = static_cast(atoi(values[REGTIME])); + type = static_cast(atoi(values[TYPE])); + public_img = atoi(values[PUBLIC]); + persistent_img = atoi(values[PERSISTENT]); + regtime = static_cast(atoi(values[REGTIME])); source = values[SOURCE]; @@ -159,6 +161,7 @@ int Image::insert(SqlDB *db) string source_att; string type_att; string public_attr; + string persistent_attr; string dev_prefix; ostringstream tmp_hashstream; @@ -203,6 +206,23 @@ int Image::insert(SqlDB *db) (int(*)(int))toupper); public_img = (public_attr == "YES"); + + // ------------ PERSISTENT -------------------- + + get_template_attribute("PERSISTENT", persistent_attr); + image_template->erase("PERSISTENT"); + + transform (persistent_attr.begin(), persistent_attr.end(), persistent_attr.begin(), + (int(*)(int))toupper); + + persistent_img = (persistent_attr == "YES"); + + // An image cannot be public and persistent simultaneously + + if ( public_img && persistent_img ) + { + goto error_public_and_persistent; + } // ------------ PREFIX -------------------- @@ -263,6 +283,10 @@ error_name: error_type: NebulaLog::log("IMG", Log::ERROR, "Incorrect TYPE in image template"); goto error_common; + +error_public_and_persistent: + NebulaLog::log("IMG", Log::ERROR, "Image cannot be public and persistant"); + goto error_common; error_common: return -1; @@ -321,6 +345,7 @@ int Image::insert_replace(SqlDB *db, bool replace) << "'" << sql_name << "'," << type << "," << public_img << "," + << persistent_img << "," << regtime << "," << "'" << sql_source << "'," << state << "," @@ -349,6 +374,7 @@ int Image::dump(ostringstream& oss, int num, char **values, char **names) (!values[NAME]) || (!values[TYPE]) || (!values[PUBLIC]) || + (!values[PERSISTENT]) || (!values[REGTIME]) || (!values[SOURCE]) || (!values[STATE]) || @@ -366,6 +392,7 @@ int Image::dump(ostringstream& oss, int num, char **values, char **names) "" << values[NAME] << "" << "" << values[TYPE] << "" << "" << values[PUBLIC] << "" << + "" << values[PERSISTENT] << "" << "" << values[REGTIME] << "" << "" << values[SOURCE] << "" << "" << values[STATE] << "" << @@ -426,20 +453,19 @@ string& Image::to_xml(string& xml) const string template_xml; ostringstream oss; - - oss << "" << - "" << oid << "" << - "" << uid << "" << - "" << name << "" << - "" << type << "" << - "" << public_img << "" << - "" << regtime << "" << - "" << source << "" << - "" << state << "" << - "" << running_vms << "" << - image_template->to_xml(template_xml) << + "" << oid << "" << + "" << uid << "" << + "" << name << "" << + "" << type << "" << + "" << public_img << "" << + "" << persistent_img << "" << + "" << regtime << "" << + "" << source << "" << + "" << state << "" << + "" << running_vms << "" << + image_template->to_xml(template_xml) << ""; xml = oss.str(); @@ -457,15 +483,16 @@ string& Image::to_str(string& str) const ostringstream os; os << - "ID = " << oid << endl << - "UID = " << uid << endl << - "NAME = " << name << endl << - "TYPE = " << type << endl << - "PUBLIC = " << public_img << endl << - "REGTIME = " << regtime << endl << - "SOURCE = " << source << endl << - "STATE = " << state << endl << - "RUNNING_VMS = " << running_vms << endl << + "ID = " << oid << endl << + "UID = " << uid << endl << + "NAME = " << name << endl << + "TYPE = " << type << endl << + "PUBLIC = " << public_img << endl << + "PERSISTENT = " << persistent_img << endl << + "REGTIME = " << regtime << endl << + "SOURCE = " << source << endl << + "STATE = " << state << endl << + "RUNNING_VMS = " << running_vms << endl << "TEMPLATE" << endl << image_template->to_str(template_str) << endl; @@ -491,7 +518,14 @@ int Image::acquire_image() break; case USED: - running_vms++; + if (persistent_img) + { + rc = -1; + } + else + { + running_vms++; + } break; case DISABLED: @@ -589,8 +623,18 @@ int Image::disk_attribute( VectorAttribute * disk, // TYPE, READONLY, CLONE, and SAVE attributes //--------------------------------------------------------------------------- - new_disk.insert(make_pair("CLONE","YES")); - new_disk.insert(make_pair("SAVE","NO")); + if ( persistent_img ) + { + new_disk.insert(make_pair("CLONE","NO")); + new_disk.insert(make_pair("SAVE","YES")); + + new_disk.insert(make_pair("SAVE_AS", iid.str())); // Tells the hook to overwrite + } + else + { + new_disk.insert(make_pair("CLONE","YES")); + new_disk.insert(make_pair("SAVE","NO")); + } switch(type) { diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index eef1d2cf52..46685c20c2 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -312,6 +312,9 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr image_publish(new RequestManager::ImagePublish(ipool, upool)); + xmlrpc_c::methodPtr image_persistent(new + RequestManager::ImagePersistent(ipool, upool)); + xmlrpc_c::methodPtr image_enable(new RequestManager::ImageEnable(ipool, upool)); @@ -368,15 +371,16 @@ void RequestManager::register_xml_methods() /* Image related methods*/ - RequestManagerRegistry.addMethod("one.image.allocate",image_allocate); - RequestManagerRegistry.addMethod("one.image.delete", image_delete); - RequestManagerRegistry.addMethod("one.image.info", image_info); - RequestManagerRegistry.addMethod("one.image.update", image_update); - RequestManagerRegistry.addMethod("one.image.rmattr", image_rm_attribute); - RequestManagerRegistry.addMethod("one.image.publish", image_publish); - RequestManagerRegistry.addMethod("one.image.enable", image_enable); + RequestManagerRegistry.addMethod("one.image.allocate", image_allocate); + RequestManagerRegistry.addMethod("one.image.delete", image_delete); + RequestManagerRegistry.addMethod("one.image.info", image_info); + RequestManagerRegistry.addMethod("one.image.update", image_update); + RequestManagerRegistry.addMethod("one.image.rmattr", image_rm_attribute); + RequestManagerRegistry.addMethod("one.image.publish", image_publish); + RequestManagerRegistry.addMethod("one.image.persistent", image_persistent); + RequestManagerRegistry.addMethod("one.image.enable", image_enable); - RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); + RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); }; diff --git a/src/rm/RequestManagerImagePersistent.cc b/src/rm/RequestManagerImagePersistent.cc new file mode 100644 index 0000000000..072e36530d --- /dev/null +++ b/src/rm/RequestManagerImagePersistent.cc @@ -0,0 +1,157 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2010, 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 "RequestManager.h" + +#include "NebulaLog.h" +#include "Nebula.h" + +#include "AuthManager.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::ImagePersistent::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + + int iid; + bool persistent_flag; + int uid; + + int image_owner; + bool is_persistent; + + Image * image; + + ostringstream oss; + + bool response; + + const string method_name = "ImagePersistent"; + + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + + NebulaLog::log("ReM",Log::DEBUG,"ImagePersistent invoked"); + + session = xmlrpc_c::value_string (paramList.getString(0)); + iid = xmlrpc_c::value_int (paramList.getInt(1)); + persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2)); + + // First, we need to authenticate the user + uid = ImagePersistent::upool->authenticate(session); + + if ( uid == -1 ) + { + goto error_authenticate; + } + + // Get image from the ImagePool + image = ImagePersistent::ipool->get(iid,true); + + if ( image == 0 ) + { + goto error_image_get; + } + + image_owner = image->get_uid(); + is_persistent = image->isPersistent(); + + image->unlock(); + + //Authorize the operation + if ( uid != 0 ) // uid == 0 means oneadmin + { + AuthRequest ar(uid); + + ar.add_auth(AuthRequest::IMAGE, + iid, + AuthRequest::MANAGE, + image_owner, + false); + + if (UserPool::authorize(ar) == -1) + { + goto error_authorize; + } + } + + // Get the image locked again + image = ImagePersistent::ipool->get(iid,true); + + if ( image == 0 ) + { + goto error_image_get; + } + + response = image->persistent(persistent_flag); + + if (response) + { + goto error_persistent; + } + + ImagePersistent::ipool->update(image); + + image->unlock(); + + arrayData.push_back(xmlrpc_c::value_boolean(true)); + arrayData.push_back(xmlrpc_c::value_int(iid)); + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + return; + +error_authenticate: + oss.str(authenticate_error(method_name)); + goto error_common; + +error_image_get: + oss.str(get_error(method_name, "IMAGE", iid)); + goto error_common; + +error_authorize: + oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid)); + goto error_common; + +error_persistent: + oss << action_error(method_name, "MANAGE", "IMAGE", iid, -1) + << ". Is the image public? An Image cannot be public and persistent."; + goto error_common; + +error_common: + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + NebulaLog::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerImagePublish.cc b/src/rm/RequestManagerImagePublish.cc index 9137766983..d61ac910d5 100644 --- a/src/rm/RequestManagerImagePublish.cc +++ b/src/rm/RequestManagerImagePublish.cc @@ -38,6 +38,8 @@ void RequestManager::ImagePublish::execute( bool is_public; Image * image; + + bool response; ostringstream oss; @@ -99,7 +101,12 @@ void RequestManager::ImagePublish::execute( goto error_image_get; } - image->publish(publish_flag); + response = image->publish(publish_flag); + + if (!response) + { + goto error_publish; + } ImagePublish::ipool->update(image); @@ -128,6 +135,11 @@ error_authorize: oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid)); goto error_common; +error_publish: + oss << action_error(method_name, "MANAGE", "IMAGE", iid, -1) + << ". Is the image persistent? An Image cannot be public and persistent."; + goto error_common; + error_common: arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE arrayData.push_back(xmlrpc_c::value_string(oss.str())); diff --git a/src/rm/SConstruct b/src/rm/SConstruct index 8bdf6dc050..42a9da1f83 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -41,6 +41,7 @@ source_files=[ 'RequestManagerImageUpdate.cc', 'RequestManagerImageRemoveAttribute.cc', 'RequestManagerImagePublish.cc', + 'RequestManagerImagePersistent.cc', 'RequestManagerImageEnable.cc', 'RequestManagerImagePoolInfo.cc', 'RequestManagerClusterAdd.cc',