mirror of
https://github.com/OpenNebula/one.git
synced 2026-11-09 22:14:13 +09:00
3166 lines
81 KiB
C++
3166 lines
81 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2018, 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 "RequestManagerVirtualMachine.h"
|
|
#include "VirtualMachineDisk.h"
|
|
#include "PoolObjectAuth.h"
|
|
#include "Nebula.h"
|
|
#include "Quotas.h"
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool RequestManagerVirtualMachine::vm_authorization(
|
|
int oid,
|
|
ImageTemplate * tmpl,
|
|
VirtualMachineTemplate* vtmpl,
|
|
RequestAttributes& att,
|
|
PoolObjectAuth * host_perm,
|
|
PoolObjectAuth * ds_perm,
|
|
PoolObjectAuth * img_perm,
|
|
AuthRequest::Operation op)
|
|
{
|
|
PoolObjectSQL * object;
|
|
PoolObjectAuth vm_perms;
|
|
|
|
object = pool->get(oid);
|
|
|
|
if ( object == 0 )
|
|
{
|
|
att.resp_id = oid;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return false;
|
|
}
|
|
|
|
object->get_permissions(vm_perms);
|
|
|
|
object->unlock();
|
|
|
|
AuthRequest ar(att.uid, att.group_ids);
|
|
|
|
ar.add_auth(op, vm_perms);
|
|
|
|
if (host_perm != 0)
|
|
{
|
|
ar.add_auth(AuthRequest::MANAGE, *host_perm);
|
|
}
|
|
|
|
if (tmpl != 0)
|
|
{
|
|
string t_xml;
|
|
|
|
ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::IMAGE,
|
|
tmpl->to_xml(t_xml));
|
|
}
|
|
|
|
if ( vtmpl != 0 )
|
|
{
|
|
VirtualMachine::set_auth_request(att.uid, ar, vtmpl, true);
|
|
}
|
|
|
|
if ( ds_perm != 0 )
|
|
{
|
|
ar.add_auth(AuthRequest::USE, *ds_perm);
|
|
}
|
|
|
|
if ( img_perm != 0 )
|
|
{
|
|
ar.add_auth(AuthRequest::MANAGE, *img_perm);
|
|
}
|
|
|
|
if (UserPool::authorize(ar) == -1)
|
|
{
|
|
att.resp_msg = ar.message;
|
|
failure_response(AUTHORIZATION, att);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool RequestManagerVirtualMachine::quota_resize_authorization(
|
|
int oid,
|
|
Template * deltas,
|
|
RequestAttributes& att)
|
|
{
|
|
PoolObjectAuth vm_perms;
|
|
VirtualMachine * vm = Nebula::instance().get_vmpool()->get(oid);
|
|
|
|
if (vm == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::VM;
|
|
att.resp_id = oid;
|
|
failure_response(NO_EXISTS, att);
|
|
return false;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
return quota_resize_authorization(deltas, att, vm_perms);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool RequestManagerVirtualMachine::quota_resize_authorization(
|
|
Template * deltas,
|
|
RequestAttributes& att,
|
|
PoolObjectAuth& vm_perms)
|
|
{
|
|
int rc;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
UserPool* upool = nd.get_upool();
|
|
GroupPool* gpool = nd.get_gpool();
|
|
|
|
DefaultQuotas user_dquotas = nd.get_default_user_quota();
|
|
DefaultQuotas group_dquotas = nd.get_default_group_quota();
|
|
|
|
if (vm_perms.uid != UserPool::ONEADMIN_ID)
|
|
{
|
|
User * user = upool->get(vm_perms.uid);
|
|
|
|
if ( user != 0 )
|
|
{
|
|
rc = user->quota.quota_update(Quotas::VM, deltas, user_dquotas, att.resp_msg);
|
|
|
|
if (rc == false)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::USER) << " [" << vm_perms.uid << "] "
|
|
<< att.resp_msg;
|
|
|
|
att.resp_msg = oss.str();
|
|
|
|
failure_response(AUTHORIZATION, att);
|
|
|
|
user->unlock();
|
|
|
|
return false;
|
|
}
|
|
|
|
upool->update_quotas(user);
|
|
|
|
user->unlock();
|
|
}
|
|
}
|
|
|
|
if (vm_perms.gid != GroupPool::ONEADMIN_ID)
|
|
{
|
|
Group * group = gpool->get(vm_perms.gid);
|
|
|
|
if ( group != 0 )
|
|
{
|
|
rc = group->quota.quota_update(Quotas::VM, deltas, group_dquotas, att.resp_msg);
|
|
|
|
if (rc == false)
|
|
{
|
|
ostringstream oss;
|
|
RequestAttributes att_tmp(vm_perms.uid, -1, att);
|
|
|
|
oss << object_name(PoolObjectSQL::GROUP) << " [" << vm_perms.gid << "] "
|
|
<< att.resp_msg;
|
|
|
|
att.resp_msg = oss.str();
|
|
|
|
failure_response(AUTHORIZATION, att);
|
|
|
|
group->unlock();
|
|
|
|
quota_rollback(deltas, Quotas::VM, att_tmp);
|
|
|
|
return false;
|
|
}
|
|
|
|
gpool->update_quotas(group);
|
|
|
|
group->unlock();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::get_default_ds_information(
|
|
int cluster_id,
|
|
int& ds_id,
|
|
string& tm_mad,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ClusterPool* clpool = nd.get_clpool();
|
|
Cluster* cluster;
|
|
|
|
bool ds_migr;
|
|
|
|
ds_id = -1;
|
|
|
|
cluster = clpool->get(cluster_id);
|
|
|
|
if (cluster == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::CLUSTER;
|
|
att.resp_id = cluster_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
set<int> ds_ids = cluster->get_datastores();
|
|
|
|
cluster->unlock();
|
|
|
|
ds_id = Cluster::get_default_system_ds(ds_ids);
|
|
|
|
if (ds_id == -1)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id
|
|
<< "] does not have any " << object_name(PoolObjectSQL::DATASTORE)
|
|
<< " of type " << Datastore::type_to_str(Datastore::SYSTEM_DS)
|
|
<< ".";
|
|
|
|
att.resp_msg = oss.str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
set<int> ds_cluster_ids;
|
|
|
|
return get_ds_information(ds_id, ds_cluster_ids, tm_mad, att, ds_migr);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::get_ds_information(int ds_id,
|
|
set<int>& ds_cluster_ids,
|
|
string& tm_mad,
|
|
RequestAttributes& att,
|
|
bool& ds_migr)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
Datastore * ds = nd.get_dspool()->get(ds_id);
|
|
|
|
ds_cluster_ids.clear();
|
|
|
|
if ( ds == 0 )
|
|
{
|
|
att.resp_obj = PoolObjectSQL::DATASTORE;
|
|
att.resp_id = ds_id;
|
|
failure_response(NO_EXISTS, att);
|
|
return -1;
|
|
}
|
|
|
|
if ( ds->get_type() != Datastore::SYSTEM_DS )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Trying to use " << object_name(PoolObjectSQL::DATASTORE)
|
|
<< " [" << ds_id << "] to deploy the VM, but it is not of type"
|
|
<< " system datastore.";
|
|
|
|
att.resp_msg = oss.str();
|
|
|
|
failure_response(INTERNAL, att);
|
|
|
|
ds->unlock();
|
|
|
|
return -1;
|
|
}
|
|
|
|
ds_cluster_ids = ds->get_cluster_ids();
|
|
|
|
tm_mad = ds->get_tm_mad();
|
|
|
|
ds->get_template_attribute("DS_MIGRATE", ds_migr);
|
|
|
|
ds->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::get_host_information(
|
|
int hid,
|
|
string& name,
|
|
string& vmm,
|
|
int& cluster_id,
|
|
bool& is_public_cloud,
|
|
PoolObjectAuth& host_perms,
|
|
RequestAttributes& att)
|
|
|
|
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
HostPool * hpool = nd.get_hpool();
|
|
|
|
Host * host = hpool->get(hid);
|
|
|
|
if ( host == 0 )
|
|
{
|
|
att.resp_obj = PoolObjectSQL::HOST;
|
|
att.resp_id = hid;
|
|
failure_response(NO_EXISTS, att);
|
|
return -1;
|
|
}
|
|
|
|
if ( host->get_state() == Host::OFFLINE )
|
|
{
|
|
att.resp_msg = "Host is offline, cannot use it to deploy VM";
|
|
failure_response(ACTION, att);
|
|
|
|
host->unlock();
|
|
|
|
return -1;
|
|
}
|
|
|
|
name = host->get_name();
|
|
vmm = host->get_vmm_mad();
|
|
|
|
cluster_id = host->get_cluster_id();
|
|
|
|
is_public_cloud = host->is_public_cloud();
|
|
|
|
host->get_permissions(host_perms);
|
|
|
|
host->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool RequestManagerVirtualMachine::check_host(
|
|
int hid, bool enforce, VirtualMachine* vm, string& error)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
HostPool * hpool = nd.get_hpool();
|
|
|
|
Host * host;
|
|
bool test;
|
|
string capacity_error;
|
|
|
|
int cpu, mem, disk;
|
|
vector<VectorAttribute *> pci;
|
|
|
|
vm->get_requirements(cpu, mem, disk, pci);
|
|
|
|
host = hpool->get(hid);
|
|
|
|
if (host == 0)
|
|
{
|
|
error = "Host no longer exists";
|
|
return false;
|
|
}
|
|
|
|
if (enforce)
|
|
{
|
|
test = host->test_capacity(cpu, mem, disk, pci, capacity_error);
|
|
}
|
|
else
|
|
{
|
|
test = host->test_capacity(pci, capacity_error);
|
|
}
|
|
|
|
if (!test)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::VM) << " [" << vm->get_oid()
|
|
<< "] does not fit in " << object_name(PoolObjectSQL::HOST) << " ["
|
|
<< hid << "]. " << capacity_error;
|
|
|
|
error = oss.str();
|
|
}
|
|
|
|
host->unlock();
|
|
|
|
return test;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VirtualMachine * RequestManagerVirtualMachine::get_vm(int id,
|
|
RequestAttributes& att)
|
|
{
|
|
VirtualMachine * vm;
|
|
|
|
vm = static_cast<VirtualMachine *>(pool->get(id));
|
|
|
|
if ( vm == 0 )
|
|
{
|
|
att.resp_id = id;
|
|
failure_response(NO_EXISTS, att);
|
|
return 0;
|
|
}
|
|
|
|
return vm;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::add_history(VirtualMachine * vm,
|
|
int hid,
|
|
int cid,
|
|
const string& hostname,
|
|
const string& vmm_mad,
|
|
const string& tm_mad,
|
|
int ds_id,
|
|
RequestAttributes& att)
|
|
{
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
|
|
vm->add_history(hid, cid, hostname, vmm_mad, tm_mad, ds_id);
|
|
|
|
if ( vmpool->update_history(vm) != 0 )
|
|
{
|
|
att.resp_msg = "Cannot update virtual machine history";
|
|
failure_response(INTERNAL, att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if ( vmpool->update(vm) != 0 )
|
|
{
|
|
att.resp_msg = "Cannot update virtual machine";
|
|
failure_response(INTERNAL, att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
string action_st = xmlrpc_c::value_string(paramList.getString(1));
|
|
int id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
int rc;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
ostringstream oss;
|
|
string error;
|
|
|
|
AuthRequest::Operation op;
|
|
History::VMAction action;
|
|
|
|
VirtualMachine * vm;
|
|
|
|
// Compatibility with 4.x
|
|
if (action_st == "shutdown-hard" || action_st == "delete" )
|
|
{
|
|
action_st = "terminate-hard";
|
|
}
|
|
else if (action_st == "shutdown")
|
|
{
|
|
action_st = "terminate";
|
|
}
|
|
|
|
History::action_from_str(action_st, action);
|
|
|
|
op = nd.get_vm_auth_op(action);
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->is_imported() && !vm->is_imported_action_supported(action))
|
|
{
|
|
att.resp_msg = "Action \"" + action_st + "\" is not supported for "
|
|
"imported VMs";
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (vm->is_vrouter() && !VirtualRouter::is_action_supported(action))
|
|
{
|
|
att.resp_msg = "Action \"" + action_st + "\" is not supported for "
|
|
"virtual router VMs";
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
switch (action)
|
|
{
|
|
case History::TERMINATE_ACTION:
|
|
rc = dm->terminate(id, false, att, error);
|
|
break;
|
|
case History::TERMINATE_HARD_ACTION:
|
|
rc = dm->terminate(id, true, att, error);
|
|
break;
|
|
case History::HOLD_ACTION:
|
|
rc = dm->hold(id, att, error);
|
|
break;
|
|
case History::RELEASE_ACTION:
|
|
rc = dm->release(id, att, error);
|
|
break;
|
|
case History::STOP_ACTION:
|
|
rc = dm->stop(id, att, error);
|
|
break;
|
|
case History::SUSPEND_ACTION:
|
|
rc = dm->suspend(id, att, error);
|
|
break;
|
|
case History::RESUME_ACTION:
|
|
rc = dm->resume(id, att, error);
|
|
break;
|
|
case History::REBOOT_ACTION:
|
|
rc = dm->reboot(id, false, att, error);
|
|
break;
|
|
case History::REBOOT_HARD_ACTION:
|
|
rc = dm->reboot(id, true, att, error);
|
|
break;
|
|
case History::RESCHED_ACTION:
|
|
rc = dm->resched(id, true, att, error);
|
|
break;
|
|
case History::UNRESCHED_ACTION:
|
|
rc = dm->resched(id, false, att, error);
|
|
break;
|
|
case History::POWEROFF_ACTION:
|
|
rc = dm->poweroff(id, false, att, error);
|
|
break;
|
|
case History::POWEROFF_HARD_ACTION:
|
|
rc = dm->poweroff(id, true, att, error);
|
|
break;
|
|
case History::UNDEPLOY_ACTION:
|
|
rc = dm->undeploy(id, false, att, error);
|
|
break;
|
|
case History::UNDEPLOY_HARD_ACTION:
|
|
rc = dm->undeploy(id, true, att, error);
|
|
break;
|
|
default:
|
|
rc = -3;
|
|
break;
|
|
}
|
|
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
success_response(id, att);
|
|
break;
|
|
|
|
case -1:
|
|
att.resp_id = id;
|
|
failure_response(NO_EXISTS, att);
|
|
break;
|
|
|
|
case -2:
|
|
oss << "Error performing action \"" << action_st << "\": " << error;
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
break;
|
|
|
|
case -3:
|
|
oss << "Action \"" << action_st << "\" is not supported";
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
break;
|
|
|
|
default:
|
|
att.resp_msg = "Internal error. Action result not defined";
|
|
failure_response(INTERNAL, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* Adds extra info to the volatile disks of the given template, ds inherited
|
|
* attributes and TYPE
|
|
* @param ds_id datastore id
|
|
* @param vd vector of DISKS
|
|
* @return true if there at least one volatile disk was found
|
|
*/
|
|
static bool set_volatile_disk_info(VirtualMachine *vm, int ds_id)
|
|
{
|
|
VirtualMachineDisks& disks = vm->get_disks();
|
|
|
|
bool found = disks.volatile_info(ds_id);
|
|
|
|
if ( found )
|
|
{
|
|
Nebula::instance().get_vmpool()->update(vm);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
static bool set_volatile_disk_info(VirtualMachine *vm, int ds_id, Template& tmpl)
|
|
{
|
|
VirtualMachineDisks disks(&tmpl, false);
|
|
|
|
bool found = disks.volatile_info(ds_id);
|
|
|
|
if ( found )
|
|
{
|
|
Nebula::instance().get_vmpool()->update(vm);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int set_vnc_port(VirtualMachine *vm, int cluster_id, RequestAttributes& att)
|
|
{
|
|
ClusterPool * cpool = Nebula::instance().get_clpool();
|
|
|
|
VectorAttribute * graphics = vm->get_template_attribute("GRAPHICS");
|
|
|
|
unsigned int port;
|
|
int rc;
|
|
|
|
if (graphics == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (vm->hasHistory() && vm->get_action()==History::STOP_ACTION)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (graphics->vector_value("PORT", port) == 0)
|
|
{
|
|
rc = cpool->set_vnc_port(cluster_id, port);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
att.resp_msg = "Requested VNC port already assgined to a VM";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = cpool->get_vnc_port(cluster_id, vm->get_oid(), port);
|
|
|
|
if ( rc == 0 )
|
|
{
|
|
graphics->replace("PORT", port);
|
|
|
|
Nebula::instance().get_vmpool()->update(vm);
|
|
}
|
|
else
|
|
{
|
|
att.resp_msg = "No free VNC ports available in the cluster";
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
DatastorePool * dspool = nd.get_dspool();
|
|
|
|
VirtualMachine * vm;
|
|
|
|
string hostname;
|
|
string vmm_mad;
|
|
int cluster_id;
|
|
bool is_public_cloud;
|
|
|
|
PoolObjectAuth host_perms, ds_perms;
|
|
PoolObjectAuth * auth_ds_perms;
|
|
|
|
string tm_mad;
|
|
|
|
bool auth = false;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get request parameters and information about the target host
|
|
// ------------------------------------------------------------------------
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int hid = xmlrpc_c::value_int(paramList.getInt(2));
|
|
bool enforce = false;
|
|
int ds_id = -1;
|
|
|
|
if ( paramList.size() > 3 )
|
|
{
|
|
enforce = xmlrpc_c::value_boolean(paramList.getBoolean(3));
|
|
}
|
|
|
|
if ( paramList.size() > 4 )
|
|
{
|
|
ds_id = xmlrpc_c::value_int(paramList.getInt(4));
|
|
}
|
|
|
|
if (get_host_information(hid,
|
|
hostname,
|
|
vmm_mad,
|
|
cluster_id,
|
|
is_public_cloud,
|
|
host_perms,
|
|
att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get information about the system DS to use (tm_mad & permissions)
|
|
// ------------------------------------------------------------------------
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->hasHistory() &&
|
|
(vm->get_action() == History::STOP_ACTION ||
|
|
vm->get_action() == History::UNDEPLOY_ACTION ||
|
|
vm->get_action() == History::UNDEPLOY_HARD_ACTION))
|
|
{
|
|
ds_id = vm->get_ds_id();
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
if (is_public_cloud) // Set ds_id to -1 and tm_mad empty(). This is used by
|
|
{ // by VirtualMachine::get_host_is_cloud()
|
|
ds_id = -1;
|
|
tm_mad = "";
|
|
}
|
|
else
|
|
{
|
|
if ( ds_id == -1 ) //Use default system DS for cluster
|
|
{
|
|
if (get_default_ds_information(cluster_id, ds_id, tm_mad, att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else //Get information from user selected system DS
|
|
{
|
|
set<int> ds_cluster_ids;
|
|
bool ds_migr;
|
|
|
|
if (get_ds_information(ds_id,ds_cluster_ids,tm_mad,att,ds_migr) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ds_cluster_ids.count(cluster_id) == 0)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::DATASTORE) << " [" << ds_id
|
|
<< "] and " << object_name(PoolObjectSQL::HOST) << " ["
|
|
<< hid << "] are not in the same "
|
|
<< object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id
|
|
<< "].";
|
|
|
|
att.resp_msg = oss.str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ds_id == -1)
|
|
{
|
|
auth_ds_perms = 0;
|
|
}
|
|
else
|
|
{
|
|
Datastore * ds = dspool->get(ds_id);
|
|
|
|
if (ds == 0 )
|
|
{
|
|
att.resp_obj = PoolObjectSQL::DATASTORE;
|
|
att.resp_id = ds_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return;
|
|
}
|
|
|
|
ds->get_permissions(ds_perms);
|
|
|
|
ds->unlock();
|
|
|
|
auth_ds_perms = &ds_perms;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Authorize request
|
|
// ------------------------------------------------------------------------
|
|
|
|
auth = vm_authorization(id, 0, 0, att, &host_perms, auth_ds_perms, 0, auth_op);
|
|
|
|
if (auth == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check request consistency:
|
|
// - VM States are right
|
|
// - Host capacity if required
|
|
// ------------------------------------------------------------------------
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->get_state() != VirtualMachine::PENDING &&
|
|
vm->get_state() != VirtualMachine::HOLD &&
|
|
vm->get_state() != VirtualMachine::STOPPED &&
|
|
vm->get_state() != VirtualMachine::UNDEPLOYED)
|
|
{
|
|
att.resp_msg = "Deploy action is not available for state " +
|
|
vm->state_str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (check_host(hid, enforce, vm, att.resp_msg) == false)
|
|
{
|
|
vm->unlock();
|
|
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Add deployment dependent attributes to VM
|
|
// - volatile disk (selected system DS driver)
|
|
// - vnc port (free in the selected cluster)
|
|
// ------------------------------------------------------------------------
|
|
set_volatile_disk_info(vm, ds_id);
|
|
|
|
if (set_vnc_port(vm, cluster_id, att) != 0)
|
|
{
|
|
failure_response(ACTION, att);
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Add a new history record
|
|
// ------------------------------------------------------------------------
|
|
if (add_history(vm,
|
|
hid,
|
|
cluster_id,
|
|
hostname,
|
|
vmm_mad,
|
|
tm_mad,
|
|
ds_id,
|
|
att) != 0)
|
|
{
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// deploy the VM
|
|
// ------------------------------------------------------------------------
|
|
|
|
if (vm->is_imported())
|
|
{
|
|
dm->import(vm, att);
|
|
}
|
|
else
|
|
{
|
|
dm->deploy(vm, att);
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
success_response(id, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
DatastorePool * dspool = nd.get_dspool();
|
|
|
|
VirtualMachinePool * vmpool = nd.get_vmpool();
|
|
VirtualMachine * vm;
|
|
|
|
string hostname;
|
|
string vmm_mad;
|
|
int cluster_id;
|
|
set<int> ds_cluster_ids;
|
|
bool is_public_cloud;
|
|
PoolObjectAuth host_perms, ds_perms;
|
|
PoolObjectAuth * auth_ds_perms;
|
|
|
|
int c_hid;
|
|
int c_ds_id;
|
|
string c_tm_mad, tm_mad;
|
|
bool c_is_public_cloud;
|
|
|
|
set<int> cluster_ids;
|
|
string error_str;
|
|
|
|
bool auth = false;
|
|
bool ds_migr;
|
|
|
|
string error;
|
|
|
|
History::VMAction action;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get request parameters and information about the target host
|
|
// ------------------------------------------------------------------------
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int hid = xmlrpc_c::value_int(paramList.getInt(2));
|
|
bool live = xmlrpc_c::value_boolean(paramList.getBoolean(3));
|
|
bool enforce = false;
|
|
int ds_id = -1;
|
|
|
|
if ( paramList.size() > 4 )
|
|
{
|
|
enforce = xmlrpc_c::value_boolean(paramList.getBoolean(4));
|
|
}
|
|
|
|
if ( paramList.size() > 5 )
|
|
{
|
|
ds_id = xmlrpc_c::value_int(paramList.getInt(5));
|
|
}
|
|
|
|
if (get_host_information(hid,
|
|
hostname,
|
|
vmm_mad,
|
|
cluster_id,
|
|
is_public_cloud,
|
|
host_perms,
|
|
att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ds_id == -1)
|
|
{
|
|
auth_ds_perms = 0;
|
|
}
|
|
else
|
|
{
|
|
Datastore * ds = dspool->get(ds_id);
|
|
|
|
if (ds == 0 )
|
|
{
|
|
att.resp_obj = PoolObjectSQL::DATASTORE;
|
|
att.resp_id = ds_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return;
|
|
}
|
|
|
|
ds->get_permissions(ds_perms);
|
|
|
|
ds->unlock();
|
|
|
|
auth_ds_perms = &ds_perms;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Authorize request
|
|
// ------------------------------------------------------------------------
|
|
|
|
auth = vm_authorization(id, 0, 0, att, &host_perms, auth_ds_perms, 0, auth_op);
|
|
|
|
if (auth == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check request consistency:
|
|
// - VM States are right and there is at least a history record
|
|
// - New host is not the current one
|
|
// - Host capacity if required
|
|
// - New host and current one are in the same cluster
|
|
// - New or old host are not public cloud
|
|
// ------------------------------------------------------------------------
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( vm->is_previous_history_open() ||
|
|
(vm->get_state() != VirtualMachine::POWEROFF &&
|
|
vm->get_state() != VirtualMachine::SUSPENDED &&
|
|
(vm->get_state() != VirtualMachine::ACTIVE ||
|
|
(vm->get_lcm_state() != VirtualMachine::RUNNING &&
|
|
vm->get_lcm_state() != VirtualMachine::UNKNOWN))))
|
|
{
|
|
att.resp_msg = "Migrate action is not available for state " + vm->state_str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (live)
|
|
{
|
|
action = History::LIVE_MIGRATE_ACTION;
|
|
}
|
|
else
|
|
{
|
|
action = History::MIGRATE_ACTION;
|
|
}
|
|
|
|
if (vm->is_imported() && !vm->is_imported_action_supported(action))
|
|
{
|
|
att.resp_msg = "Migration is not supported for imported VMs";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (vm->is_vrouter() && !VirtualRouter::is_action_supported(action))
|
|
{
|
|
att.resp_msg = "Migration is not supported for virtual router VMs";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// Get System DS information from current History record
|
|
c_ds_id = vm->get_ds_id();
|
|
c_tm_mad = vm->get_tm_mad();
|
|
|
|
// Check we are not migrating to the same host and the same system DS
|
|
c_hid = vm->get_hid();
|
|
|
|
if (c_hid == hid && (ds_id == -1 || ds_id == c_ds_id))
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "VM is already running on " << object_name(PoolObjectSQL::HOST)
|
|
<< " [" << c_hid << "]";
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// Check the host has enough capacity
|
|
if (check_host(hid, enforce, vm, att.resp_msg) == false)
|
|
{
|
|
vm->unlock();
|
|
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
int rc = vm->automatic_requirements(cluster_ids, error_str);
|
|
|
|
vmpool->update(vm);
|
|
|
|
if (rc != 0)
|
|
{
|
|
vm->unlock();
|
|
|
|
att.resp_msg = error_str;
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
// Check we are migrating to a compatible cluster
|
|
Host * host = nd.get_hpool()->get(c_hid);
|
|
|
|
if (host == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::HOST;
|
|
att.resp_id = c_hid;
|
|
failure_response(NO_EXISTS, att);
|
|
}
|
|
|
|
c_is_public_cloud = host->is_public_cloud();
|
|
|
|
host->unlock();
|
|
|
|
if (!cluster_ids.empty() && cluster_ids.count(cluster_id) == 0)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Cannot migrate to host [" << hid << "]. Host is in cluster ["
|
|
<< cluster_id << "], and VM requires to be placed on cluster ["
|
|
<< one_util::join(cluster_ids, ',') << "]";
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( is_public_cloud || c_is_public_cloud )
|
|
{
|
|
att.resp_msg = "Cannot migrate to or from a Public Cloud Host";
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
|
|
if (ds_id != -1)
|
|
{
|
|
if ( c_ds_id != ds_id && live )
|
|
{
|
|
att.resp_msg = "A migration to a different system datastore "
|
|
"cannot be performed live.";
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
if (get_ds_information(ds_id, ds_cluster_ids, tm_mad, att, ds_migr) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!ds_migr)
|
|
{
|
|
att.resp_msg = "System datastore migration not supported by TM driver";
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
if (c_tm_mad != tm_mad)
|
|
{
|
|
att.resp_msg = "Cannot migrate to a system datastore with a different TM driver";
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ds_id = c_ds_id;
|
|
|
|
if (get_ds_information(ds_id, ds_cluster_ids, tm_mad, att, ds_migr) != 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!ds_cluster_ids.empty() && ds_cluster_ids.count(cluster_id) == 0)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Cannot migrate to host [" << hid << "] and system datastore [" << ds_id << "]. Host is in cluster ["
|
|
<< cluster_id << "], and the datastore is in cluster ["
|
|
<< one_util::join(ds_cluster_ids, ',') << "]";
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Add a new history record and update volatile DISK attributes
|
|
// ------------------------------------------------------------------------
|
|
|
|
if ( (vm = get_vm(id, att)) == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
set_volatile_disk_info(vm, ds_id);
|
|
|
|
if (add_history(vm,
|
|
hid,
|
|
cluster_id,
|
|
hostname,
|
|
vmm_mad,
|
|
tm_mad,
|
|
ds_id,
|
|
att) != 0)
|
|
{
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Migrate the VM
|
|
// ------------------------------------------------------------------------
|
|
|
|
if (live == true && vm->get_lcm_state() == VirtualMachine::RUNNING )
|
|
{
|
|
dm->live_migrate(vm, att);
|
|
}
|
|
else
|
|
{
|
|
dm->migrate(vm, att);
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
success_response(id, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDiskSaveas::request_execute(
|
|
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ImagePool * ipool = nd.get_ipool();
|
|
DatastorePool * dspool = nd.get_dspool();
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int disk_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
string img_name = xmlrpc_c::value_string(paramList.getString(3));
|
|
string img_type = xmlrpc_c::value_string(paramList.getString(4));
|
|
int snap_id = xmlrpc_c::value_int(paramList.getInt(5));
|
|
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
|
|
VirtualMachine * vm;
|
|
Datastore * ds;
|
|
Image * img;
|
|
int iid;
|
|
int iid_orig;
|
|
|
|
string ds_data;
|
|
PoolObjectAuth ds_perms;
|
|
long long avail;
|
|
bool ds_check;
|
|
|
|
string ds_mad;
|
|
string tm_mad;
|
|
|
|
string driver;
|
|
string target;
|
|
string dev_prefix;
|
|
|
|
int ds_id;
|
|
string ds_name;
|
|
long long size;
|
|
|
|
string iname_orig;
|
|
string iuname_orig;
|
|
|
|
Image::ImageType type;
|
|
Image::DiskType ds_disk_type;
|
|
|
|
ImageTemplate * itemplate;
|
|
Template img_usage;
|
|
|
|
int rc;
|
|
bool rc_auth;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Prepare and check the VM/DISK to be saved as
|
|
// -------------------------------------------------------------------------
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->set_saveas_state() != 0)
|
|
{
|
|
goto error_state;
|
|
}
|
|
|
|
rc = vm->set_saveas_disk(disk_id, snap_id, iid_orig, size, att.resp_msg);
|
|
|
|
if (rc == -1)
|
|
{
|
|
goto error_disk;
|
|
}
|
|
|
|
vmpool->update(vm);
|
|
|
|
vm->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the data of the Image to be saved
|
|
// -------------------------------------------------------------------------
|
|
img = ipool->get(iid_orig);
|
|
|
|
if ( img == 0 )
|
|
{
|
|
goto error_image;
|
|
}
|
|
|
|
ds_id = img->get_ds_id();
|
|
ds_name = img->get_ds_name();
|
|
|
|
type = img->get_type();
|
|
|
|
iname_orig = img->get_name();
|
|
iuname_orig = img->get_uname();
|
|
|
|
img->get_template_attribute("DRIVER", driver);
|
|
img->get_template_attribute("TARGET", target);
|
|
img->get_template_attribute("DEV_PREFIX", dev_prefix);
|
|
|
|
img->unlock();
|
|
|
|
switch (type)
|
|
{
|
|
case Image::OS:
|
|
case Image::DATABLOCK:
|
|
case Image::CDROM:
|
|
break;
|
|
|
|
case Image::KERNEL:
|
|
case Image::RAMDISK:
|
|
case Image::CONTEXT:
|
|
goto error_image_type;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the data of the DataStore for the new image & size
|
|
// -------------------------------------------------------------------------
|
|
if ((ds = dspool->get(ds_id)) == 0 )
|
|
{
|
|
goto error_ds;
|
|
}
|
|
|
|
ds->get_permissions(ds_perms);
|
|
ds->to_xml(ds_data);
|
|
|
|
ds_check = ds->get_avail_mb(avail);
|
|
ds_disk_type = ds->get_disk_type();
|
|
ds_mad = ds->get_ds_mad();
|
|
ds_mad = ds->get_tm_mad();
|
|
|
|
ds->unlock();
|
|
|
|
if (ds_check && (size > avail))
|
|
{
|
|
goto error_size;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Create a template for the new Image
|
|
// -------------------------------------------------------------------------
|
|
itemplate = new ImageTemplate;
|
|
|
|
itemplate->add("NAME", img_name);
|
|
itemplate->add("SIZE", size);
|
|
|
|
itemplate->add("SAVED_IMAGE_ID",iid_orig);
|
|
itemplate->add("SAVED_DISK_ID",disk_id);
|
|
itemplate->add("SAVED_VM_ID", id);
|
|
itemplate->set_saving();
|
|
|
|
if (img_type.empty())
|
|
{
|
|
itemplate->add("TYPE", Image::type_to_str(type));
|
|
}
|
|
else
|
|
{
|
|
itemplate->add("TYPE", img_type);
|
|
}
|
|
|
|
if (!driver.empty())
|
|
{
|
|
itemplate->add("DRIVER", driver);
|
|
}
|
|
|
|
if (!target.empty())
|
|
{
|
|
itemplate->add("TARGET", target);
|
|
}
|
|
|
|
if (!dev_prefix.empty())
|
|
{
|
|
itemplate->add("DEV_PREFIX", dev_prefix);
|
|
}
|
|
|
|
Image::test_set_persistent(itemplate, att.uid, att.gid, false);
|
|
|
|
img_usage.add("SIZE", size);
|
|
img_usage.add("DATASTORE", ds_id);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation & check quotas
|
|
// -------------------------------------------------------------------------
|
|
rc_auth = vm_authorization(id, itemplate, 0, att, 0,&ds_perms,0,auth_op);
|
|
|
|
if ( rc_auth == true )
|
|
{
|
|
rc_auth = quota_authorization(&img_usage, Quotas::DATASTORE, att);
|
|
}
|
|
|
|
if ( rc_auth == false)
|
|
{
|
|
goto error_auth;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Create the image
|
|
// -------------------------------------------------------------------------
|
|
rc = ipool->allocate(att.uid,
|
|
att.gid,
|
|
att.uname,
|
|
att.gname,
|
|
att.umask,
|
|
itemplate,
|
|
ds_id,
|
|
ds_name,
|
|
ds_disk_type,
|
|
ds_data,
|
|
Datastore::IMAGE_DS,
|
|
ds_mad,
|
|
tm_mad,
|
|
"",
|
|
-1,
|
|
&iid,
|
|
att.resp_msg);
|
|
if (rc < 0)
|
|
{
|
|
goto error_allocate;
|
|
}
|
|
|
|
ds = dspool->get(ds_id);
|
|
|
|
if (ds == 0)
|
|
{
|
|
goto error_ds_removed;
|
|
}
|
|
|
|
ds->add_image(iid);
|
|
|
|
dspool->update(ds);
|
|
|
|
ds->unlock();
|
|
|
|
success_response(iid, att);
|
|
|
|
return;
|
|
|
|
error_state:
|
|
vm->unlock();
|
|
|
|
att.resp_msg = "VM has to be RUNNING, POWEROFF or SUSPENDED to save disks.";
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
|
|
error_disk:
|
|
vm->clear_saveas_state();
|
|
|
|
vm->clear_saveas_disk();
|
|
|
|
vm->unlock();
|
|
att.resp_msg ="Cannot use DISK. " + att.resp_msg;
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
|
|
error_image:
|
|
att.resp_obj = PoolObjectSQL::IMAGE;
|
|
att.resp_id = iid_orig;
|
|
failure_response(NO_EXISTS, att);
|
|
goto error_common;
|
|
|
|
error_image_type:
|
|
att.resp_msg = "Cannot save_as image of type " + Image::type_to_str(type);
|
|
failure_response(INTERNAL, att);
|
|
goto error_common;
|
|
|
|
error_ds:
|
|
error_ds_removed:
|
|
att.resp_obj = PoolObjectSQL::DATASTORE;
|
|
att.resp_id = ds_id;
|
|
failure_response(NO_EXISTS, att);
|
|
goto error_common;
|
|
|
|
error_size:
|
|
att.resp_msg = "Not enough space in datastore";
|
|
failure_response(ACTION, att);
|
|
goto error_common;
|
|
|
|
error_auth:
|
|
delete itemplate;
|
|
goto error_common;
|
|
|
|
error_allocate:
|
|
att.resp_obj = PoolObjectSQL::IMAGE;
|
|
quota_rollback(&img_usage, Quotas::DATASTORE, att);
|
|
failure_response(ALLOCATE, att);
|
|
goto error_common;
|
|
|
|
error_common:
|
|
if ((vm = vmpool->get(id)) != 0)
|
|
{
|
|
vm->clear_saveas_state();
|
|
|
|
vm->clear_saveas_disk();
|
|
|
|
vmpool->update(vm);
|
|
|
|
vm->unlock();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineMonitoring::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int rc;
|
|
|
|
ostringstream oss;
|
|
|
|
bool auth = vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op);
|
|
|
|
if ( auth == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = (static_cast<VirtualMachinePool *>(pool))->dump_monitoring(oss, id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
att.resp_msg = "Internal error";
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
success_response(oss.str(), att);
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
VirtualMachineTemplate tmpl;
|
|
PoolObjectAuth vm_perms;
|
|
|
|
VirtualMachine * vm;
|
|
|
|
int rc;
|
|
bool volatile_disk;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse Disk template
|
|
// -------------------------------------------------------------------------
|
|
|
|
rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation & check quotas
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, &tmpl, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
if ( !vm->hasHistory() )
|
|
{
|
|
att.resp_msg = "VM is not running in any host";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
volatile_disk = set_volatile_disk_info(vm, vm->get_ds_id(), tmpl);
|
|
|
|
if (vm->is_vrouter() &&
|
|
!VirtualRouter::is_action_supported(History::DISK_ATTACH_ACTION))
|
|
{
|
|
att.resp_msg = "Action is not supported for virtual router VMs";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
VirtualMachineTemplate deltas(tmpl);
|
|
VirtualMachineDisks::extended_info(att.uid, &deltas);
|
|
|
|
deltas.add("VMS", 0);
|
|
|
|
if (quota_resize_authorization(id, &deltas, att_quota) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (volatile_disk == false)
|
|
{
|
|
if ( quota_authorization(&tmpl, Quotas::IMAGE, att_quota) == false )
|
|
{
|
|
quota_rollback(&deltas, Quotas::VM, att_quota);
|
|
return;
|
|
}
|
|
}
|
|
|
|
rc = dm->attach(id, &tmpl, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
quota_rollback(&deltas, Quotas::VM, att_quota);
|
|
|
|
if (volatile_disk == false)
|
|
{
|
|
quota_rollback(&tmpl, Quotas::IMAGE, att_quota);
|
|
}
|
|
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
VirtualMachine * vm;
|
|
|
|
int rc;
|
|
string error_str;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int disk_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->is_vrouter() && !VirtualRouter::is_action_supported(History::NIC_DETACH_ACTION))
|
|
{
|
|
att.resp_msg = "Action is not supported for virtual router VMs";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
rc = dm->detach(id, disk_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
|
bool enforce_param = xmlrpc_c::value_boolean(paramList.getBoolean(3));
|
|
|
|
float ncpu, ocpu, dcpu;
|
|
int nmemory, omemory, dmemory;
|
|
int nvcpu, ovcpu;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
HostPool * hpool = nd.get_hpool();
|
|
Host * host;
|
|
|
|
Template deltas;
|
|
bool rc;
|
|
int ret;
|
|
int hid = -1;
|
|
|
|
PoolObjectAuth vm_perms;
|
|
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
VirtualMachine * vm;
|
|
VirtualMachineTemplate tmpl;
|
|
|
|
bool enforce = true;
|
|
|
|
if (att.is_admin())
|
|
{
|
|
enforce = enforce_param;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse template
|
|
// -------------------------------------------------------------------------
|
|
rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Authorize the operation & restricted attributes */
|
|
/* ---------------------------------------------------------------------- */
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!att.is_admin())
|
|
{
|
|
string aname;
|
|
|
|
if (tmpl.check_restricted(aname))
|
|
{
|
|
att.resp_msg = "Template includes a restricted attribute " + aname;
|
|
failure_response(AUTHORIZATION, att);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the resize values */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
tmpl.get("CPU", ncpu);
|
|
tmpl.get("VCPU", nvcpu);
|
|
tmpl.get("MEMORY", nmemory);
|
|
|
|
vm = vmpool->get(id);
|
|
|
|
if (vm == 0)
|
|
{
|
|
att.resp_id = id;
|
|
failure_response(NO_EXISTS, att);
|
|
return;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->get_template_attribute("MEMORY", omemory);
|
|
vm->get_template_attribute("CPU", ocpu);
|
|
vm->get_template_attribute("VCPU", ovcpu);
|
|
|
|
if (nmemory == 0)
|
|
{
|
|
nmemory = omemory;
|
|
}
|
|
|
|
if (ncpu == 0)
|
|
{
|
|
ncpu = ocpu;
|
|
}
|
|
|
|
if (nvcpu == 0)
|
|
{
|
|
nvcpu = ovcpu;
|
|
}
|
|
|
|
dcpu = ncpu - ocpu;
|
|
dmemory = nmemory - omemory;
|
|
|
|
deltas.add("MEMORY", dmemory);
|
|
deltas.add("CPU", dcpu);
|
|
deltas.add("VMS", 0);
|
|
|
|
switch (vm->get_state())
|
|
{
|
|
case VirtualMachine::POWEROFF: //Only check host capacity in POWEROFF
|
|
if (vm->hasHistory() == true)
|
|
{
|
|
hid = vm->get_hid();
|
|
}
|
|
break;
|
|
|
|
case VirtualMachine::INIT:
|
|
case VirtualMachine::PENDING:
|
|
case VirtualMachine::HOLD:
|
|
case VirtualMachine::UNDEPLOYED:
|
|
case VirtualMachine::CLONING:
|
|
case VirtualMachine::CLONING_FAILURE:
|
|
break;
|
|
|
|
case VirtualMachine::STOPPED:
|
|
case VirtualMachine::DONE:
|
|
case VirtualMachine::SUSPENDED:
|
|
case VirtualMachine::ACTIVE:
|
|
att.resp_msg="Resize action is not available for state " +
|
|
vm->state_str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
ret = vm->check_resize(ncpu, nmemory, nvcpu, att.resp_msg);
|
|
|
|
vm->unlock();
|
|
|
|
if (ret != 0)
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Check quotas */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
if (quota_resize_authorization(&deltas, att, vm_perms) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RequestAttributes att_rollback(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Check & update host capacity */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
if (hid != -1)
|
|
{
|
|
int dcpu_host = (int) (dcpu * 100);//now in 100%
|
|
int dmem_host = dmemory * 1024; //now in Kilobytes
|
|
|
|
vector<VectorAttribute *> empty_pci;
|
|
|
|
host = hpool->get(hid);
|
|
|
|
if (host == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::HOST;
|
|
att.resp_id = hid;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0,
|
|
empty_pci, att.resp_msg) == false)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::HOST) << " " << hid
|
|
<< " does not have enough capacity.";
|
|
|
|
att.resp_msg = oss.str();
|
|
failure_response(ACTION, att);
|
|
|
|
host->unlock();
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
return;
|
|
}
|
|
|
|
host->update_capacity(dcpu_host, dmem_host, 0);
|
|
|
|
hpool->update(host);
|
|
|
|
host->unlock();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Resize the VM */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
vm = vmpool->get(id);
|
|
|
|
if (vm == 0)
|
|
{
|
|
att.resp_msg = id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
if (hid != -1)
|
|
{
|
|
host = hpool->get(hid);
|
|
|
|
if (host != 0)
|
|
{
|
|
host->update_capacity(-dcpu, -dmemory, 0);
|
|
hpool->update(host);
|
|
|
|
host->unlock();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//Check again state as the VM may transit to active (e.g. scheduled)
|
|
switch (vm->get_state())
|
|
{
|
|
case VirtualMachine::INIT:
|
|
case VirtualMachine::PENDING:
|
|
case VirtualMachine::HOLD:
|
|
case VirtualMachine::POWEROFF:
|
|
case VirtualMachine::UNDEPLOYED:
|
|
case VirtualMachine::CLONING:
|
|
case VirtualMachine::CLONING_FAILURE:
|
|
ret = vm->resize(ncpu, nmemory, nvcpu, att.resp_msg);
|
|
|
|
if (ret != 0)
|
|
{
|
|
vm->unlock();
|
|
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
vmpool->update(vm);
|
|
break;
|
|
|
|
case VirtualMachine::STOPPED:
|
|
case VirtualMachine::DONE:
|
|
case VirtualMachine::SUSPENDED:
|
|
case VirtualMachine::ACTIVE:
|
|
att.resp_msg = "Resize action is not available for state " +
|
|
vm->state_str();
|
|
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
if (hid != -1)
|
|
{
|
|
host = hpool->get(hid);
|
|
|
|
if (host != 0)
|
|
{
|
|
host->update_capacity(ocpu - ncpu, omemory - nmemory, 0);
|
|
hpool->update(host);
|
|
|
|
host->unlock();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
success_response(id, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineSnapshotCreate::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
int rc;
|
|
int snap_id;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string name = xmlrpc_c::value_string(paramList.getString(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_create(id, name, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(snap_id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineSnapshotRevert::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
int rc;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int snap_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_revert(id, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineSnapshotDelete::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
int rc;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int snap_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_delete(id, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineAttachNic::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
VirtualMachine * vm;
|
|
VirtualMachineTemplate tmpl;
|
|
|
|
int rc;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Check if the VM is a Virtual Router
|
|
// -------------------------------------------------------------------------
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->is_vrouter() &&
|
|
!VirtualRouter::is_action_supported(History::NIC_ATTACH_ACTION))
|
|
{
|
|
att.resp_msg = "Action is not supported for virtual router VMs";
|
|
failure_response(Request::ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse NIC template
|
|
// -------------------------------------------------------------------------
|
|
rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Perform the attach
|
|
// -------------------------------------------------------------------------
|
|
ErrorCode ec = request_execute(id, tmpl, att);
|
|
|
|
if ( ec == SUCCESS )
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
else
|
|
{
|
|
failure_response(ec, att);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
Request::ErrorCode VirtualMachineAttachNic::request_execute(int id,
|
|
VirtualMachineTemplate& tmpl, RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
DispatchManager * dm = nd.get_dm();
|
|
VirtualMachinePool* vmpool = nd.get_vmpool();
|
|
|
|
PoolObjectAuth vm_perms;
|
|
VirtualMachine * vm;
|
|
|
|
int rc;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation, restricted attributes & check quotas
|
|
// -------------------------------------------------------------------------
|
|
vm = vmpool->get(id);
|
|
|
|
if ( vm == 0 )
|
|
{
|
|
att.resp_id = id;
|
|
att.resp_obj = PoolObjectSQL::VM;
|
|
return NO_EXISTS;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
AuthRequest ar(att.uid, att.group_ids);
|
|
|
|
ar.add_auth(AuthRequest::MANAGE, vm_perms);
|
|
|
|
VirtualMachine::set_auth_request(att.uid, ar, &tmpl, true);
|
|
|
|
if (UserPool::authorize(ar) == -1)
|
|
{
|
|
att.resp_msg = ar.message;
|
|
return AUTHORIZATION;
|
|
}
|
|
|
|
RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
if (!att.is_admin())
|
|
{
|
|
string aname;
|
|
|
|
if (tmpl.check_restricted(aname))
|
|
{
|
|
att.resp_msg = "NIC includes a restricted attribute " + aname;
|
|
return AUTHORIZATION;
|
|
}
|
|
}
|
|
|
|
if (quota_authorization(&tmpl, Quotas::NETWORK, att_quota,
|
|
att.resp_msg) == false)
|
|
{
|
|
return AUTHORIZATION;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Perform the attach
|
|
// -------------------------------------------------------------------------
|
|
|
|
rc = dm->attach_nic(id, &tmpl, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
quota_rollback(&tmpl, Quotas::NETWORK, att_quota);
|
|
return ACTION;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDetachNic::request_execute(
|
|
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
|
|
{
|
|
VirtualMachine * vm;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int nic_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Check if the VM is a Virtual Router
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (vm->is_vrouter() &&
|
|
!VirtualRouter::is_action_supported(History::NIC_DETACH_ACTION))
|
|
{
|
|
att.resp_msg = "Action is not supported for virtual router VMs";
|
|
failure_response(Request::ACTION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Perform the detach
|
|
// -------------------------------------------------------------------------
|
|
ErrorCode ec = request_execute(id, nic_id, att);
|
|
|
|
if ( ec == SUCCESS )
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
else
|
|
{
|
|
failure_response(ec, att);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
Request::ErrorCode VirtualMachineDetachNic::request_execute(int id, int nic_id,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
VirtualMachinePool* vmpool = nd.get_vmpool();
|
|
|
|
PoolObjectAuth vm_perms;
|
|
VirtualMachine * vm;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
vm = vmpool->get(id);
|
|
|
|
if ( vm == 0 )
|
|
{
|
|
return NO_EXISTS;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
AuthRequest ar(att.uid, att.group_ids);
|
|
|
|
ar.add_auth(AuthRequest::MANAGE, vm_perms);
|
|
|
|
if (UserPool::authorize(ar) == -1)
|
|
{
|
|
att.resp_msg = ar.message;
|
|
return AUTHORIZATION;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Perform the detach
|
|
// -------------------------------------------------------------------------
|
|
if ( dm->detach_nic(id, nic_id, att, att.resp_msg) != 0 )
|
|
{
|
|
return ACTION;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineRecover::request_execute(
|
|
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
|
|
{
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int op = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
int rc;
|
|
string error;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
AuthRequest::Operation aop;
|
|
|
|
switch (op)
|
|
{
|
|
case 0: //recover-failure
|
|
case 1: //recover-success
|
|
aop = nd.get_vm_auth_op(History::RECOVER_ACTION);
|
|
break;
|
|
|
|
case 2: //retry
|
|
aop = nd.get_vm_auth_op(History::RETRY_ACTION);
|
|
break;
|
|
|
|
case 3: //delete
|
|
case 4: //delete-recreate set same as delete in OpenNebulaTemplate
|
|
aop = nd.get_vm_auth_op(History::DELETE_ACTION);
|
|
break;
|
|
|
|
default:
|
|
att.resp_msg = "Wrong recovery operation code";
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, aop) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
VirtualMachine * vm=(static_cast<VirtualMachinePool *>(pool))->get(id);
|
|
|
|
if (vm == 0)
|
|
{
|
|
att.resp_id = id;
|
|
failure_response(NO_EXISTS, att);
|
|
return;
|
|
}
|
|
|
|
switch (op)
|
|
{
|
|
case 0: //recover-failure
|
|
rc = dm->recover(vm, false, att, error);
|
|
break;
|
|
|
|
case 1: //recover-success
|
|
rc = dm->recover(vm, true, att, error);
|
|
break;
|
|
|
|
case 2: //retry
|
|
rc = dm->retry(vm, att, error);
|
|
break;
|
|
|
|
case 3: //delete
|
|
rc = dm->delete_vm(vm, att, error);
|
|
break;
|
|
|
|
case 4: //delete-recreate
|
|
rc = dm->delete_recreate(vm, att, error);
|
|
break;
|
|
}
|
|
|
|
if ( rc == 0 )
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
else
|
|
{
|
|
att.resp_msg = error;
|
|
failure_response(ACTION, att);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachinePoolCalculateShowback::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
int start_month = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int start_year = xmlrpc_c::value_int(paramList.getInt(2));
|
|
int end_month = xmlrpc_c::value_int(paramList.getInt(3));
|
|
int end_year = xmlrpc_c::value_int(paramList.getInt(4));
|
|
|
|
ostringstream oss;
|
|
string where;
|
|
int rc;
|
|
|
|
if ( att.gid != 0 )
|
|
{
|
|
att.resp_msg = "Action reserved for group 0 only";
|
|
failure_response(AUTHORIZATION, att);
|
|
return;
|
|
}
|
|
|
|
rc = (static_cast<VirtualMachinePool *>(pool))->calculate_showback(
|
|
start_month, start_year, end_month, end_year, att.resp_msg);
|
|
|
|
if (rc != 0)
|
|
{
|
|
failure_response(AUTHORIZATION, att);
|
|
return;
|
|
}
|
|
|
|
success_response("", att);
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDiskSnapshotCreate::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
VirtualMachine * vm;
|
|
|
|
PoolObjectAuth vm_perms;
|
|
|
|
VirtualMachineDisk * disk;
|
|
|
|
Template ds_deltas;
|
|
Template vm_deltas;
|
|
|
|
int rc;
|
|
int snap_id;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int did = xmlrpc_c::value_int(paramList.getInt(2));
|
|
string name = xmlrpc_c::value_string(paramList.getString(3));
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check request consistency (VM & disk exists, no volatile)
|
|
// ------------------------------------------------------------------------
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
disk = (const_cast<const VirtualMachine *>(vm))->get_disk(did);
|
|
|
|
if (disk == 0)
|
|
{
|
|
att.resp_msg = "VM disk does not exist";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get disk information and quota usage deltas */
|
|
/* ---------------------------------------------------------------------- */
|
|
bool img_ds_quota, vm_ds_quota;
|
|
|
|
long long ssize;
|
|
disk->vector_value("SIZE", ssize);
|
|
|
|
ssize = 2 * ssize; //Sanpshot accounts as another disk of same size
|
|
|
|
disk->resize_quotas(ssize, ds_deltas, vm_deltas, img_ds_quota, vm_ds_quota);
|
|
|
|
bool is_volatile = disk->is_volatile();
|
|
|
|
int img_id = -1;
|
|
disk->vector_value("IMAGE_ID", img_id);
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
if (is_volatile)
|
|
{
|
|
att.resp_msg = "Cannot make snapshots on volatile disks";
|
|
failure_response(ACTION, att);
|
|
return;
|
|
}
|
|
|
|
/* ---------- Attributes for quota update requests ---------------------- */
|
|
|
|
RequestAttributes img_att_quota;
|
|
RequestAttributes vm_att_quota;
|
|
|
|
if (img_ds_quota)
|
|
{
|
|
PoolObjectAuth img_perms;
|
|
|
|
Image* img = ipool->get(img_id);
|
|
|
|
if (img == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::IMAGE;
|
|
att.resp_id = img_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return;
|
|
}
|
|
|
|
img->get_permissions(img_perms);
|
|
|
|
img->unlock();
|
|
|
|
if (vm_authorization(id, 0, 0, att, 0, 0, &img_perms, auth_op) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
img_att_quota = RequestAttributes(img_perms.uid, img_perms.gid, att);
|
|
}
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
vm_att_quota = RequestAttributes(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Check quotas for the new size in image/system datastoress */
|
|
/* ---------------------------------------------------------------------- */
|
|
if ( img_ds_quota && !quota_authorization(&ds_deltas, Quotas::DATASTORE,
|
|
img_att_quota) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( vm_ds_quota && !quota_authorization(&ds_deltas, Quotas::DATASTORE,
|
|
vm_att_quota) )
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( !vm_deltas.empty() )
|
|
{
|
|
if (!quota_resize_authorization(id, &vm_deltas, vm_att_quota))
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
if ( vm_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, vm_att_quota);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Do the snapshot
|
|
// ------------------------------------------------------------------------
|
|
rc = dm->disk_snapshot_create(id, did, name, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
if ( vm_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, vm_att_quota);
|
|
}
|
|
|
|
if ( !vm_deltas.empty() )
|
|
{
|
|
quota_rollback(&vm_deltas, Quotas::VM, vm_att_quota);
|
|
}
|
|
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(snap_id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDiskSnapshotRevert::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
int rc;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int did = xmlrpc_c::value_int(paramList.getInt(2));
|
|
int snap_id = xmlrpc_c::value_int(paramList.getInt(3));
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->disk_snapshot_revert(id, did, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDiskSnapshotDelete::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
VirtualMachine * vm;
|
|
|
|
const VirtualMachineDisk * disk;
|
|
|
|
int rc;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int did = xmlrpc_c::value_int(paramList.getInt(2));
|
|
int snap_id = xmlrpc_c::value_int(paramList.getInt(3));
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
disk = (const_cast<const VirtualMachine *>(vm))->get_disk(did);
|
|
|
|
if (disk == 0)
|
|
{
|
|
att.resp_msg = "VM disk does not exist";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
bool persistent = disk->is_persistent();
|
|
|
|
int img_id = -1;
|
|
disk->vector_value("IMAGE_ID", img_id);
|
|
|
|
vm->unlock();
|
|
|
|
if (persistent)
|
|
{
|
|
PoolObjectAuth img_perms;
|
|
|
|
Image* img = ipool->get(img_id);
|
|
|
|
if (img == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::IMAGE;
|
|
att.resp_id = img_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return;
|
|
}
|
|
|
|
img->get_permissions(img_perms);
|
|
|
|
img->unlock();
|
|
|
|
if (vm_authorization(id, 0, 0, att, 0, 0, &img_perms, auth_op) == false)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->disk_snapshot_delete(id, did, snap_id, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineUpdateConf::request_execute(
|
|
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
|
|
{
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
|
|
|
VirtualMachine * vm;
|
|
VirtualMachineTemplate tmpl;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse template
|
|
// -------------------------------------------------------------------------
|
|
int rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Authorize the operation & restricted attributes */
|
|
/* ---------------------------------------------------------------------- */
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Update VirtualMachine Configuration */
|
|
/* ---------------------------------------------------------------------- */
|
|
vm = static_cast<VirtualMachinePool *>(pool)->get(id);
|
|
|
|
if (vm == 0)
|
|
{
|
|
att.resp_id = id;
|
|
failure_response(NO_EXISTS, att);
|
|
return;
|
|
}
|
|
|
|
if (!att.is_admin())
|
|
{
|
|
string aname;
|
|
|
|
VirtualMachineTemplate * conf_tmpl = vm->get_updateconf_template();
|
|
|
|
bool has_restricted = tmpl.check_restricted(aname, conf_tmpl);
|
|
|
|
delete conf_tmpl;
|
|
|
|
if (has_restricted)
|
|
{
|
|
att.resp_msg = "Template includes a restricted attribute " + aname;
|
|
failure_response(AUTHORIZATION, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( vm->updateconf(tmpl, att.resp_msg) != 0 )
|
|
{
|
|
failure_response(INTERNAL, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Update PORT if a new GRAPHICS section has been added & VM is deployed. */
|
|
/* ---------------------------------------------------------------------- */
|
|
VectorAttribute * graphics = vm->get_template_attribute("GRAPHICS");
|
|
|
|
unsigned int port;
|
|
VirtualMachine::VmState state = vm->get_state();
|
|
|
|
if (graphics != 0 && graphics->vector_value("PORT", port) == -1 &&
|
|
(state == VirtualMachine::ACTIVE || state == VirtualMachine::POWEROFF ||
|
|
state == VirtualMachine::SUSPENDED))
|
|
{
|
|
ClusterPool * cpool = Nebula::instance().get_clpool();
|
|
|
|
int rc = cpool->get_vnc_port(vm->get_cid(), vm->get_oid(), port);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
att.resp_msg = "No free VNC ports available in the cluster";
|
|
failure_response(INTERNAL, att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
graphics->replace("PORT", port);
|
|
}
|
|
|
|
static_cast<VirtualMachinePool *>(pool)->update(vm);
|
|
|
|
vm->unlock();
|
|
|
|
success_response(id, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDiskResize::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
VirtualMachine * vm;
|
|
|
|
Template ds_deltas;
|
|
Template vm_deltas;
|
|
|
|
PoolObjectAuth vm_perms;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int did = xmlrpc_c::value_int(paramList.getInt(2));
|
|
string size_s = xmlrpc_c::value_string(paramList.getString(3));
|
|
|
|
long long size , current_size;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check request consistency (VM & disk exists, size, and no snapshots)
|
|
// ------------------------------------------------------------------------
|
|
istringstream iss(size_s);
|
|
|
|
iss >> size;
|
|
|
|
if (iss.fail() || !iss.eof())
|
|
{
|
|
att.resp_msg = "Disk SIZE is not a valid integer";
|
|
failure_response(ACTION, att);
|
|
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
VirtualMachineDisk * disk =vm->get_disk(did);
|
|
|
|
if (disk == 0)
|
|
{
|
|
att.resp_msg = "VM disk does not exist";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
disk->vector_value("SIZE", current_size);
|
|
|
|
if ( size <= current_size )
|
|
{
|
|
att.resp_msg = "New disk size has to be greater than current one";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
if ( disk->has_snapshots() )
|
|
{
|
|
att.resp_msg = "Cannot resize a disk with snapshots";
|
|
failure_response(ACTION, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
/* ------------- Get information about the disk and image --------------- */
|
|
bool img_ds_quota, vm_ds_quota;
|
|
|
|
disk->resize_quotas(size, ds_deltas, vm_deltas, img_ds_quota, vm_ds_quota);
|
|
|
|
int img_id = -1;
|
|
disk->vector_value("IMAGE_ID", img_id);
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Authorize the request for VM and IMAGE for persistent disks */
|
|
/* ---------------------------------------------------------------------- */
|
|
RequestAttributes img_att_quota;
|
|
RequestAttributes vm_att_quota;
|
|
|
|
if ( img_ds_quota )
|
|
{
|
|
PoolObjectAuth img_perms;
|
|
|
|
if ( img_id != -1 )
|
|
{
|
|
Image* img = ipool->get(img_id);
|
|
|
|
if (img == 0)
|
|
{
|
|
att.resp_obj = PoolObjectSQL::IMAGE;
|
|
att.resp_id = img_id;
|
|
failure_response(NO_EXISTS, att);
|
|
|
|
return;
|
|
}
|
|
|
|
img->get_permissions(img_perms);
|
|
|
|
img->unlock();
|
|
}
|
|
|
|
if (vm_authorization(id, 0, 0, att, 0, 0, &img_perms, auth_op) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
img_att_quota = RequestAttributes(img_perms.uid, img_perms.gid, att);
|
|
}
|
|
|
|
if ( vm_ds_quota )
|
|
{
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
vm_att_quota = RequestAttributes(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Check quotas for the new size in image/system datastoress */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
if ( img_ds_quota && !quota_authorization(&ds_deltas, Quotas::DATASTORE,
|
|
img_att_quota))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( vm_ds_quota && !quota_authorization(&ds_deltas, Quotas::DATASTORE,
|
|
vm_att_quota))
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( !vm_deltas.empty() )
|
|
{
|
|
if (!quota_resize_authorization(id, &vm_deltas, vm_att_quota))
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
if ( vm_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, vm_att_quota);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Resize the disk
|
|
// ------------------------------------------------------------------------
|
|
int rc = dm->disk_resize(id, did, size, att, att.resp_msg);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
if ( img_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, img_att_quota);
|
|
}
|
|
|
|
if ( vm_ds_quota )
|
|
{
|
|
quota_rollback(&ds_deltas, Quotas::DATASTORE, vm_att_quota);
|
|
}
|
|
|
|
if ( !vm_deltas.empty() )
|
|
{
|
|
quota_rollback(&vm_deltas, Quotas::VM, vm_att_quota);
|
|
}
|
|
|
|
failure_response(ACTION, att);
|
|
}
|
|
else
|
|
{
|
|
success_response(did, att);
|
|
}
|
|
|
|
return;
|
|
}
|