mirror of
https://github.com/OpenNebula/one.git
synced 2026-11-16 01:33:10 +09:00
2132 lines
56 KiB
C++
2132 lines
56 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
|
/* */
|
|
/* 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 "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,
|
|
AuthRequest::Operation op)
|
|
{
|
|
PoolObjectSQL * object;
|
|
PoolObjectAuth vm_perms;
|
|
|
|
object = pool->get(oid,true);
|
|
|
|
if ( object == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(auth_object),oid),
|
|
att);
|
|
|
|
return false;
|
|
}
|
|
|
|
if ( att.uid == 0 )
|
|
{
|
|
object->unlock();
|
|
return true;
|
|
}
|
|
|
|
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(PoolObjectSQL::IMAGE, tmpl->to_xml(t_xml));
|
|
}
|
|
|
|
if ( vtmpl != 0 )
|
|
{
|
|
VirtualMachine::set_auth_request(att.uid, ar, vtmpl);
|
|
}
|
|
|
|
if ( ds_perm != 0 )
|
|
{
|
|
ar.add_auth(AuthRequest::USE, *ds_perm);
|
|
}
|
|
|
|
if (UserPool::authorize(ar) == -1)
|
|
{
|
|
failure_response(AUTHORIZATION,
|
|
authorization_error(ar.message, att),
|
|
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, true);
|
|
|
|
if (vm == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::VM),oid),
|
|
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;
|
|
|
|
string error_str;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
UserPool* upool = nd.get_upool();
|
|
GroupPool* gpool = nd.get_gpool();
|
|
|
|
Quotas user_dquotas = nd.get_default_user_quota();
|
|
Quotas group_dquotas = nd.get_default_group_quota();
|
|
|
|
if (vm_perms.uid != UserPool::ONEADMIN_ID)
|
|
{
|
|
User * user = upool->get(vm_perms.uid, true);
|
|
|
|
if ( user != 0 )
|
|
{
|
|
rc = user->quota.quota_update(Quotas::VM, deltas, user_dquotas, error_str);
|
|
|
|
if (rc == false)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::USER)
|
|
<< " [" << vm_perms.uid << "] "
|
|
<< error_str;
|
|
|
|
failure_response(AUTHORIZATION,
|
|
request_error(oss.str(), ""),
|
|
att);
|
|
|
|
user->unlock();
|
|
|
|
return false;
|
|
}
|
|
|
|
upool->update(user);
|
|
|
|
user->unlock();
|
|
}
|
|
}
|
|
|
|
if (vm_perms.gid != GroupPool::ONEADMIN_ID)
|
|
{
|
|
Group * group = gpool->get(vm_perms.gid, true);
|
|
|
|
if ( group != 0 )
|
|
{
|
|
rc = group->quota.quota_update(Quotas::VM, deltas, group_dquotas, error_str);
|
|
|
|
if (rc == false)
|
|
{
|
|
ostringstream oss;
|
|
RequestAttributes att_tmp(vm_perms.uid, -1, att);
|
|
|
|
oss << object_name(PoolObjectSQL::GROUP)
|
|
<< " [" << vm_perms.gid << "] "
|
|
<< error_str;
|
|
|
|
failure_response(AUTHORIZATION,
|
|
request_error(oss.str(), ""),
|
|
att);
|
|
|
|
group->unlock();
|
|
|
|
quota_rollback(deltas, Quotas::VM, att_tmp);
|
|
|
|
return false;
|
|
}
|
|
|
|
gpool->update(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;
|
|
|
|
ds_id = -1;
|
|
|
|
if (cluster_id == ClusterPool::NONE_CLUSTER_ID)
|
|
{
|
|
ds_id = DatastorePool::SYSTEM_DS_ID;
|
|
}
|
|
else
|
|
{
|
|
cluster = clpool->get(cluster_id, true);
|
|
|
|
if (cluster == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::CLUSTER), cluster_id),
|
|
att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
set<int> ds_ids = cluster->get_datastores();
|
|
|
|
cluster->unlock();
|
|
|
|
ds_id = Cluster::get_default_sysetm_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) << ".";
|
|
|
|
failure_response(ACTION, request_error(oss.str(),""), att);
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return get_ds_information(ds_id, cluster_id, tm_mad, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::get_ds_information(int ds_id,
|
|
int& ds_cluster_id,
|
|
string& tm_mad,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
Datastore * ds = nd.get_dspool()->get(ds_id, true);
|
|
|
|
ds_cluster_id = -1;
|
|
|
|
if ( ds == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
|
|
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.";
|
|
|
|
failure_response(INTERNAL, request_error(oss.str(),""), att);
|
|
|
|
ds->unlock();
|
|
|
|
return -1;
|
|
}
|
|
|
|
ds_cluster_id = ds->get_cluster_id();
|
|
|
|
tm_mad = ds->get_tm_mad();
|
|
|
|
ds->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::get_host_information(
|
|
int hid,
|
|
string& name,
|
|
string& vmm,
|
|
string& vnm,
|
|
int& cluster_id,
|
|
string& ds_location,
|
|
bool& is_public_cloud,
|
|
PoolObjectAuth& host_perms,
|
|
RequestAttributes& att)
|
|
|
|
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
HostPool * hpool = nd.get_hpool();
|
|
|
|
Host * host = hpool->get(hid,true);
|
|
|
|
if ( host == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::HOST),hid),
|
|
att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
name = host->get_name();
|
|
vmm = host->get_vmm_mad();
|
|
vnm = host->get_vnm_mad();
|
|
|
|
cluster_id = host->get_cluster_id();
|
|
|
|
is_public_cloud = host->is_public_cloud();
|
|
|
|
host->get_permissions(host_perms);
|
|
|
|
host->unlock();
|
|
|
|
if (nd.get_ds_location(cluster_id, ds_location) == -1)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::CLUSTER),cluster_id),
|
|
att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool RequestManagerVirtualMachine::check_host(int hid,
|
|
int cpu,
|
|
int mem,
|
|
int disk,
|
|
string& error)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
HostPool * hpool = nd.get_hpool();
|
|
|
|
Host * host;
|
|
bool test;
|
|
|
|
host = hpool->get(hid, true);
|
|
|
|
if (host == 0)
|
|
{
|
|
error = "Host no longer exists";
|
|
return false;
|
|
}
|
|
|
|
test = host->test_capacity(cpu, mem, disk);
|
|
|
|
if (!test)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::HOST)
|
|
<< " " << hid << " does not have enough capacity.";
|
|
|
|
error = oss.str();
|
|
}
|
|
|
|
host->unlock();
|
|
|
|
return test;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VirtualMachine * RequestManagerVirtualMachine::get_vm(int id,
|
|
RequestAttributes& att)
|
|
{
|
|
VirtualMachine * vm;
|
|
|
|
vm = static_cast<VirtualMachine *>(pool->get(id,true));
|
|
|
|
if ( vm == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,get_error(object_name(auth_object),id), att);
|
|
return 0;
|
|
}
|
|
|
|
return vm;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int RequestManagerVirtualMachine::add_history(VirtualMachine * vm,
|
|
int hid,
|
|
int cid,
|
|
const string& hostname,
|
|
const string& vmm_mad,
|
|
const string& vnm_mad,
|
|
const string& tm_mad,
|
|
const string& ds_location,
|
|
int ds_id,
|
|
RequestAttributes& att)
|
|
{
|
|
string vmdir;
|
|
int rc;
|
|
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
|
|
vm->add_history(hid, cid, hostname, vmm_mad, vnm_mad, tm_mad, ds_location, ds_id);
|
|
|
|
rc = vmpool->update_history(vm);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL,
|
|
request_error("Cannot update virtual machine history",""),
|
|
att);
|
|
|
|
return -1;
|
|
}
|
|
|
|
vmpool->update(vm);
|
|
|
|
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;
|
|
|
|
AuthRequest::Operation op = auth_op;
|
|
History::VMAction action;
|
|
|
|
// Compatibility with 3.8
|
|
if (action_st == "cancel")
|
|
{
|
|
action_st = "shutdown-hard";
|
|
}
|
|
else if (action_st == "restart")
|
|
{
|
|
action_st = "boot";
|
|
}
|
|
else if (action_st == "finalize")
|
|
{
|
|
action_st = "delete";
|
|
}
|
|
else if (action_st == "resubmit")
|
|
{
|
|
action_st = "delete-recreate";
|
|
}
|
|
else if (action_st == "reset")
|
|
{
|
|
action_st = "reboot-hard";
|
|
}
|
|
|
|
History::action_from_str(action_st, action);
|
|
|
|
if (action == History::RESCHED_ACTION || action == History::UNRESCHED_ACTION)
|
|
{
|
|
op = AuthRequest::ADMIN;
|
|
}
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (action)
|
|
{
|
|
case History::SHUTDOWN_ACTION:
|
|
rc = dm->shutdown(id);
|
|
break;
|
|
case History::HOLD_ACTION:
|
|
rc = dm->hold(id);
|
|
break;
|
|
case History::RELEASE_ACTION:
|
|
rc = dm->release(id);
|
|
break;
|
|
case History::STOP_ACTION:
|
|
rc = dm->stop(id);
|
|
break;
|
|
case History::SHUTDOWN_HARD_ACTION:
|
|
rc = dm->cancel(id);
|
|
break;
|
|
case History::SUSPEND_ACTION:
|
|
rc = dm->suspend(id);
|
|
break;
|
|
case History::RESUME_ACTION:
|
|
rc = dm->resume(id);
|
|
break;
|
|
case History::BOOT_ACTION:
|
|
rc = dm->restart(id);
|
|
break;
|
|
case History::DELETE_ACTION:
|
|
rc = dm->finalize(id);
|
|
break;
|
|
case History::DELETE_RECREATE_ACTION:
|
|
rc = dm->resubmit(id);
|
|
break;
|
|
case History::REBOOT_ACTION:
|
|
rc = dm->reboot(id);
|
|
break;
|
|
case History::RESCHED_ACTION:
|
|
rc = dm->resched(id, true);
|
|
break;
|
|
case History::UNRESCHED_ACTION:
|
|
rc = dm->resched(id, false);
|
|
break;
|
|
case History::REBOOT_HARD_ACTION:
|
|
rc = dm->reset(id);
|
|
break;
|
|
case History::POWEROFF_ACTION:
|
|
rc = dm->poweroff(id, false);
|
|
break;
|
|
case History::POWEROFF_HARD_ACTION:
|
|
rc = dm->poweroff(id, true);
|
|
break;
|
|
case History::UNDEPLOY_ACTION:
|
|
rc = dm->undeploy(id, false);
|
|
break;
|
|
case History::UNDEPLOY_HARD_ACTION:
|
|
rc = dm->undeploy(id, true);
|
|
break;
|
|
default:
|
|
rc = -3;
|
|
break;
|
|
}
|
|
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
success_response(id, att);
|
|
break;
|
|
case -1:
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(auth_object),id),
|
|
att);
|
|
break;
|
|
case -2:
|
|
oss << "Wrong state to perform action \"" << action_st << "\"";
|
|
|
|
failure_response(ACTION,
|
|
request_error(oss.str(),""),
|
|
att);
|
|
break;
|
|
case -3:
|
|
oss << "Virtual machine action \"" << action_st
|
|
<< "\" is not supported";
|
|
|
|
failure_response(ACTION,
|
|
request_error(oss.str(),""),
|
|
att);
|
|
break;
|
|
default:
|
|
failure_response(INTERNAL,
|
|
request_error("Internal error","Action result not defined"),
|
|
att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
VirtualMachine * vm;
|
|
|
|
string hostname;
|
|
string vmm_mad;
|
|
string vnm_mad;
|
|
int cluster_id;
|
|
string ds_location;
|
|
bool is_public_cloud;
|
|
PoolObjectAuth host_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,
|
|
vnm_mad,
|
|
cluster_id,
|
|
ds_location,
|
|
is_public_cloud,
|
|
host_perms,
|
|
att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Authorize request
|
|
// ------------------------------------------------------------------------
|
|
|
|
auth = vm_authorization(id, 0, 0, att, &host_perms, 0, auth_op);
|
|
|
|
if (auth == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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();
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get information about the system DS to use (tm_mad)
|
|
// ------------------------------------------------------------------------
|
|
|
|
if (is_public_cloud)
|
|
{
|
|
ds_id = -1;
|
|
}
|
|
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
|
|
{
|
|
int ds_cluster_id;
|
|
|
|
if (get_ds_information(ds_id, ds_cluster_id, tm_mad, att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ds_cluster_id != cluster_id)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::DATASTORE)
|
|
<< " [" << ds_id << "] and " << object_name(PoolObjectSQL::HOST)
|
|
<< " [" << hid <<"] are not in the same cluster.";
|
|
|
|
failure_response(ACTION, request_error(oss.str(),""), att);
|
|
|
|
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)
|
|
{
|
|
failure_response(ACTION,
|
|
request_error("Wrong state to perform action",""),
|
|
att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (enforce)
|
|
{
|
|
int cpu, mem, disk;
|
|
string error;
|
|
|
|
vm->get_requirements(cpu, mem, disk);
|
|
|
|
vm->unlock();
|
|
|
|
if (check_host(hid, cpu, mem, disk, error) == false)
|
|
{
|
|
failure_response(ACTION, request_error(error,""), att);
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Add a new history record and deploy the VM
|
|
// ------------------------------------------------------------------------
|
|
|
|
if (add_history(vm,
|
|
hid,
|
|
cluster_id,
|
|
hostname,
|
|
vmm_mad,
|
|
vnm_mad,
|
|
tm_mad,
|
|
ds_location,
|
|
ds_id,
|
|
att) != 0)
|
|
{
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
dm->deploy(vm);
|
|
|
|
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();
|
|
|
|
VirtualMachine * vm;
|
|
|
|
string hostname;
|
|
string vmm_mad;
|
|
string vnm_mad;
|
|
int cluster_id;
|
|
string ds_location;
|
|
bool is_public_cloud;
|
|
PoolObjectAuth host_perms;
|
|
|
|
int c_hid;
|
|
int c_cluster_id;
|
|
int c_ds_id;
|
|
string c_tm_mad;
|
|
bool c_is_public_cloud;
|
|
|
|
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 live = xmlrpc_c::value_boolean(paramList.getBoolean(3));
|
|
bool enforce = false;
|
|
|
|
if ( paramList.size() > 4 )
|
|
{
|
|
enforce = xmlrpc_c::value_boolean(paramList.getBoolean(4));
|
|
}
|
|
|
|
if (get_host_information(hid,
|
|
hostname,
|
|
vmm_mad,
|
|
vnm_mad,
|
|
cluster_id,
|
|
ds_location,
|
|
is_public_cloud,
|
|
host_perms,
|
|
att) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Authorize request
|
|
// ------------------------------------------------------------------------
|
|
|
|
auth = vm_authorization(id, 0, 0, att, &host_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->get_state() != VirtualMachine::ACTIVE) ||
|
|
(vm->get_lcm_state() != VirtualMachine::RUNNING) ||
|
|
(vm->hasPreviousHistory() && vm->get_previous_reason() == History::NONE))
|
|
{
|
|
failure_response(ACTION,
|
|
request_error("Wrong state to perform action",""),
|
|
att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
// Check we are not migrating to the same host
|
|
|
|
c_hid = vm->get_hid();
|
|
|
|
if (c_hid == hid)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "VM is already running on "
|
|
<< object_name(PoolObjectSQL::HOST) << " [" << c_hid << "]";
|
|
|
|
failure_response(ACTION,
|
|
request_error(oss.str(),""),
|
|
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();
|
|
|
|
if (enforce)
|
|
{
|
|
int cpu, mem, disk;
|
|
string error;
|
|
|
|
vm->get_requirements(cpu, mem, disk);
|
|
|
|
vm->unlock();
|
|
|
|
if (check_host(hid, cpu, mem, disk, error) == false)
|
|
{
|
|
failure_response(ACTION, request_error(error,""), att);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vm->unlock();
|
|
}
|
|
|
|
// Check we are in the same cluster
|
|
|
|
Host * host = nd.get_hpool()->get(c_hid, true);
|
|
|
|
if (host == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::HOST), c_hid),
|
|
att);
|
|
}
|
|
|
|
c_cluster_id = host->get_cluster_id();
|
|
|
|
c_is_public_cloud = host->is_public_cloud();
|
|
|
|
host->unlock();
|
|
|
|
if ( c_cluster_id != cluster_id )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Cannot migrate to a different cluster. VM running in a host"
|
|
<< " in " << object_name(PoolObjectSQL::CLUSTER) << " ["
|
|
<< c_cluster_id << "] , and new host is in "
|
|
<< object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id << "]";
|
|
|
|
failure_response(ACTION,
|
|
request_error(oss.str(),""),
|
|
att);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( is_public_cloud || c_is_public_cloud )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error("Cannot migrate to or from a Public Cloud Host",""),
|
|
att);
|
|
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Add a new history record and migrate the VM
|
|
// ------------------------------------------------------------------------
|
|
|
|
if ( (vm = get_vm(id, att)) == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (add_history(vm,
|
|
hid,
|
|
cluster_id,
|
|
hostname,
|
|
vmm_mad,
|
|
vnm_mad,
|
|
c_tm_mad,
|
|
ds_location,
|
|
c_ds_id,
|
|
att) != 0)
|
|
{
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
if (live == true)
|
|
{
|
|
dm->live_migrate(vm);
|
|
}
|
|
else
|
|
{
|
|
dm->migrate(vm);
|
|
}
|
|
|
|
vm->unlock();
|
|
|
|
success_response(id, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ImagePool * ipool = nd.get_ipool();
|
|
DatastorePool * dspool = nd.get_dspool();
|
|
UserPool * upool = nd.get_upool();
|
|
|
|
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));
|
|
bool is_hot = false; //Optional XML-RPC argument
|
|
|
|
if ( paramList.size() > 5 )
|
|
{
|
|
is_hot = xmlrpc_c::value_boolean(paramList.getBoolean(5));
|
|
}
|
|
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
VirtualMachine * vm;
|
|
Datastore * ds;
|
|
int iid;
|
|
|
|
string error_str;
|
|
|
|
string driver;
|
|
string target;
|
|
string dev_prefix;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get user's umask
|
|
// -------------------------------------------------------------------------
|
|
User * user = upool->get(att.uid, true);
|
|
|
|
if ( user == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::USER), att.uid),
|
|
att);
|
|
|
|
return;
|
|
}
|
|
|
|
int umask = user->get_umask();
|
|
|
|
user->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Prepare and check the VM/DISK to be saved_as
|
|
// -------------------------------------------------------------------------
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( vm->set_saveas_state(disk_id, is_hot) != 0 )
|
|
{
|
|
vm->unlock();
|
|
|
|
failure_response(INTERNAL,
|
|
request_error("VM has to be RUNNING, POWEROFF or"
|
|
" SUSPENDED to snapshot disks.",""), att);
|
|
return;
|
|
}
|
|
|
|
int iid_orig = vm->get_image_from_disk(disk_id, is_hot, error_str);
|
|
|
|
if ( iid_orig == -1 )
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vm->unlock();
|
|
|
|
failure_response(INTERNAL,
|
|
request_error("Cannot use selected DISK", error_str),
|
|
att);
|
|
return;
|
|
}
|
|
|
|
vmpool->update(vm);
|
|
|
|
vm->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the data of the Image to be saved
|
|
// -------------------------------------------------------------------------
|
|
Image * img = ipool->get(iid_orig, true);
|
|
|
|
if ( img == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::IMAGE), iid_orig),
|
|
att);
|
|
|
|
if ((vm = vmpool->get(id, true)) != 0)
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vmpool->update(vm);
|
|
vm->unlock();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int ds_id = img->get_ds_id();
|
|
string ds_name = img->get_ds_name();
|
|
long long size = img->get_size();
|
|
|
|
Image::ImageType type = img->get_type();
|
|
|
|
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:
|
|
failure_response(INTERNAL,
|
|
request_error("Cannot save_as image of type " +
|
|
Image::type_to_str(type), ""), att);
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the data of the DataStore for the new image
|
|
// -------------------------------------------------------------------------
|
|
if ((ds = dspool->get(ds_id, true)) == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
|
|
att);
|
|
|
|
if ((vm = vmpool->get(id, true)) != 0)
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vmpool->update(vm);
|
|
vm->unlock();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
string ds_data;
|
|
PoolObjectAuth ds_perms;
|
|
long long avail;
|
|
bool ds_check;
|
|
|
|
ds->get_permissions(ds_perms);
|
|
ds->to_xml(ds_data);
|
|
|
|
ds_check = ds->get_avail_mb(avail);
|
|
|
|
Image::DiskType ds_disk_type = ds->get_disk_type();
|
|
|
|
ds->unlock();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Check Datastore Capacity
|
|
// -------------------------------------------------------------------------
|
|
if (ds_check && (size > avail))
|
|
{
|
|
failure_response(ACTION, "Not enough space in datastore", att);
|
|
|
|
if ((vm = vmpool->get(id, true)) != 0)
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vmpool->update(vm);
|
|
vm->unlock();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Create a template for the new Image
|
|
// -------------------------------------------------------------------------
|
|
ImageTemplate * itemplate = new ImageTemplate;
|
|
Template img_usage;
|
|
|
|
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 ( is_hot )
|
|
{
|
|
itemplate->set_saving_hot();
|
|
}
|
|
|
|
if ( img_type.empty() )
|
|
{
|
|
itemplate->add("TYPE", Image::type_to_str(type));
|
|
}
|
|
else
|
|
{
|
|
itemplate->add("TYPE", img_type);
|
|
}
|
|
|
|
if ( driver.empty() == false )
|
|
{
|
|
itemplate->add("DRIVER", driver);
|
|
}
|
|
|
|
if ( target.empty() == false )
|
|
{
|
|
itemplate->add("TARGET", target);
|
|
}
|
|
|
|
if ( dev_prefix.empty() == false )
|
|
{
|
|
itemplate->add("DEV_PREFIX", dev_prefix);
|
|
}
|
|
|
|
img_usage.add("SIZE", size);
|
|
img_usage.add("DATASTORE", ds_id);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation & check quotas
|
|
// -------------------------------------------------------------------------
|
|
bool rc_auth = vm_authorization(id, itemplate, 0, att, 0,&ds_perms,auth_op);
|
|
|
|
if ( rc_auth == true )
|
|
{
|
|
rc_auth = quota_authorization(&img_usage, Quotas::DATASTORE, att);
|
|
}
|
|
|
|
if ( rc_auth == false)
|
|
{
|
|
delete itemplate;
|
|
|
|
if ((vm = vmpool->get(id, true)) != 0)
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vmpool->update(vm);
|
|
vm->unlock();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Create the image
|
|
// -------------------------------------------------------------------------
|
|
int rc = ipool->allocate(att.uid,
|
|
att.gid,
|
|
att.uname,
|
|
att.gname,
|
|
umask,
|
|
itemplate,
|
|
ds_id,
|
|
ds_name,
|
|
ds_disk_type,
|
|
ds_data,
|
|
Datastore::IMAGE_DS,
|
|
-1,
|
|
&iid,
|
|
error_str);
|
|
if (rc < 0)
|
|
{
|
|
quota_rollback(&img_usage, Quotas::DATASTORE, att);
|
|
|
|
if ((vm = vmpool->get(id, true)) != 0)
|
|
{
|
|
vm->clear_saveas_state(disk_id, is_hot);
|
|
|
|
vmpool->update(vm);
|
|
vm->unlock();
|
|
}
|
|
|
|
failure_response(INTERNAL,
|
|
allocate_error(PoolObjectSQL::IMAGE, error_str), att);
|
|
return;
|
|
}
|
|
|
|
ds = dspool->get(ds_id, true);
|
|
|
|
if ( ds != 0 ) // TODO: error otherwise or leave image in ERROR?
|
|
{
|
|
ds->add_image(iid);
|
|
|
|
dspool->update(ds);
|
|
|
|
ds->unlock();
|
|
}
|
|
|
|
// Return the new allocated Image ID
|
|
success_response(iid, att);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
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, auth_op);
|
|
|
|
if ( auth == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = (static_cast<VirtualMachinePool *>(pool))->dump_monitoring(oss, id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL,request_error("Internal Error",""), 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 = new VirtualMachineTemplate();
|
|
VirtualMachineTemplate * deltas = 0;
|
|
PoolObjectAuth vm_perms;
|
|
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
VirtualMachine * vm;
|
|
|
|
int rc;
|
|
string error_str;
|
|
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, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, error_str, att);
|
|
delete tmpl;
|
|
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation & check quotas
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, tmpl, att, 0, 0, auth_op) == false )
|
|
{
|
|
delete tmpl;
|
|
return;
|
|
}
|
|
|
|
vm = vmpool->get(id, true);
|
|
|
|
if (vm == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::VM),id),
|
|
att);
|
|
return;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
volatile_disk = VirtualMachine::isVolatile(tmpl);
|
|
|
|
if ( volatile_disk )
|
|
{
|
|
deltas = new VirtualMachineTemplate(*tmpl);
|
|
|
|
deltas->add("VMS", 0);
|
|
|
|
if (quota_resize_authorization(id, deltas, att_quota) == false)
|
|
{
|
|
delete tmpl;
|
|
delete deltas;
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( quota_authorization(tmpl, Quotas::IMAGE, att_quota) == false )
|
|
{
|
|
delete tmpl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
rc = dm->attach(id, tmpl, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
if ( volatile_disk )
|
|
{
|
|
quota_rollback(deltas, Quotas::VM, att_quota);
|
|
}
|
|
else
|
|
{
|
|
quota_rollback(tmpl, Quotas::IMAGE, att_quota);
|
|
}
|
|
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
delete tmpl;
|
|
delete deltas;
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
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, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->detach(id, disk_id, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
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;
|
|
string error_str;
|
|
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.uid == UserPool::ONEADMIN_ID || att.gid == GroupPool::ONEADMIN_ID)
|
|
{
|
|
enforce = enforce_param;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse template
|
|
// -------------------------------------------------------------------------
|
|
|
|
rc = tmpl.parse_str_or_xml(str_tmpl, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, error_str, att);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Authorize the operation & restricted attributes */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (att.uid != UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID)
|
|
{
|
|
string aname;
|
|
|
|
if (tmpl.check(aname))
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Template includes a restricted attribute " << aname;
|
|
|
|
failure_response(AUTHORIZATION,
|
|
authorization_error(oss.str(), att),
|
|
att);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the resize values */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
tmpl.get("CPU", ncpu);
|
|
tmpl.get("VCPU", nvcpu);
|
|
tmpl.get("MEMORY", nmemory);
|
|
|
|
vm = vmpool->get(id, true);
|
|
|
|
if (vm == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::VM),id),
|
|
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::FAILED:
|
|
case VirtualMachine::UNDEPLOYED:
|
|
break;
|
|
|
|
case VirtualMachine::STOPPED:
|
|
case VirtualMachine::DONE:
|
|
case VirtualMachine::SUSPENDED:
|
|
case VirtualMachine::ACTIVE:
|
|
failure_response(ACTION,
|
|
request_error("Wrong state to perform action",""),
|
|
att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
ret = vm->check_resize(ncpu, nmemory, nvcpu, error_str);
|
|
|
|
vm->unlock();
|
|
|
|
if (ret != 0)
|
|
{
|
|
failure_response(INTERNAL,
|
|
request_error("Could resize the VM", error_str),
|
|
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
|
|
|
|
host = hpool->get(hid, true);
|
|
|
|
if (host == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::HOST),hid),
|
|
att);
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0) == false)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::HOST)
|
|
<< " " << hid << " does not have enough capacity.";
|
|
|
|
failure_response(ACTION, request_error(oss.str(),""), 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, true);
|
|
|
|
if (vm == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::VM),id),
|
|
att);
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
if (hid != -1)
|
|
{
|
|
host = hpool->get(hid, true);
|
|
|
|
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::FAILED:
|
|
case VirtualMachine::POWEROFF:
|
|
case VirtualMachine::UNDEPLOYED:
|
|
ret = vm->resize(ncpu, nmemory, nvcpu, error_str);
|
|
|
|
if (ret != 0)
|
|
{
|
|
vm->unlock();
|
|
|
|
failure_response(INTERNAL,
|
|
request_error("Could not resize the VM", error_str),
|
|
att);
|
|
return;
|
|
}
|
|
|
|
vmpool->update(vm);
|
|
break;
|
|
|
|
case VirtualMachine::STOPPED:
|
|
case VirtualMachine::DONE:
|
|
case VirtualMachine::SUSPENDED:
|
|
case VirtualMachine::ACTIVE:
|
|
failure_response(ACTION,
|
|
request_error("Wrong state to perform action",""),
|
|
att);
|
|
|
|
vm->unlock();
|
|
|
|
quota_rollback(&deltas, Quotas::VM, att_rollback);
|
|
|
|
if (hid != -1)
|
|
{
|
|
host = hpool->get(hid, true);
|
|
|
|
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;
|
|
string error_str;
|
|
|
|
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, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_create(id, name, snap_id, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
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;
|
|
string error_str;
|
|
|
|
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, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_revert(id, snap_id, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
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;
|
|
string error_str;
|
|
|
|
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, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->snapshot_delete(id, snap_id, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineAttachNic::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
VirtualMachineTemplate tmpl;
|
|
|
|
PoolObjectAuth vm_perms;
|
|
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
|
|
VirtualMachine * vm;
|
|
|
|
int rc;
|
|
string error_str;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
string str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse NIC template
|
|
// -------------------------------------------------------------------------
|
|
|
|
rc = tmpl.parse_str_or_xml(str_tmpl, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(INTERNAL, error_str, att);
|
|
return;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation, restricted attributes & check quotas
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, &tmpl, att, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
vm = vmpool->get(id, true);
|
|
|
|
if (vm == 0)
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(PoolObjectSQL::VM),id),
|
|
att);
|
|
return;
|
|
}
|
|
|
|
vm->get_permissions(vm_perms);
|
|
|
|
vm->unlock();
|
|
|
|
RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
|
|
|
|
if (att.uid != UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID)
|
|
{
|
|
string aname;
|
|
|
|
if (tmpl.check(aname))
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "NIC includes a restricted attribute " << aname;
|
|
|
|
failure_response(AUTHORIZATION,
|
|
authorization_error(oss.str(), att),
|
|
att);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( quota_authorization(&tmpl, Quotas::NETWORK, att_quota) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->attach_nic(id, &tmpl, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
quota_rollback(&tmpl, Quotas::NETWORK, att_quota);
|
|
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineDetachNic::request_execute(
|
|
xmlrpc_c::paramList const& paramList,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
DispatchManager * dm = nd.get_dm();
|
|
|
|
int rc;
|
|
string error_str;
|
|
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
int nic_id = xmlrpc_c::value_int(paramList.getInt(2));
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Authorize the operation
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc = dm->detach_nic(id, nic_id, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
failure_response(ACTION,
|
|
request_error(error_str, ""),
|
|
att);
|
|
}
|
|
else
|
|
{
|
|
success_response(id, att);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachineRecover::request_execute(
|
|
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
|
|
{
|
|
int id = xmlrpc_c::value_int(paramList.getInt(1));
|
|
bool success = xmlrpc_c::value_boolean(paramList.getBoolean(2));
|
|
|
|
VirtualMachine * vm;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
LifeCycleManager* lcm = nd.get_lcm();
|
|
|
|
if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((vm = get_vm(id, att)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(vm->get_state() != VirtualMachine::ACTIVE)
|
|
{
|
|
failure_response(ACTION,
|
|
request_error("Wrong state to perform action",""),
|
|
att);
|
|
|
|
vm->unlock();
|
|
return;
|
|
}
|
|
|
|
lcm->recover(vm, success);
|
|
|
|
success_response(id, att);
|
|
|
|
vm->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|