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

Feature #4400: New param to clone templates recursively

This commit is contained in:
Carlos Martín 2016-04-11 12:25:02 +02:00
parent f6bd738af2
commit 01a0079f0c
11 changed files with 460 additions and 117 deletions

View File

@ -213,10 +213,19 @@ public:
* Gets the IDs of the images associated to a set of disks
* @param dsk a vector with the DISK attributes
* @param ids set of image ids
* @param uid effective user id makeing the call
* @param uid effective user id making the call
*/
void get_image_ids(vector<VectorAttribute *>& dsk, set<int>& ids, int uid);
/**
* Gets the IDs of the images associated to a set of disks
* @param disk DISK attribute
* @param ids the image id, if found
* @param uid effective user id making the call
* @return 0 if the disk uses an image, -1 otherwise
*/
int get_image_id(VectorAttribute * disk, int &id, int uid);
private:
//--------------------------------------------------------------------------
// Configuration Attributes for Images

View File

@ -299,6 +299,26 @@ protected:
bool basic_authorization(int oid, AuthRequest::Operation op,
RequestAttributes& att);
/**
* Performs a basic authorization for this request using the uid/gid
* from the request. The function gets the object from the pool to get
* the public attribute and its owner. The authorization is based on
* object and type of operation for the request.
* @param pool object pool
* @param oid of the object, can be -1 for objects to be created, or
* pools.
* @param op operation of the request.
* @param att the specific request attributes
*
* @return SUCCESS if the user is authorized.
*/
static ErrorCode basic_authorization(
PoolSQL* pool,
int oid,
AuthRequest::Operation op,
PoolObjectSQL::ObjectType auth_object,
RequestAttributes& att);
/**
* Performs a basic quota check for this request using the uid/gid
* from the request. Usage counters are updated for the user/group.

View File

@ -42,6 +42,12 @@ protected:
virtual void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
ErrorCode clone(
int source_id,
const string &name,
int &new_id,
RequestAttributes& att);
virtual Template * clone_template(PoolObjectSQL* obj) = 0;
virtual int pool_allocate(
@ -59,7 +65,8 @@ class VMTemplateClone : public RequestManagerClone
public:
VMTemplateClone():
RequestManagerClone("VMTemplateClone",
"Clone an existing virtual machine template")
"Clone an existing virtual machine template",
"A:sisb")
{
Nebula& nd = Nebula::instance();
pool = nd.get_tpool();
@ -72,6 +79,9 @@ public:
/* -------------------------------------------------------------------- */
void request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
Template * clone_template(PoolObjectSQL* obj)
{
return static_cast<VMTemplate*>(obj)->clone_template();

View File

@ -107,6 +107,8 @@ public:
void request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
static ErrorCode request_execute(int oid, bool recursive, RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */

View File

@ -80,6 +80,11 @@ public:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
static ErrorCode request_execute(
int id,
bool persistent_flag,
RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */
@ -117,6 +122,13 @@ public:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
static ErrorCode clone_img(
int clone_id,
const string &name,
int ds_id,
int &new_id,
RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */

View File

@ -88,6 +88,20 @@ public:
}
}
// Replaces the current DISK attributes with the given ones. The objects
// must NOT be deleted by the calling function
void replace_disks(vector<VectorAttribute *>& disks)
{
vector<VectorAttribute *>::iterator i;
obj_template->erase("DISK");
for (i = disks.begin(); i != disks.end(); i++)
{
obj_template->set(*i);
}
}
// ------------------------------------------------------------------------
// Virtual Router
// ------------------------------------------------------------------------

View File

@ -550,7 +550,6 @@ void ImagePool::authorize_disk(VectorAttribute * disk,int uid, AuthRequest * ar)
ar->add_auth(AuthRequest::USE, perm);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -559,36 +558,52 @@ void ImagePool::get_image_ids(vector<VectorAttribute *>& disks, set<int>& ids,
{
vector<VectorAttribute *>::iterator i;
int id;
for ( i = disks.begin() ; i != disks.end(); ++i )
{
if ( get_image_id(*i, id, uid) == 0 )
{
ids.insert(id);
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ImagePool::get_image_id(VectorAttribute * disk, int &id, int uid)
{
int iid;
string iname;
Image * img = 0;
for ( i = disks.begin() ; i != disks.end(); ++i )
if ( disk->vector_value("IMAGE_ID", iid) == 0 )
{
if ( (*i)->vector_value("IMAGE_ID", iid) == 0 )
{
ids.insert(iid);
}
else if ( (*i)->vector_value("IMAGE", iname) == 0 )
{
int uiid = get_disk_uid(*i, uid);
if ( uiid == -1)
{
continue;
}
img = get(iname, uiid, true);
if ( img != 0 )
{
ids.insert(img->get_oid());
img->unlock();
}
}
id = iid;
return 0;
}
else if ( disk->vector_value("IMAGE", iname) == 0 )
{
int uiid = get_disk_uid(disk, uid);
if ( uiid == -1)
{
return -1;
}
img = get(iname, uiid, true);
if ( img != 0 )
{
id = img->get_oid();
img->unlock();
}
return 0;
}
return -1;
}

View File

@ -302,6 +302,29 @@ void Request::execute(
bool Request::basic_authorization(int oid,
AuthRequest::Operation op,
RequestAttributes& att)
{
ErrorCode ec = basic_authorization(pool, oid, op, auth_object, att);
if (ec == SUCCESS)
{
return true;
}
else
{
failure_response(ec, att);
return false;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Request::ErrorCode Request::basic_authorization(
PoolSQL* pool,
int oid,
AuthRequest::Operation op,
PoolObjectSQL::ObjectType auth_object,
RequestAttributes& att)
{
PoolObjectSQL * object;
PoolObjectAuth perms;
@ -313,14 +336,14 @@ bool Request::basic_authorization(int oid,
if ( object == 0 )
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return false;
return NO_EXISTS;
}
if ( att.uid == 0 )
{
object->unlock();
return true;
return SUCCESS;
}
object->get_permissions(perms);
@ -331,7 +354,7 @@ bool Request::basic_authorization(int oid,
{
if ( att.uid == 0 )
{
return true;
return SUCCESS;
}
perms.obj_type = auth_object;
@ -344,12 +367,11 @@ bool Request::basic_authorization(int oid,
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
return false;
return AUTHORIZATION;
}
return true;
return SUCCESS;
}
/* -------------------------------------------------------------------------- */

View File

@ -15,6 +15,8 @@
/* -------------------------------------------------------------------------- */
#include "RequestManagerClone.h"
#include "RequestManagerImage.h"
#include "RequestManagerDelete.h"
#include "PoolObjectAuth.h"
#include "Nebula.h"
@ -28,7 +30,30 @@ void RequestManagerClone::request_execute(
int source_id = xmlrpc_c::value_int(paramList.getInt(1));
string name = xmlrpc_c::value_string(paramList.getString(2));
int rc, new_id;
int new_id;
ErrorCode ec = clone(source_id, name, new_id, att);
if ( ec == SUCCESS )
{
success_response(new_id, att);
}
else
{
failure_response(ec, att);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Request::ErrorCode RequestManagerClone::clone(
int source_id,
const string &name,
int &new_id,
RequestAttributes& att)
{
int rc;
PoolObjectAuth perms;
@ -40,8 +65,7 @@ void RequestManagerClone::request_execute(
if ( source_obj == 0 )
{
att.resp_id = source_id;
failure_response(NO_EXISTS, att);
return;
return NO_EXISTS;
}
tmpl = clone_template(source_obj);
@ -68,10 +92,9 @@ void RequestManagerClone::request_execute(
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
delete tmpl;
return;
return AUTHORIZATION;
}
}
@ -79,11 +102,174 @@ void RequestManagerClone::request_execute(
if ( rc < 0 )
{
failure_response(ALLOCATE, att);
return;
return ALLOCATE;
}
success_response(new_id, att);
return SUCCESS;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VMTemplateClone::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int source_id = xmlrpc_c::value_int(paramList.getInt(1));
string name = xmlrpc_c::value_string(paramList.getString(2));
bool recursive = false;
if (paramList.size() > 3)
{
recursive = xmlrpc_c::value_boolean(paramList.getBoolean(3));
}
int new_id;
VMTemplate * vmtmpl;
VMTemplatePool* tpool = static_cast<VMTemplatePool*>(pool);
ErrorCode ec;
ostringstream oss;
vector<VectorAttribute *> disks;
vector<int> new_img_ids;
vector<int>::iterator i;
RequestAttributes img_att(att);
img_att.resp_obj = PoolObjectSQL::IMAGE;
ec = clone(source_id, name, new_id, att);
if ( ec != SUCCESS )
{
failure_response(ec, att);
}
if (recursive)
{
Nebula& nd = Nebula::instance();
ImagePool* ipool = nd.get_ipool();
int img_id;
int new_img_id;
vmtmpl = tpool->get(new_id, true);
if (vmtmpl == 0)
{
att.resp_msg = object_name(PoolObjectSQL::TEMPLATE) +
" was cloned, but it was deleted before the disks could also be cloned.";
failure_response(ACTION, att);
return;
}
vmtmpl->get_disks(disks);
vmtmpl->unlock();
int ndisk = 0;
for (vector<VectorAttribute*>::iterator it = disks.begin(); it != disks.end(); it++)
{
if (ipool->get_image_id(*it, img_id, att.uid) == 0)
{
oss.str("");
oss << name << "-disk-" << ndisk;
ec = ImageClone::clone_img(img_id, oss.str(), -1, new_img_id, img_att);
if ( ec == SUCCESS)
{
ec = ImagePersistent::request_execute(new_img_id, true, img_att);
if (ec != SUCCESS)
{
NebulaLog::log("ReM", Log::ERROR, failure_message(ec, img_att));
ImageDelete::delete_img(img_id, img_att);
att.resp_msg = "Failure while making the cloned "
"images persistent. "+img_att.resp_msg;
goto error_images;
}
(*it)->remove("IMAGE");
(*it)->remove("IMAGE_UNAME");
(*it)->remove("IMAGE_UID");
(*it)->replace("IMAGE_ID", new_img_id);
new_img_ids.push_back(new_img_id);
}
else
{
NebulaLog::log("ReM", Log::ERROR, failure_message(ec, img_att));
att.resp_msg = "Failure while cloning the "
"template images. "+img_att.resp_msg;
goto error_images;
}
}
ndisk++;
}
vmtmpl = tpool->get(new_id, true);
if (vmtmpl == 0)
{
att.resp_msg = "The template was cloned, but it was deleted "
"before the disks could also be cloned.";
goto error_template;
}
vmtmpl->replace_disks(disks);
tpool->update(vmtmpl);
vmtmpl->unlock();
}
success_response(new_id, att);
return;
error_images:
ec = TemplateDelete::request_execute(new_id, false, att);
if (ec != SUCCESS)
{
NebulaLog::log("ReM", Log::ERROR, failure_message(ec, att));
}
goto error_template;
error_template:
for (i = new_img_ids.begin(); i != new_img_ids.end(); i++)
{
ec = ImageDelete::delete_img(*i, att);
if (ec != SUCCESS)
{
NebulaLog::log("ReM", Log::ERROR, failure_message(ec, img_att));
}
}
for (vector<VectorAttribute *>::iterator i = disks.begin() ;
i != disks.end() ; i++)
{
delete *i;
}
failure_response(ACTION, att);
return;
}
/* -------------------------------------------------------------------------- */

View File

@ -154,7 +154,33 @@ void TemplateDelete::request_execute(
int oid = xmlrpc_c::value_int(paramList.getInt(1));
bool recursive = false;
VMTemplate * object;
if (paramList.size() > 2)
{
recursive = xmlrpc_c::value_boolean(paramList.getBoolean(2));
}
ErrorCode ec = request_execute(oid, recursive, att);
if ( ec == SUCCESS )
{
success_response(oid, att);
}
else
{
failure_response(ec, att);
}
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
Request::ErrorCode TemplateDelete::request_execute(
int oid, bool recursive, RequestAttributes& att)
{
Nebula& nd = Nebula::instance();
AclManager * aclm = nd.get_aclm();
VMTemplatePool * pool = nd.get_tpool();
VMTemplate * object;
string error_msg;
set<int> error_ids;
@ -163,26 +189,19 @@ void TemplateDelete::request_execute(
vector<VectorAttribute *> disks;
if (paramList.size() > 2)
{
recursive = xmlrpc_c::value_boolean(paramList.getBoolean(2));
}
ec = delete_authorization(pool, oid, auth_op, att);
ec = delete_authorization(pool, oid, AuthRequest::MANAGE, att);
if ( ec != SUCCESS )
{
failure_response(ec, att);
return;
return ec;
}
object = static_cast<VMTemplatePool*>(pool)->get(oid, true);
object = pool->get(oid, true);
if ( object == 0 )
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
return NO_EXISTS;
}
int rc = pool->drop(object, error_msg);
@ -196,16 +215,14 @@ void TemplateDelete::request_execute(
if ( rc != 0 )
{
att.resp_msg = "Cannot delete " + object_name(auth_object) + ". " + error_msg;
failure_response(ACTION, att);
return;
att.resp_msg = "Cannot delete " + object_name(PoolObjectSQL::TEMPLATE) + ". " + error_msg;
return ACTION;
}
aclm->del_resource_rules(oid, auth_object);
aclm->del_resource_rules(oid, PoolObjectSQL::TEMPLATE);
if (recursive)
{
Nebula& nd = Nebula::instance();
ImagePool* ipool = nd.get_ipool();
ipool->get_image_ids(disks, img_ids, att.uid);
@ -214,7 +231,7 @@ void TemplateDelete::request_execute(
{
if ( ImageDelete::delete_img(*it, att) != SUCCESS )
{
NebulaLog::log("ReM", Log::ERROR, failure_message(ec, att));
NebulaLog::log("ReM", Log::ERROR, att.resp_msg);
error_ids.insert(*it);
rc = -1;
@ -234,13 +251,10 @@ void TemplateDelete::request_execute(
": " + one_util::join<set<int>::iterator>(error_ids.begin(),
error_ids.end(), ',');
failure_response(ACTION, att);
return;
return ACTION;
}
success_response(oid, att);
return;
return SUCCESS;
}
/* ------------------------------------------------------------------------- */

View File

@ -64,30 +64,56 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList,
{
int id = xmlrpc_c::value_int(paramList.getInt(1));
bool persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2));
ErrorCode ec = request_execute(id, persistent_flag, att);
if ( ec == SUCCESS )
{
success_response(id, att);
}
else
{
failure_response(ec, att);
}
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
Request::ErrorCode ImagePersistent::request_execute(
int id,
bool persistent_flag,
RequestAttributes& att)
{
int rc;
int ds_id;
int ds_persistent_only;
Nebula& nd = Nebula::instance();
ImagePool * ipool = nd.get_ipool();
DatastorePool * dspool = nd.get_dspool();
Datastore * ds;
Image * image;
if ( basic_authorization(id, att) == false )
ErrorCode ec;
ec = basic_authorization(ipool, id,
AuthRequest::MANAGE, PoolObjectSQL::IMAGE, att);
if ( ec != SUCCESS)
{
return;
return ec;
}
image = static_cast<Image *>(pool->get(id,true));
image = ipool->get(id,true);
if ( image == 0 )
{
att.resp_id = id;
failure_response(NO_EXISTS, att);
return;
return NO_EXISTS;
}
ds_id = image->get_ds_id();
@ -99,23 +125,21 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList,
if ( ds == 0 )
{
att.resp_msg = "Datastore no longer exists.";
failure_response(INTERNAL, att);
return;
return INTERNAL;
}
ds_persistent_only = ds->is_persistent_only();
ds->unlock();
image = static_cast<Image *>(pool->get(id,true));
image = ipool->get(id,true);
if ( image == 0 )
{
att.resp_id = id;
failure_response(NO_EXISTS, att);
return;
return NO_EXISTS;
}
switch (image->get_type())
@ -129,19 +153,19 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList,
case Image::RAMDISK:
case Image::CONTEXT:
att.resp_msg = "KERNEL, RAMDISK and CONTEXT must be non-persistent";
failure_response(ACTION, att);
image->unlock();
return;
return ACTION;
}
/* Check if datastore allows the operation */
if ( ds_persistent_only && persistent_flag == false )
{
att.resp_msg = "This Datastore only accepts persistent images.";
failure_response(INTERNAL, att);
image->unlock();
return;
return INTERNAL;
}
rc = image->persistent(persistent_flag, att.resp_msg);
@ -157,17 +181,16 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList,
att.resp_msg = "Could not make image non-persistent: " + att.resp_msg;
}
failure_response(INTERNAL, att);
image->unlock();
return;
return INTERNAL;
}
pool->update(image);
ipool->update(image);
image->unlock();
success_response(id, att);
return SUCCESS;
}
/* ------------------------------------------------------------------------- */
@ -261,8 +284,39 @@ void ImageClone::request_execute(
int clone_id = xmlrpc_c::value_int(paramList.getInt(1));
string name = xmlrpc_c::value_string(paramList.getString(2));
int new_id;
int ds_id = -1;
if (paramList.size() > 3)
{
ds_id = xmlrpc_c::value_int(paramList.getInt(3));
}
ErrorCode ec = clone_img(clone_id, name, ds_id, new_id, att);
if ( ec == SUCCESS )
{
success_response(new_id, att);
}
else
{
failure_response(ec, att);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Request::ErrorCode ImageClone::clone_img(
int clone_id,
const string& name,
int ds_id,
int &new_id,
RequestAttributes& att)
{
long long avail, size;
int rc, new_id, ds_id_orig, ds_id = -1;
int rc, ds_id_orig;
string ds_name, ds_data, ds_mad;
bool ds_check;
@ -277,12 +331,8 @@ void ImageClone::request_execute(
Nebula& nd = Nebula::instance();
DatastorePool * dspool = nd.get_dspool();
ImagePool * ipool = static_cast<ImagePool *>(pool);
ImagePool * ipool = nd.get_ipool();
if (paramList.size() > 3)
{
ds_id = xmlrpc_c::value_int(paramList.getInt(3));
}
// ------------------------- Get source Image info -------------------------
@ -291,8 +341,7 @@ void ImageClone::request_execute(
if ( img == 0 )
{
att.resp_id = clone_id;
failure_response(NO_EXISTS, att);
return;
return NO_EXISTS;
}
switch (img->get_type())
@ -306,9 +355,8 @@ void ImageClone::request_execute(
case Image::RAMDISK:
case Image::CONTEXT:
att.resp_msg = "KERNEL, RAMDISK and CONTEXT cannot be cloned.";
failure_response(ACTION, att);
img->unlock();
return;
return ACTION;
}
const Snapshots& snaps = img->get_snapshots();
@ -316,9 +364,8 @@ void ImageClone::request_execute(
if (snaps.size () > 0)
{
att.resp_msg = "Cannot clone images with snapshots";
failure_response(ACTION, att);
img->unlock();
return;
return ACTION;
}
tmpl = img->clone_template(name);
@ -344,21 +391,19 @@ void ImageClone::request_execute(
{
att.resp_obj = PoolObjectSQL::DATASTORE;
att.resp_id = ds_id;
failure_response(NO_EXISTS, att);
delete tmpl;
return;
return NO_EXISTS;
}
if ( ds->get_type() != Datastore::IMAGE_DS )
{
att.resp_msg = "Clone only supported for IMAGE_DS Datastores";
failure_response(ACTION, att);
ds->unlock();
delete tmpl;
return;
return ACTION;
}
ds->get_permissions(ds_perms);
@ -381,32 +426,29 @@ void ImageClone::request_execute(
{
att.resp_obj = PoolObjectSQL::DATASTORE;
att.resp_id = ds_id_orig;
failure_response(NO_EXISTS, att);
delete tmpl;
return;
return NO_EXISTS;
}
if (ds->get_type() != Datastore::IMAGE_DS)
{
att.resp_msg = "Clone only supported for IMAGE_DS Datastores";
failure_response(ACTION, att);
ds->unlock();
delete tmpl;
return;
return ACTION;
}
if (ds->get_ds_mad() != ds_mad)
{
att.resp_msg = "Clone only supported to same DS_MAD Datastores";
failure_response(ACTION, att);
ds->unlock();
delete tmpl;
return;
return ACTION;
}
ds->get_permissions(ds_perms_orig);
@ -422,10 +464,9 @@ void ImageClone::request_execute(
if (ds_check && (size > avail))
{
att.resp_msg = "Not enough space in datastore";
failure_response(ACTION, att);
delete tmpl;
return;
return ACTION;
}
if ( att.uid != 0 )
@ -437,7 +478,7 @@ void ImageClone::request_execute(
tmpl->to_xml(tmpl_str);
ar.add_create_auth(att.uid, att.gid, auth_object, tmpl_str); // CREATE IMAGE
ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::IMAGE, tmpl_str); // CREATE IMAGE
ar.add_auth(AuthRequest::USE, ds_perms); // USE DATASTORE
@ -449,18 +490,17 @@ void ImageClone::request_execute(
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
delete tmpl;
return;
return AUTHORIZATION;
}
// -------------------------- Check Quotas ----------------------------
if ( quota_authorization(&img_usage, Quotas::DATASTORE, att) == false )
if ( quota_authorization(&img_usage, Quotas::DATASTORE, att, att.resp_msg) == false )
{
delete tmpl;
return;
return AUTHORIZATION;
}
}
@ -483,8 +523,7 @@ void ImageClone::request_execute(
{
quota_rollback(&img_usage, Quotas::DATASTORE, att);
failure_response(ALLOCATE, att);
return;
return ALLOCATE;
}
ds = dspool->get(ds_id, true);
@ -498,7 +537,7 @@ void ImageClone::request_execute(
ds->unlock();
}
success_response(new_id, att);
return SUCCESS;
}
/* ------------------------------------------------------------------------- */