mirror of
https://github.com/OpenNebula/one.git
synced 2026-11-15 09:13:15 +09:00
3632 lines
87 KiB
C++
3632 lines
87 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2013, 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 <limits.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <queue>
|
|
|
|
#include "VirtualMachine.h"
|
|
#include "VirtualNetworkPool.h"
|
|
#include "ImagePool.h"
|
|
#include "NebulaLog.h"
|
|
#include "NebulaUtil.h"
|
|
|
|
#include "Nebula.h"
|
|
|
|
#include "vm_file_var_syntax.h"
|
|
#include "vm_var_syntax.h"
|
|
|
|
/* ************************************************************************** */
|
|
/* Virtual Machine :: Constructor/Destructor */
|
|
/* ************************************************************************** */
|
|
|
|
VirtualMachine::VirtualMachine(int id,
|
|
int _uid,
|
|
int _gid,
|
|
const string& _uname,
|
|
const string& _gname,
|
|
int umask,
|
|
VirtualMachineTemplate * _vm_template):
|
|
PoolObjectSQL(id,VM,"",_uid,_gid,_uname,_gname,table),
|
|
last_poll(0),
|
|
state(INIT),
|
|
lcm_state(LCM_INIT),
|
|
resched(0),
|
|
stime(time(0)),
|
|
etime(0),
|
|
deploy_id(""),
|
|
memory(0),
|
|
cpu(0),
|
|
net_tx(0),
|
|
net_rx(0),
|
|
history(0),
|
|
previous_history(0),
|
|
_log(0)
|
|
{
|
|
if (_vm_template != 0)
|
|
{
|
|
// This is a VM Template, with the root TEMPLATE.
|
|
_vm_template->set_xml_root("USER_TEMPLATE");
|
|
|
|
user_obj_template = _vm_template;
|
|
}
|
|
else
|
|
{
|
|
user_obj_template = new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
|
|
}
|
|
|
|
obj_template = new VirtualMachineTemplate;
|
|
|
|
set_umask(umask);
|
|
}
|
|
|
|
VirtualMachine::~VirtualMachine()
|
|
{
|
|
for (unsigned int i=0 ; i < history_records.size() ; i++)
|
|
{
|
|
delete history_records[i];
|
|
}
|
|
|
|
if (_log != 0)
|
|
{
|
|
delete _log;
|
|
}
|
|
|
|
if (obj_template != 0)
|
|
{
|
|
delete obj_template;
|
|
}
|
|
|
|
if (user_obj_template != 0)
|
|
{
|
|
delete user_obj_template;
|
|
}
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* Virtual Machine :: Database Access Functions */
|
|
/* ************************************************************************** */
|
|
|
|
const char * VirtualMachine::table = "vm_pool";
|
|
|
|
const char * VirtualMachine::db_names =
|
|
"oid, name, body, uid, gid, last_poll, state, lcm_state, "
|
|
"owner_u, group_u, other_u";
|
|
|
|
const char * VirtualMachine::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
|
|
"vm_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
|
|
"gid INTEGER, last_poll INTEGER, state INTEGER, lcm_state INTEGER, "
|
|
"owner_u INTEGER, group_u INTEGER, other_u INTEGER)";
|
|
|
|
|
|
const char * VirtualMachine::monit_table = "vm_monitoring";
|
|
|
|
const char * VirtualMachine::monit_db_names = "vmid, last_poll, body";
|
|
|
|
const char * VirtualMachine::monit_db_bootstrap = "CREATE TABLE IF NOT EXISTS "
|
|
"vm_monitoring (vmid INTEGER, last_poll INTEGER, body MEDIUMTEXT, "
|
|
"PRIMARY KEY(vmid, last_poll))";
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::select(SqlDB * db)
|
|
{
|
|
ostringstream oss;
|
|
ostringstream ose;
|
|
|
|
string system_dir;
|
|
int rc;
|
|
int last_seq;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
// Rebuild the VirtualMachine object
|
|
rc = PoolObjectSQL::select(db);
|
|
|
|
if( rc != 0 )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
//Get History Records. Current history is built in from_xml() (if any).
|
|
if( hasHistory() )
|
|
{
|
|
last_seq = history->seq - 1;
|
|
|
|
for (int i = last_seq; i >= 0; i--)
|
|
{
|
|
History * hp;
|
|
|
|
hp = new History(oid, i);
|
|
rc = hp->select(db);
|
|
|
|
if ( rc != 0)
|
|
{
|
|
goto error_previous_history;
|
|
}
|
|
|
|
history_records[i] = hp;
|
|
|
|
if ( i == last_seq )
|
|
{
|
|
previous_history = hp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( state == DONE ) //Do not recreate dirs. They may be deleted
|
|
{
|
|
_log = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//Create support directories for this VM
|
|
//--------------------------------------------------------------------------
|
|
oss.str("");
|
|
oss << nd.get_vms_location() << oid;
|
|
|
|
mkdir(oss.str().c_str(), 0700);
|
|
chmod(oss.str().c_str(), 0700);
|
|
|
|
//--------------------------------------------------------------------------
|
|
//Create Log support for this VM
|
|
//--------------------------------------------------------------------------
|
|
try
|
|
{
|
|
Log::MessageType clevel;
|
|
NebulaLog::LogType log_system;
|
|
|
|
log_system = nd.get_log_system();
|
|
clevel = nd.get_debug_level();
|
|
|
|
switch(log_system)
|
|
{
|
|
case NebulaLog::FILE_TS:
|
|
case NebulaLog::FILE:
|
|
_log = new FileLog(nd.get_vm_log_filename(oid), clevel);
|
|
break;
|
|
|
|
case NebulaLog::SYSLOG:
|
|
_log = new SysLogResource(oid, obj_type, clevel);
|
|
break;
|
|
|
|
case NebulaLog::CERR:
|
|
_log = new CerrLog(clevel);
|
|
break;
|
|
|
|
default:
|
|
throw runtime_error("Unknown log system.");
|
|
break;
|
|
}
|
|
}
|
|
catch(exception &e)
|
|
{
|
|
ose << "Error creating log: " << e.what();
|
|
NebulaLog::log("ONE",Log::ERROR, ose);
|
|
|
|
_log = 0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_previous_history:
|
|
ose << "Cannot get previous history record (seq:" << history->seq
|
|
<< ") for VM id: " << oid;
|
|
|
|
log("ONE", Log::ERROR, ose);
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::insert(SqlDB * db, string& error_str)
|
|
{
|
|
int rc;
|
|
string name;
|
|
string prefix;
|
|
|
|
string value;
|
|
int ivalue;
|
|
float fvalue;
|
|
|
|
ostringstream oss;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Set a name if the VM has not got one and VM_ID
|
|
// ------------------------------------------------------------------------
|
|
|
|
oss << oid;
|
|
value = oss.str();
|
|
|
|
user_obj_template->erase("VMID");
|
|
obj_template->add("VMID", value);
|
|
|
|
user_obj_template->get("TEMPLATE_ID", value);
|
|
user_obj_template->erase("TEMPLATE_ID");
|
|
|
|
if (!value.empty())
|
|
{
|
|
obj_template->add("TEMPLATE_ID", value);
|
|
}
|
|
|
|
user_obj_template->get("NAME",name);
|
|
user_obj_template->erase("NAME");
|
|
|
|
user_obj_template->get("TEMPLATE_NAME", prefix);
|
|
user_obj_template->erase("TEMPLATE_NAME");
|
|
|
|
if (prefix.empty())
|
|
{
|
|
prefix = "one";
|
|
}
|
|
|
|
if (name.empty() == true)
|
|
{
|
|
oss.str("");
|
|
oss << prefix << "-" << oid;
|
|
name = oss.str();
|
|
}
|
|
|
|
if ( !PoolObjectSQL::name_is_valid(name, error_str) )
|
|
{
|
|
goto error_name;
|
|
}
|
|
|
|
this->name = name;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check for CPU, VCPU and MEMORY attributes
|
|
// ------------------------------------------------------------------------
|
|
|
|
if ( user_obj_template->get("MEMORY", ivalue) == false || ivalue <= 0 )
|
|
{
|
|
goto error_memory;
|
|
}
|
|
|
|
user_obj_template->erase("MEMORY");
|
|
obj_template->add("MEMORY", ivalue);
|
|
|
|
if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 )
|
|
{
|
|
goto error_cpu;
|
|
}
|
|
|
|
user_obj_template->erase("CPU");
|
|
obj_template->add("CPU", fvalue);
|
|
|
|
// VCPU is optional, first check if the attribute exists, then check it is
|
|
// an integer
|
|
user_obj_template->get("VCPU", value);
|
|
|
|
if ( value.empty() == false )
|
|
{
|
|
if ( user_obj_template->get("VCPU", ivalue) == false || ivalue <= 0 )
|
|
{
|
|
goto error_vcpu;
|
|
}
|
|
|
|
user_obj_template->erase("VCPU");
|
|
obj_template->add("VCPU", ivalue);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check the OS attribute
|
|
// ------------------------------------------------------------------------
|
|
|
|
rc = parse_os(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_os;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get network leases
|
|
// ------------------------------------------------------------------------
|
|
|
|
rc = get_network_leases(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_leases_rollback;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Get disk images
|
|
// ------------------------------------------------------------------------
|
|
|
|
rc = get_disk_images(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
// The get_disk_images method has an internal rollback for
|
|
// the acquired images, release_disk_images() would release all disks
|
|
goto error_leases_rollback;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse the context & requirements
|
|
// -------------------------------------------------------------------------
|
|
|
|
rc = parse_context(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_context;
|
|
}
|
|
|
|
rc = parse_requirements(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_requirements;
|
|
}
|
|
|
|
rc = automatic_requirements(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_requirements;
|
|
}
|
|
|
|
parse_graphics();
|
|
|
|
parse_well_known_attributes();
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Insert the VM
|
|
// ------------------------------------------------------------------------
|
|
|
|
rc = insert_replace(db, false, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_update;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_update:
|
|
goto error_rollback;
|
|
|
|
error_context:
|
|
goto error_rollback;
|
|
|
|
error_requirements:
|
|
goto error_rollback;
|
|
|
|
error_rollback:
|
|
release_disk_images();
|
|
|
|
error_leases_rollback:
|
|
release_network_leases();
|
|
goto error_common;
|
|
|
|
error_cpu:
|
|
error_str = "CPU attribute must be a positive float or integer value.";
|
|
goto error_common;
|
|
|
|
error_vcpu:
|
|
error_str = "VCPU attribute must be a positive integer value.";
|
|
goto error_common;
|
|
|
|
error_memory:
|
|
error_str = "MEMORY attribute must be a positive integer value.";
|
|
goto error_common;
|
|
|
|
error_os:
|
|
error_name:
|
|
error_common:
|
|
NebulaLog::log("ONE",Log::ERROR, error_str);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_os_file(VectorAttribute * os,
|
|
const string& base_name,
|
|
Image::ImageType base_type,
|
|
string& error_str)
|
|
{
|
|
vector<int> img_ids;
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ImagePool * ipool = nd.get_ipool();
|
|
Image * img = 0;
|
|
|
|
int img_id;
|
|
|
|
Image::ImageType type;
|
|
Image::ImageState state;
|
|
|
|
DatastorePool * ds_pool = nd.get_dspool();
|
|
Datastore * ds;
|
|
int ds_id;
|
|
|
|
string attr;
|
|
string base_name_ds = base_name + "_DS";
|
|
string base_name_id = base_name + "_DS_ID";
|
|
string base_name_source = base_name + "_DS_SOURCE";
|
|
string base_name_ds_id = base_name + "_DS_DSID";
|
|
string base_name_tm = base_name + "_DS_TM";
|
|
string base_name_cluster= base_name + "_DS_CLUSTER_ID";
|
|
|
|
string type_str;
|
|
|
|
attr = os->vector_value(base_name_ds.c_str());
|
|
|
|
if ( attr.empty() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( parse_file_attribute(attr, img_ids, error_str) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if ( img_ids.size() != 1 )
|
|
{
|
|
error_str = "Only one FILE variable can be used in: " + attr;
|
|
return -1;
|
|
}
|
|
|
|
img_id = img_ids.back();
|
|
|
|
img = ipool->get(img_id, true);
|
|
|
|
if ( img == 0 )
|
|
{
|
|
error_str = "Image no longer exists in attribute: " + attr;
|
|
return -1;
|
|
}
|
|
|
|
state = img->get_state();
|
|
|
|
ds_id = img->get_ds_id();
|
|
type = img->get_type();
|
|
|
|
os->remove(base_name);
|
|
|
|
os->replace(base_name_id, img->get_oid());
|
|
os->replace(base_name_source, img->get_source());
|
|
os->replace(base_name_ds_id, img->get_ds_id());
|
|
|
|
img->unlock();
|
|
|
|
type_str = Image::type_to_str(type);
|
|
|
|
if ( type != base_type )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << base_name << " needs an image of type "
|
|
<< Image::type_to_str(base_type) << " and not "
|
|
<< type_str;
|
|
|
|
error_str = oss.str();
|
|
return -1;
|
|
}
|
|
|
|
if ( state != Image::READY )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << type_str << " Image '" << img_id << " 'not in READY state.";
|
|
|
|
error_str = oss.str();
|
|
return -1;
|
|
}
|
|
|
|
ds = ds_pool->get(ds_id, true);
|
|
|
|
if ( ds == 0 )
|
|
{
|
|
error_str = "Associated datastore for image does not exist";
|
|
return -1;
|
|
}
|
|
|
|
os->replace(base_name_tm, ds->get_tm_mad());
|
|
|
|
if ( ds->get_cluster_id() != ClusterPool::NONE_CLUSTER_ID )
|
|
{
|
|
os->replace(base_name_cluster, ds->get_cluster_id());
|
|
}
|
|
|
|
ds->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::parse_os(string& error_str)
|
|
{
|
|
int num;
|
|
int rc;
|
|
|
|
vector<Attribute *> os_attr;
|
|
VectorAttribute * os;
|
|
|
|
vector<Attribute *>::iterator it;
|
|
|
|
num = user_obj_template->remove("OS", os_attr);
|
|
|
|
for (it=os_attr.begin(); it != os_attr.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
|
|
if ( num == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
else if ( num > 1 )
|
|
{
|
|
error_str = "Only one OS attribute can be defined.";
|
|
return -1;
|
|
}
|
|
|
|
os = dynamic_cast<VectorAttribute *>(os_attr[0]);
|
|
|
|
if ( os == 0 )
|
|
{
|
|
error_str = "Internal error parsing OS attribute.";
|
|
return -1;
|
|
}
|
|
|
|
rc = set_os_file(os, "KERNEL", Image::KERNEL, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
rc = set_os_file(os, "INITRD", Image::RAMDISK, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::parse_context(string& error_str)
|
|
{
|
|
int rc, num;
|
|
|
|
vector<Attribute *> array_context;
|
|
VectorAttribute * context;
|
|
VectorAttribute * context_parsed;
|
|
|
|
string * str;
|
|
string parsed;
|
|
string files_ds;
|
|
string files_ds_parsed;
|
|
|
|
ostringstream oss_parsed;
|
|
|
|
vector<int> img_ids;
|
|
|
|
num = obj_template->remove("CONTEXT", array_context);
|
|
|
|
if ( num == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
else if ( num > 1 )
|
|
{
|
|
error_str = "Only one CONTEXT attribute can be defined.";
|
|
goto error_cleanup;
|
|
}
|
|
|
|
context = dynamic_cast<VectorAttribute *>(array_context[0]);
|
|
|
|
if ( context == 0 )
|
|
{
|
|
error_str = "Wrong format for CONTEXT attribute.";
|
|
goto error_cleanup;
|
|
}
|
|
|
|
//Backup datastore files to parse them later
|
|
|
|
files_ds = context->vector_value("FILES_DS");
|
|
|
|
context->remove("FILES_DS");
|
|
|
|
// ----------- Inject Network context in marshalled string ----------------
|
|
|
|
bool net_context;
|
|
context->vector_value("NETWORK", net_context);
|
|
|
|
if (net_context)
|
|
{
|
|
vector<Attribute * > v_attributes;
|
|
VectorAttribute * vatt;
|
|
|
|
int num_vatts = obj_template->get("NIC", v_attributes);
|
|
|
|
for(int i=0; i<num_vatts; i++)
|
|
{
|
|
vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
|
|
|
|
if ( vatt == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string name = vatt->vector_value("NETWORK");
|
|
string ip = vatt->vector_value("IP");
|
|
string mac = vatt->vector_value("MAC");
|
|
string ip6 = vatt->vector_value("IP6_GLOBAL");
|
|
string nic_id = vatt->vector_value("NIC_ID");
|
|
|
|
ostringstream var;
|
|
ostringstream val;
|
|
|
|
var << "ETH" << nic_id << "_IP";
|
|
context->replace(var.str(), ip);
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_MAC";
|
|
context->replace(var.str(), mac);
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_NETWORK";
|
|
val << "$NETWORK[NETWORK_ADDRESS, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_MASK";
|
|
val << "$NETWORK[NETWORK_MASK, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_GATEWAY";
|
|
val << "$NETWORK[GATEWAY, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_GATEWAY";
|
|
val << "$NETWORK[GATEWAY, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_DNS";
|
|
val << "$NETWORK[DNS, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
if (!ip6.empty())
|
|
{
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_IP6";
|
|
context->replace(var.str(), ip6);
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_GATEWAY6";
|
|
val << "$NETWORK[GATEWAY6, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
|
|
var.str(""); val.str("");
|
|
|
|
var << "ETH" << nic_id << "_CONTEXT_FORCE_IPV4";
|
|
val << "$NETWORK[CONTEXT_FORCE_IPV4, NETWORK=\"" << name << "\"]";
|
|
context->replace(var.str(), val.str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse CONTEXT variables & free vector attributes
|
|
// -------------------------------------------------------------------------
|
|
|
|
str = context->marshall(" @^_^@ ");
|
|
|
|
if (str == 0)
|
|
{
|
|
error_str = "Cannot marshall CONTEXT";
|
|
goto error_cleanup;
|
|
}
|
|
|
|
rc = parse_template_attribute(*str, parsed, error_str);
|
|
|
|
delete str;
|
|
|
|
if (rc != 0)
|
|
{
|
|
goto error_cleanup;
|
|
}
|
|
|
|
for (int i = 0; i < num ; i++)
|
|
{
|
|
if (array_context[i] != 0)
|
|
{
|
|
delete array_context[i];
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse FILE_DS variables
|
|
// -------------------------------------------------------------------------
|
|
|
|
if (!files_ds.empty())
|
|
{
|
|
if ( parse_file_attribute(files_ds, img_ids, error_str) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if ( img_ids.size() > 0 )
|
|
{
|
|
vector<int>::iterator it;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ImagePool * ipool = nd.get_ipool();
|
|
Image * img = 0;
|
|
|
|
Image::ImageType type;
|
|
Image::ImageState state;
|
|
|
|
for ( it=img_ids.begin() ; it < img_ids.end(); it++ )
|
|
{
|
|
img = ipool->get(*it, true);
|
|
|
|
if ( img != 0 )
|
|
{
|
|
oss_parsed << img->get_source() << ":'"
|
|
<< img->get_name() << "' ";
|
|
|
|
type = img->get_type();
|
|
state = img->get_state();
|
|
|
|
img->unlock();
|
|
|
|
if (type != Image::CONTEXT)
|
|
{
|
|
error_str = "Only images of type CONTEXT can be used in"
|
|
" FILE_DS attribute.";
|
|
return -1;
|
|
}
|
|
|
|
if ( state != Image::READY )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << Image::type_to_str(type)
|
|
<< " Image '" << *it << "' not in READY state.";
|
|
|
|
error_str = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
files_ds_parsed = oss_parsed.str();
|
|
|
|
context_parsed = new VectorAttribute("CONTEXT");
|
|
context_parsed->unmarshall(parsed," @^_^@ ");
|
|
|
|
if ( !files_ds_parsed.empty() )
|
|
{
|
|
context_parsed->replace("FILES_DS", files_ds_parsed);
|
|
}
|
|
|
|
obj_template->set(context_parsed);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// OneGate URL
|
|
// -------------------------------------------------------------------------
|
|
|
|
bool token;
|
|
context_parsed->vector_value("TOKEN", token);
|
|
|
|
if (token)
|
|
{
|
|
string onegate_url;
|
|
context_parsed->vector_value("ONEGATE_URL");
|
|
|
|
if (onegate_url.empty())
|
|
{
|
|
string endpoint;
|
|
endpoint = context_parsed->vector_value("ONEGATE_ENDPOINT");
|
|
|
|
if ( endpoint.empty() )
|
|
{
|
|
Nebula::instance().get_configuration_attribute(
|
|
"ONEGATE_ENDPOINT", endpoint);
|
|
}
|
|
|
|
if ( endpoint.empty() )
|
|
{
|
|
error_str = "CONTEXT/TOKEN set, but OneGate endpoint was not "
|
|
"defined in oned.conf or CONTEXT.";
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
ostringstream oss;
|
|
oss << endpoint << "/vm/" << oid;
|
|
|
|
context_parsed->replace("ONEGATE_URL", oss.str());
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
error_cleanup:
|
|
for (int i = 0; i < num ; i++)
|
|
{
|
|
if (array_context[i] != 0)
|
|
{
|
|
delete array_context[i];
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::parse_graphics()
|
|
{
|
|
int num;
|
|
|
|
vector<Attribute *> array_graphics;
|
|
VectorAttribute * graphics;
|
|
|
|
vector<Attribute *>::iterator it;
|
|
|
|
num = user_obj_template->remove("GRAPHICS", array_graphics);
|
|
|
|
for (it=array_graphics.begin(); it != array_graphics.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
|
|
if ( num == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
graphics = dynamic_cast<VectorAttribute * >(array_graphics[0]);
|
|
|
|
if ( graphics == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
string port = graphics->vector_value("PORT");
|
|
|
|
if ( port.empty() )
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ostringstream oss;
|
|
istringstream iss;
|
|
|
|
int base_port;
|
|
string base_port_s;
|
|
|
|
int limit = 65535;
|
|
|
|
nd.get_configuration_attribute("VNC_BASE_PORT",base_port_s);
|
|
iss.str(base_port_s);
|
|
iss >> base_port;
|
|
|
|
oss << ( base_port + ( oid % (limit - base_port) ));
|
|
graphics->replace("PORT", oss.str());
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::parse_requirements(string& error_str)
|
|
{
|
|
int rc, num;
|
|
|
|
vector<Attribute *> array_reqs;
|
|
SingleAttribute * reqs;
|
|
|
|
string parsed;
|
|
|
|
num = user_obj_template->remove("SCHED_REQUIREMENTS", array_reqs);
|
|
|
|
if ( num == 0 ) // Compatibility with old REQUIREMENTS attribute
|
|
{
|
|
num = user_obj_template->remove("REQUIREMENTS", array_reqs);
|
|
}
|
|
else
|
|
{
|
|
user_obj_template->erase("REQUIREMENTS");
|
|
}
|
|
|
|
if ( num == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
else if ( num > 1 )
|
|
{
|
|
error_str = "Only one SCHED_REQUIREMENTS attribute can be defined.";
|
|
goto error_cleanup;
|
|
}
|
|
|
|
reqs = dynamic_cast<SingleAttribute *>(array_reqs[0]);
|
|
|
|
if ( reqs == 0 )
|
|
{
|
|
error_str = "Wrong format for SCHED_REQUIREMENTS attribute.";
|
|
goto error_cleanup;
|
|
}
|
|
|
|
rc = parse_template_attribute(reqs->value(), parsed, error_str);
|
|
|
|
if ( rc == 0 )
|
|
{
|
|
SingleAttribute * reqs_parsed;
|
|
|
|
reqs_parsed = new SingleAttribute("SCHED_REQUIREMENTS",parsed);
|
|
user_obj_template->set(reqs_parsed);
|
|
}
|
|
|
|
/* --- Delete old requirements attribute --- */
|
|
|
|
delete array_reqs[0];
|
|
|
|
return rc;
|
|
|
|
error_cleanup:
|
|
for (int i = 0; i < num ; i++)
|
|
{
|
|
if (array_reqs[i] != 0)
|
|
{
|
|
delete array_reqs[i];
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void VirtualMachine::parse_well_known_attributes()
|
|
{
|
|
/*
|
|
* List of meaningful attributes, used in other places and expected in
|
|
* obj_template:
|
|
*
|
|
* DISK
|
|
* NIC
|
|
* VCPU
|
|
* MEMORY
|
|
* CPU
|
|
* CONTEXT
|
|
* OS
|
|
* GRAPHICS
|
|
*
|
|
* INPUT
|
|
* FEATURES
|
|
* RAW
|
|
*/
|
|
|
|
vector<Attribute *> v_attr;
|
|
vector<Attribute *>::iterator it;
|
|
|
|
string names[] = {"INPUT", "FEATURES", "RAW"};
|
|
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
v_attr.clear();
|
|
|
|
user_obj_template->remove(names[i], v_attr);
|
|
|
|
for (it=v_attr.begin(); it != v_attr.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static int check_and_set_cluster_id(const char * id_name,
|
|
VectorAttribute * vatt,
|
|
string& cluster_id)
|
|
{
|
|
string vatt_cluster_id;
|
|
|
|
vatt_cluster_id = vatt->vector_value(id_name);
|
|
|
|
if ( !vatt_cluster_id.empty() )
|
|
{
|
|
if ( cluster_id.empty() )
|
|
{
|
|
cluster_id = vatt_cluster_id;
|
|
}
|
|
else if ( cluster_id != vatt_cluster_id )
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::automatic_requirements(string& error_str)
|
|
{
|
|
int num_vatts;
|
|
vector<Attribute * > v_attributes;
|
|
VectorAttribute * vatt;
|
|
|
|
ostringstream oss;
|
|
string requirements;
|
|
string cluster_id = "";
|
|
string hypervisor;
|
|
|
|
int incomp_id;
|
|
int rc;
|
|
|
|
// Get cluster id from all DISK vector attributes (IMAGE Datastore)
|
|
|
|
num_vatts = obj_template->get("DISK",v_attributes);
|
|
|
|
for(int i=0; i<num_vatts; i++)
|
|
{
|
|
vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
|
|
|
|
if ( vatt == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rc = check_and_set_cluster_id("CLUSTER_ID", vatt, cluster_id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_disk;
|
|
}
|
|
}
|
|
|
|
// Get cluster id from the KERNEL and INITRD (FILE Datastores)
|
|
|
|
v_attributes.clear();
|
|
num_vatts = obj_template->get("OS",v_attributes);
|
|
|
|
if ( num_vatts > 0 )
|
|
{
|
|
vatt = dynamic_cast<VectorAttribute * >(v_attributes[0]);
|
|
|
|
if ( vatt != 0 )
|
|
{
|
|
rc = check_and_set_cluster_id("KERNEL_CLUSTER_ID", vatt, cluster_id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_kernel;
|
|
}
|
|
|
|
rc = check_and_set_cluster_id("INITRD_CLUSTER_ID", vatt, cluster_id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_initrd;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get cluster id from all NIC vector attributes
|
|
|
|
v_attributes.clear();
|
|
num_vatts = obj_template->get("NIC",v_attributes);
|
|
|
|
for(int i=0; i<num_vatts; i++)
|
|
{
|
|
vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
|
|
|
|
if ( vatt == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rc = check_and_set_cluster_id("CLUSTER_ID", vatt, cluster_id);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_nic;
|
|
}
|
|
}
|
|
|
|
if ( !cluster_id.empty() )
|
|
{
|
|
oss << "CLUSTER_ID = " << cluster_id;
|
|
}
|
|
|
|
if (static_cast<VirtualMachineTemplate*>(obj_template)->get_hybrid_hypervisor(hypervisor))
|
|
{
|
|
if ( !cluster_id.empty() )
|
|
{
|
|
oss << " || ";
|
|
}
|
|
|
|
oss << "HYPERVISOR = " << hypervisor;
|
|
}
|
|
|
|
if ( !cluster_id.empty() || !hypervisor.empty() )
|
|
{
|
|
obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_disk:
|
|
oss << "Incompatible clusters in DISK. Datastore for DISK "<< incomp_id
|
|
<< " is not the same as the one used by other VM elements (cluster "
|
|
<< cluster_id << ")";
|
|
goto error_common;
|
|
|
|
error_kernel:
|
|
oss << "Incompatible cluster in KERNEL datastore, it should be in cluster "
|
|
<< cluster_id << ".";
|
|
goto error_common;
|
|
|
|
error_initrd:
|
|
oss << "Incompatible cluster in INITRD datastore, it should be in cluster "
|
|
<< cluster_id << ".";
|
|
goto error_common;
|
|
|
|
error_nic:
|
|
oss << "Incompatible clusters in NIC. Network for NIC "<< incomp_id
|
|
<< " is not the same as the one used by other VM elements (cluster "
|
|
<< cluster_id << ")";
|
|
goto error_common;
|
|
|
|
error_common:
|
|
error_str = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
|
|
{
|
|
ostringstream oss;
|
|
int rc;
|
|
|
|
string xml_body;
|
|
char * sql_name;
|
|
char * sql_xml;
|
|
|
|
sql_name = db->escape_str(name.c_str());
|
|
|
|
if ( sql_name == 0 )
|
|
{
|
|
goto error_generic;
|
|
}
|
|
|
|
sql_xml = db->escape_str(to_xml(xml_body).c_str());
|
|
|
|
if ( sql_xml == 0 )
|
|
{
|
|
goto error_body;
|
|
}
|
|
|
|
if ( validate_xml(sql_xml) != 0 )
|
|
{
|
|
goto error_xml;
|
|
}
|
|
|
|
if(replace)
|
|
{
|
|
oss << "REPLACE";
|
|
}
|
|
else
|
|
{
|
|
oss << "INSERT";
|
|
}
|
|
|
|
oss << " INTO " << table << " ("<< db_names <<") VALUES ("
|
|
<< oid << ","
|
|
<< "'" << sql_name << "',"
|
|
<< "'" << sql_xml << "',"
|
|
<< uid << ","
|
|
<< gid << ","
|
|
<< last_poll << ","
|
|
<< state << ","
|
|
<< lcm_state << ","
|
|
<< owner_u << ","
|
|
<< group_u << ","
|
|
<< other_u << ")";
|
|
|
|
db->free_str(sql_name);
|
|
db->free_str(sql_xml);
|
|
|
|
rc = db->exec(oss);
|
|
|
|
return rc;
|
|
|
|
error_xml:
|
|
db->free_str(sql_name);
|
|
db->free_str(sql_xml);
|
|
|
|
error_str = "Error transforming the VM to XML.";
|
|
|
|
goto error_common;
|
|
|
|
error_body:
|
|
db->free_str(sql_name);
|
|
goto error_generic;
|
|
|
|
error_generic:
|
|
error_str = "Error inserting VM in DB.";
|
|
error_common:
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::update_monitoring(SqlDB * db)
|
|
{
|
|
ostringstream oss;
|
|
int rc;
|
|
|
|
string xml_body;
|
|
string error_str;
|
|
char * sql_xml;
|
|
|
|
sql_xml = db->escape_str(to_xml(xml_body).c_str());
|
|
|
|
if ( sql_xml == 0 )
|
|
{
|
|
goto error_body;
|
|
}
|
|
|
|
if ( validate_xml(sql_xml) != 0 )
|
|
{
|
|
goto error_xml;
|
|
}
|
|
|
|
oss << "INSERT INTO " << monit_table << " ("<< monit_db_names <<") VALUES ("
|
|
<< oid << ","
|
|
<< last_poll << ","
|
|
<< "'" << sql_xml << "')";
|
|
|
|
db->free_str(sql_xml);
|
|
|
|
rc = db->exec(oss);
|
|
|
|
return rc;
|
|
|
|
error_xml:
|
|
db->free_str(sql_xml);
|
|
|
|
error_str = "could not transform the VM to XML.";
|
|
|
|
goto error_common;
|
|
|
|
error_body:
|
|
error_str = "could not insert the VM in the DB.";
|
|
|
|
error_common:
|
|
oss.str("");
|
|
oss << "Error updating VM monitoring information, " << error_str;
|
|
|
|
NebulaLog::log("ONE",Log::ERROR, oss);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::add_history(
|
|
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)
|
|
{
|
|
ostringstream os;
|
|
int seq;
|
|
string vm_xml;
|
|
|
|
if (history == 0)
|
|
{
|
|
seq = 0;
|
|
}
|
|
else
|
|
{
|
|
seq = history->seq + 1;
|
|
|
|
previous_history = history;
|
|
}
|
|
|
|
to_xml_extended(vm_xml, 0);
|
|
|
|
history = new History(oid,
|
|
seq,
|
|
hid,
|
|
hostname,
|
|
cid,
|
|
vmm_mad,
|
|
vnm_mad,
|
|
tm_mad,
|
|
ds_location,
|
|
ds_id,
|
|
vm_xml);
|
|
|
|
history_records.push_back(history);
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::cp_history()
|
|
{
|
|
History * htmp;
|
|
string vm_xml;
|
|
|
|
if (history == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
to_xml_extended(vm_xml, 0);
|
|
|
|
htmp = new History(oid,
|
|
history->seq + 1,
|
|
history->hid,
|
|
history->hostname,
|
|
history->cid,
|
|
history->vmm_mad_name,
|
|
history->vnm_mad_name,
|
|
history->tm_mad_name,
|
|
history->ds_location,
|
|
history->ds_id,
|
|
vm_xml);
|
|
|
|
previous_history = history;
|
|
history = htmp;
|
|
|
|
history_records.push_back(history);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::cp_previous_history()
|
|
{
|
|
History * htmp;
|
|
string vm_xml;
|
|
|
|
if ( previous_history == 0 || history == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
to_xml_extended(vm_xml, 0);
|
|
|
|
htmp = new History(oid,
|
|
history->seq + 1,
|
|
previous_history->hid,
|
|
previous_history->hostname,
|
|
previous_history->cid,
|
|
previous_history->vmm_mad_name,
|
|
previous_history->vnm_mad_name,
|
|
previous_history->tm_mad_name,
|
|
previous_history->ds_location,
|
|
previous_history->ds_id,
|
|
vm_xml);
|
|
|
|
previous_history = history;
|
|
history = htmp;
|
|
|
|
history_records.push_back(history);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
|
|
{
|
|
istringstream iss;
|
|
float fcpu;
|
|
|
|
if ((get_template_attribute("MEMORY",memory) == false) ||
|
|
(get_template_attribute("CPU",fcpu) == false))
|
|
{
|
|
cpu = 0;
|
|
memory = 0;
|
|
disk = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
cpu = (int) (fcpu * 100);//now in 100%
|
|
memory = memory * 1024; //now in Kilobytes
|
|
disk = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::check_resize (
|
|
float cpu, int memory, int vcpu, string& error_str)
|
|
{
|
|
if (cpu < 0)
|
|
{
|
|
error_str = "CPU must be a positive float or integer value.";
|
|
return -1;
|
|
}
|
|
|
|
if (memory < 0)
|
|
{
|
|
error_str = "MEMORY must be a positive integer value.";
|
|
return -1;
|
|
}
|
|
|
|
if (vcpu < 0)
|
|
{
|
|
error_str = "VCPU must be a positive integer value.";
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::resize(float cpu, int memory, int vcpu, string& error_str)
|
|
{
|
|
ostringstream oss;
|
|
|
|
int rc = check_resize(cpu, memory, vcpu, error_str);
|
|
|
|
if (rc != 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
if (cpu > 0)
|
|
{
|
|
oss << cpu;
|
|
replace_template_attribute("CPU", oss.str());
|
|
oss.str("");
|
|
}
|
|
|
|
if (memory > 0)
|
|
{
|
|
oss << memory;
|
|
replace_template_attribute("MEMORY", oss.str());
|
|
oss.str("");
|
|
}
|
|
|
|
if (vcpu > 0)
|
|
{
|
|
oss << vcpu;
|
|
replace_template_attribute("VCPU", oss.str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
static void assign_disk_targets(queue<pair <string, VectorAttribute *> >& _queue,
|
|
set<string>& used_targets)
|
|
{
|
|
int index = 0;
|
|
string target;
|
|
|
|
pair <string, VectorAttribute *> disk_pair;
|
|
|
|
while (_queue.size() > 0 )
|
|
{
|
|
disk_pair = _queue.front();
|
|
index = 0;
|
|
|
|
do
|
|
{
|
|
target = disk_pair.first + static_cast<char>(('a'+ index));
|
|
index++;
|
|
}
|
|
while ( used_targets.count(target) > 0 && index < 26 );
|
|
|
|
disk_pair.second->replace("TARGET", target);
|
|
used_targets.insert(target);
|
|
|
|
_queue.pop();
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_disk_images(string& error_str)
|
|
{
|
|
int num_disks, num_context, rc;
|
|
vector<Attribute *> disks;
|
|
vector<Attribute *> context_disks;
|
|
ImagePool * ipool;
|
|
VectorAttribute * disk;
|
|
vector<int> acquired_images;
|
|
|
|
int image_id;
|
|
string dev_prefix;
|
|
string target;
|
|
|
|
queue<pair <string, VectorAttribute *> > os_disk;
|
|
queue<pair <string, VectorAttribute *> > cdrom_disks;
|
|
queue<pair <string, VectorAttribute *> > datablock_disks;
|
|
|
|
set<string> used_targets;
|
|
|
|
ostringstream oss;
|
|
Image::ImageType img_type;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
ipool = nd.get_ipool();
|
|
|
|
vector<Attribute*>::iterator it;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// The context is the first of the cdroms
|
|
// -------------------------------------------------------------------------
|
|
num_context = user_obj_template->remove("CONTEXT", context_disks);
|
|
num_disks = user_obj_template->remove("DISK", disks);
|
|
|
|
for (it=context_disks.begin(); it != context_disks.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
|
|
for (it=disks.begin(); it != disks.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
|
|
if ( num_disks > 20 )
|
|
{
|
|
goto error_max_disks;
|
|
}
|
|
|
|
if ( num_context > 0 )
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(context_disks[0]);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
target = disk->vector_value("TARGET");
|
|
|
|
if ( !target.empty() )
|
|
{
|
|
used_targets.insert(target);
|
|
}
|
|
else
|
|
{
|
|
cdrom_disks.push(make_pair(ipool->default_dev_prefix(), disk));
|
|
}
|
|
|
|
// Disk IDs are 0..num-1, context disk is is num
|
|
disk->replace("DISK_ID", num_disks);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Set DISK attributes & Targets
|
|
// -------------------------------------------------------------------------
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rc = ipool->disk_attribute(oid,
|
|
disk,
|
|
i,
|
|
img_type,
|
|
dev_prefix,
|
|
uid,
|
|
image_id,
|
|
error_str);
|
|
if (rc == 0 )
|
|
{
|
|
acquired_images.push_back(image_id);
|
|
|
|
target = disk->vector_value("TARGET");
|
|
|
|
if ( !target.empty() )
|
|
{
|
|
if ( used_targets.insert(target).second == false )
|
|
{
|
|
goto error_duplicated_target;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(img_type)
|
|
{
|
|
case Image::OS:
|
|
// The first OS disk gets the first device (a),
|
|
// other OS's will be managed as DATABLOCK's
|
|
if ( os_disk.empty() )
|
|
{
|
|
os_disk.push( make_pair(dev_prefix, disk) );
|
|
}
|
|
else
|
|
{
|
|
datablock_disks.push( make_pair(dev_prefix, disk) );
|
|
}
|
|
break;
|
|
|
|
case Image::CDROM:
|
|
cdrom_disks.push( make_pair(dev_prefix, disk) );
|
|
break;
|
|
|
|
case Image::DATABLOCK:
|
|
datablock_disks.push( make_pair(dev_prefix, disk) );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oss << "DISK " << i << ": " << error_str;
|
|
error_str = oss.str();
|
|
|
|
goto error_common;
|
|
}
|
|
}
|
|
|
|
assign_disk_targets(os_disk, used_targets);
|
|
assign_disk_targets(cdrom_disks, used_targets);
|
|
assign_disk_targets(datablock_disks, used_targets);
|
|
|
|
return 0;
|
|
|
|
error_max_disks:
|
|
error_str = "Exceeded the maximum number of disks (20)";
|
|
return -1;
|
|
|
|
error_duplicated_target:
|
|
oss << "Two disks have defined the same target " << target;
|
|
error_str = oss.str();
|
|
|
|
error_common:
|
|
ImageManager * imagem = nd.get_imagem();
|
|
|
|
vector<int>::iterator img_it;
|
|
|
|
for ( img_it=acquired_images.begin() ; img_it < acquired_images.end(); img_it++ )
|
|
{
|
|
imagem->release_image(oid, *img_it, false);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::get_disk_info(int& max_disk_id,
|
|
set<string>& used_targets)
|
|
{
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
string target;
|
|
|
|
int disk_id;
|
|
int num_disks;
|
|
|
|
max_disk_id = -1;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
target = disk->vector_value("TARGET");
|
|
|
|
if ( !target.empty() )
|
|
{
|
|
used_targets.insert(target);
|
|
}
|
|
|
|
disk->vector_value("DISK_ID", disk_id);
|
|
|
|
if ( disk_id > max_disk_id )
|
|
{
|
|
max_disk_id = disk_id;
|
|
}
|
|
}
|
|
|
|
disks.clear();
|
|
|
|
if ( obj_template->get("CONTEXT", disks) > 0 )
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[0]);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
target = disk->vector_value("TARGET");
|
|
|
|
if ( !target.empty() )
|
|
{
|
|
used_targets.insert(target);
|
|
}
|
|
|
|
disk->vector_value("DISK_ID", disk_id);
|
|
|
|
if ( disk_id > max_disk_id )
|
|
{
|
|
max_disk_id = disk_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute * VirtualMachine::set_up_attach_disk(
|
|
int vm_id,
|
|
VirtualMachineTemplate * tmpl,
|
|
set<string>& used_targets,
|
|
int max_disk_id,
|
|
int uid,
|
|
int& image_id,
|
|
string& error_str)
|
|
{
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * new_disk;
|
|
|
|
string target;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
ImagePool * ipool = nd.get_ipool();
|
|
ImageManager* imagem = nd.get_imagem();
|
|
|
|
string dev_prefix;
|
|
Image::ImageType img_type;
|
|
|
|
image_id = -1;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the DISK attribute from the template
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( tmpl->get("DISK", disks) != 1 )
|
|
{
|
|
error_str = "The template must contain one DISK attribute";
|
|
return 0;
|
|
}
|
|
|
|
new_disk = dynamic_cast<VectorAttribute * >(disks[0]);
|
|
|
|
if ( new_disk == 0 )
|
|
{
|
|
error_str = "Internal error parsing DISK attribute";
|
|
return 0;
|
|
}
|
|
|
|
new_disk = new_disk->clone();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Acquire the new disk image
|
|
// -------------------------------------------------------------------------
|
|
|
|
int rc = ipool->disk_attribute(vm_id,
|
|
new_disk,
|
|
max_disk_id + 1,
|
|
img_type,
|
|
dev_prefix,
|
|
uid,
|
|
image_id,
|
|
error_str);
|
|
if ( rc != 0 )
|
|
{
|
|
delete new_disk;
|
|
return 0;
|
|
}
|
|
|
|
target = new_disk->vector_value("TARGET");
|
|
|
|
if ( !target.empty() )
|
|
{
|
|
if ( used_targets.insert(target).second == false )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Target " << target << " is already in use.";
|
|
error_str = oss.str();
|
|
|
|
imagem->release_image(vm_id, image_id, false);
|
|
|
|
delete new_disk;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
queue<pair <string, VectorAttribute *> > disks_queue;
|
|
|
|
disks_queue.push(make_pair(dev_prefix, new_disk));
|
|
|
|
assign_disk_targets(disks_queue, used_targets);
|
|
}
|
|
|
|
return new_disk;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_attach_disk(int disk_id)
|
|
{
|
|
VectorAttribute * disk;
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
disk->replace("ATTACH", "YES");
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute* VirtualMachine::get_attach_disk()
|
|
{
|
|
int num_disks;
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( disk->vector_value("ATTACH") == "YES" )
|
|
{
|
|
return disk;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::clear_attach_disk()
|
|
{
|
|
int num_disks;
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( disk->vector_value("ATTACH") == "YES" )
|
|
{
|
|
disk->remove("ATTACH");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute * VirtualMachine::delete_attach_disk()
|
|
{
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
int num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( disk->vector_value("ATTACH") == "YES" )
|
|
{
|
|
return static_cast<VectorAttribute * >(obj_template->remove(disk));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool VirtualMachine::isVolatile(const VectorAttribute * disk)
|
|
{
|
|
string type = disk->vector_value("TYPE");
|
|
|
|
one_util::toupper(type);
|
|
|
|
return ( type == "SWAP" || type == "FS");
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool VirtualMachine::isVolatile(const Template * tmpl)
|
|
{
|
|
vector<const Attribute*> disks;
|
|
int num_disks = tmpl->get("DISK", disks);
|
|
|
|
for (int i = 0 ; i < num_disks ; i++)
|
|
{
|
|
const VectorAttribute * disk = dynamic_cast<const VectorAttribute*>(disks[i]);
|
|
|
|
if (disk == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (VirtualMachine::isVolatile(disk))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
long long VirtualMachine::get_volatile_disk_size(Template * tmpl)
|
|
{
|
|
long long size = 0;
|
|
|
|
vector<const Attribute*> disks;
|
|
int num_disks = tmpl->get("DISK", disks);
|
|
|
|
if (num_disks == 0)
|
|
{
|
|
return size;
|
|
}
|
|
|
|
for (int i = 0 ; i < num_disks ; i++)
|
|
{
|
|
long long disk_size;
|
|
const VectorAttribute * disk = dynamic_cast<const VectorAttribute*>(disks[i]);
|
|
|
|
if (disk == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!VirtualMachine::isVolatile(disk))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (disk->vector_value("SIZE", disk_size) == 0)
|
|
{
|
|
size += disk_size;
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::get_nic_info(int& max_nic_id)
|
|
{
|
|
vector<Attribute *> nics;
|
|
VectorAttribute * nic;
|
|
|
|
int nic_id;
|
|
int num_nics;
|
|
|
|
max_nic_id = -1;
|
|
|
|
num_nics = obj_template->get("NIC", nics);
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
nic = dynamic_cast<VectorAttribute * >(nics[i]);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
nic->vector_value("NIC_ID", nic_id);
|
|
|
|
if ( nic_id > max_nic_id )
|
|
{
|
|
max_nic_id = nic_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute * VirtualMachine::set_up_attach_nic(
|
|
int vm_id,
|
|
VirtualMachineTemplate * tmpl,
|
|
int max_nic_id,
|
|
int uid,
|
|
int& network_id,
|
|
string& error_str)
|
|
{
|
|
vector<Attribute *> nics;
|
|
VectorAttribute * new_nic;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
VirtualNetworkPool* vnpool = nd.get_vnpool();
|
|
|
|
network_id = -1;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get the NIC attribute from the template
|
|
// -------------------------------------------------------------------------
|
|
|
|
if ( tmpl->get("NIC", nics) != 1 )
|
|
{
|
|
error_str = "The template must contain one NIC attribute";
|
|
return 0;
|
|
}
|
|
|
|
new_nic = dynamic_cast<VectorAttribute * >(nics[0]);
|
|
|
|
if ( new_nic == 0 )
|
|
{
|
|
error_str = "Internal error parsing NIC attribute";
|
|
return 0;
|
|
}
|
|
|
|
new_nic = new_nic->clone();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Acquire the new network lease
|
|
// -------------------------------------------------------------------------
|
|
|
|
int rc = vnpool->nic_attribute(new_nic, max_nic_id+1, uid, vm_id, error_str);
|
|
|
|
if ( rc == -1 ) //-2 is not using a pre-defined network
|
|
{
|
|
delete new_nic;
|
|
return 0;
|
|
}
|
|
|
|
return new_nic;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::clear_attach_nic()
|
|
{
|
|
int num_nics;
|
|
vector<Attribute *> nics;
|
|
VectorAttribute * nic;
|
|
|
|
num_nics = obj_template->get("NIC", nics);
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
nic = dynamic_cast<VectorAttribute * >(nics[i]);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( nic->vector_value("ATTACH") == "YES" )
|
|
{
|
|
nic->remove("ATTACH");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute * VirtualMachine::delete_attach_nic()
|
|
{
|
|
vector<Attribute *> nics;
|
|
VectorAttribute * nic;
|
|
|
|
int num_nics = obj_template->get("NIC", nics);
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
nic = dynamic_cast<VectorAttribute * >(nics[i]);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( nic->vector_value("ATTACH") == "YES" )
|
|
{
|
|
return static_cast<VectorAttribute * >(obj_template->remove(nic));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_attach_nic(int nic_id)
|
|
{
|
|
int num_nics;
|
|
int n_id;
|
|
|
|
vector<Attribute *> nics;
|
|
VectorAttribute * nic;
|
|
|
|
num_nics = obj_template->get("NIC", nics);
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
nic = dynamic_cast<VectorAttribute * >(nics[i]);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
nic->vector_value("NIC_ID", n_id);
|
|
|
|
if ( n_id == nic_id )
|
|
{
|
|
nic->replace("ATTACH", "YES");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::release_disk_images()
|
|
{
|
|
int iid;
|
|
int save_as_id;
|
|
int rc;
|
|
int num_disks;
|
|
|
|
vector<Attribute const * > disks;
|
|
ImageManager * imagem;
|
|
|
|
string disk_base_path = "";
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
imagem = nd.get_imagem();
|
|
|
|
num_disks = get_template_attribute("DISK",disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
VectorAttribute const * disk =
|
|
dynamic_cast<VectorAttribute const * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rc = disk->vector_value("IMAGE_ID", iid);
|
|
|
|
if ( rc == 0 )
|
|
{
|
|
imagem->release_image(oid, iid, (state == FAILED));
|
|
}
|
|
|
|
rc = disk->vector_value("SAVE_AS", save_as_id);
|
|
|
|
if ( rc == 0 )
|
|
{
|
|
imagem->release_image(oid, save_as_id, (state != ACTIVE || lcm_state != EPILOG));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::new_snapshot(string& name, int& snap_id)
|
|
{
|
|
int num_snaps;
|
|
int id;
|
|
int max_id = -1;
|
|
|
|
vector<Attribute *> snaps;
|
|
VectorAttribute * snap;
|
|
|
|
num_snaps = obj_template->get("SNAPSHOT", snaps);
|
|
|
|
for(int i=0; i<num_snaps; i++)
|
|
{
|
|
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
|
|
|
|
if ( snap == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
snap->vector_value("SNAPSHOT_ID", id);
|
|
|
|
if (id > max_id)
|
|
{
|
|
max_id = id;
|
|
}
|
|
}
|
|
|
|
snap_id = max_id + 1;
|
|
|
|
if (name.empty())
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "snapshot-" << snap_id;
|
|
|
|
name = oss.str();
|
|
}
|
|
|
|
snap = new VectorAttribute("SNAPSHOT");
|
|
snap->replace("SNAPSHOT_ID", snap_id);
|
|
snap->replace("NAME", name);
|
|
snap->replace("TIME", (int)time(0));
|
|
snap->replace("HYPERVISOR_ID", "");
|
|
|
|
snap->replace("ACTIVE", "YES");
|
|
|
|
obj_template->set(snap);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_active_snapshot(int snap_id)
|
|
{
|
|
int num_snaps;
|
|
int s_id;
|
|
|
|
vector<Attribute *> snaps;
|
|
VectorAttribute * snap;
|
|
|
|
num_snaps = obj_template->get("SNAPSHOT", snaps);
|
|
|
|
for(int i=0; i<num_snaps; i++)
|
|
{
|
|
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
|
|
|
|
if ( snap == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
snap->vector_value("SNAPSHOT_ID", s_id);
|
|
|
|
if ( s_id == snap_id )
|
|
{
|
|
snap->replace("ACTIVE", "YES");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::update_snapshot_id(string& hypervisor_id)
|
|
{
|
|
int num_snaps;
|
|
vector<Attribute *> snaps;
|
|
VectorAttribute * snap;
|
|
|
|
num_snaps = obj_template->get("SNAPSHOT", snaps);
|
|
|
|
for(int i=0; i<num_snaps; i++)
|
|
{
|
|
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
|
|
|
|
if ( snap == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( snap->vector_value("ACTIVE") == "YES" )
|
|
{
|
|
snap->replace("HYPERVISOR_ID", hypervisor_id);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::clear_active_snapshot()
|
|
{
|
|
int num_snaps;
|
|
vector<Attribute *> snaps;
|
|
VectorAttribute * snap;
|
|
|
|
num_snaps = obj_template->get("SNAPSHOT", snaps);
|
|
|
|
for(int i=0; i<num_snaps; i++)
|
|
{
|
|
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
|
|
|
|
if ( snap == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( snap->vector_value("ACTIVE") == "YES" )
|
|
{
|
|
snap->remove("ACTIVE");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::delete_active_snapshot()
|
|
{
|
|
vector<Attribute *> snaps;
|
|
VectorAttribute * snap;
|
|
|
|
int num_snaps = obj_template->get("SNAPSHOT", snaps);
|
|
|
|
for(int i=0; i<num_snaps; i++)
|
|
{
|
|
snap = dynamic_cast<VectorAttribute * >(snaps[i]);
|
|
|
|
if ( snap == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( snap->vector_value("ACTIVE") == "YES" )
|
|
{
|
|
if (obj_template->remove(snap) != 0)
|
|
{
|
|
delete snap;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::delete_snapshots()
|
|
{
|
|
obj_template->erase("SNAPSHOT");
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_network_leases(string& estr)
|
|
{
|
|
int num_nics, rc;
|
|
vector<Attribute * > nics;
|
|
VirtualNetworkPool * vnpool;
|
|
VectorAttribute * nic;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
vnpool = nd.get_vnpool();
|
|
|
|
num_nics = user_obj_template->remove("NIC",nics);
|
|
|
|
for (vector<Attribute*>::iterator it=nics.begin(); it != nics.end(); it++)
|
|
{
|
|
obj_template->set(*it);
|
|
}
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
nic = dynamic_cast<VectorAttribute * >(nics[i]);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rc = vnpool->nic_attribute(nic, i, uid, oid, estr);
|
|
|
|
if (rc == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::release_network_leases()
|
|
{
|
|
string vnid;
|
|
string ip;
|
|
int num_nics;
|
|
vector<Attribute const * > nics;
|
|
|
|
num_nics = get_template_attribute("NIC",nics);
|
|
|
|
for(int i=0; i<num_nics; i++)
|
|
{
|
|
VectorAttribute const * nic =
|
|
dynamic_cast<VectorAttribute const * >(nics[i]);
|
|
|
|
release_network_leases(nic, oid);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::release_network_leases(VectorAttribute const * nic, int vmid)
|
|
{
|
|
VirtualNetworkPool* vnpool = Nebula::instance().get_vnpool();
|
|
VirtualNetwork* vn;
|
|
|
|
int vnid;
|
|
string ip;
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if ( nic->vector_value("NETWORK_ID", vnid) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ip = nic->vector_value("IP");
|
|
|
|
if ( ip.empty() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
vn = vnpool->get(vnid, true);
|
|
|
|
if ( vn == 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (vn->is_owner(ip,vmid))
|
|
{
|
|
vn->release_lease(ip);
|
|
vnpool->update(vn);
|
|
}
|
|
|
|
vn->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::generate_context(string &files, int &disk_id, string& token_password)
|
|
{
|
|
ofstream file;
|
|
string files_ds;
|
|
|
|
vector<const Attribute*> attrs;
|
|
const VectorAttribute * context;
|
|
|
|
map<string, string>::const_iterator it;
|
|
|
|
files = "";
|
|
bool token;
|
|
|
|
if ( history == 0 )
|
|
return -1;
|
|
|
|
if ( get_template_attribute("CONTEXT",attrs) != 1 )
|
|
{
|
|
log("VM", Log::INFO, "Virtual Machine has no context");
|
|
return 0;
|
|
}
|
|
|
|
file.open(history->context_file.c_str(),ios::out);
|
|
|
|
if (file.fail() == true)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Could not open context file: " << history->context_file;
|
|
log("VM", Log::ERROR, oss);
|
|
return -1;
|
|
}
|
|
|
|
context = dynamic_cast<const VectorAttribute *>(attrs[0]);
|
|
|
|
if (context == 0)
|
|
{
|
|
file.close();
|
|
return -1;
|
|
}
|
|
|
|
files = context->vector_value("FILES");
|
|
|
|
files_ds = context->vector_value("FILES_DS");
|
|
|
|
if (!files_ds.empty())
|
|
{
|
|
files += " ";
|
|
files += files_ds;
|
|
}
|
|
|
|
context->vector_value("TOKEN", token);
|
|
|
|
if (token)
|
|
{
|
|
ofstream token_file;
|
|
ostringstream oss;
|
|
|
|
string* encrypted;
|
|
string tk_error;
|
|
|
|
if (token_password.empty())
|
|
{
|
|
tk_error = "CONTEXT/TOKEN set, but TOKEN_PASSWORD is not defined"
|
|
" in the user template.";
|
|
|
|
file.close();
|
|
|
|
log("VM", Log::ERROR, tk_error.c_str());
|
|
set_template_error_message(tk_error);
|
|
|
|
return -1;
|
|
}
|
|
|
|
// The token_password is taken from the owner user's template.
|
|
// We store this original owner in case a chown operation is performed.
|
|
add_template_attribute("CREATED_BY", uid);
|
|
|
|
token_file.open(history->token_file.c_str(), ios::out);
|
|
|
|
if (token_file.fail())
|
|
{
|
|
tk_error = "Cannot create token file";
|
|
|
|
file.close();
|
|
|
|
log("VM", Log::ERROR, tk_error.c_str());
|
|
set_template_error_message(tk_error);
|
|
|
|
return -1;
|
|
}
|
|
|
|
oss << oid << ':' << stime;
|
|
|
|
encrypted = one_util::aes256cbc_encrypt(oss.str(), token_password);
|
|
|
|
token_file << *encrypted << endl;
|
|
|
|
token_file.close();
|
|
|
|
delete encrypted;
|
|
|
|
files += (" " + history->token_file);
|
|
}
|
|
|
|
const map<string, string> values = context->value();
|
|
|
|
file << "# Context variables generated by OpenNebula\n";
|
|
|
|
for (it=values.begin(); it != values.end(); it++ )
|
|
{
|
|
//Replace every ' in value by '\''
|
|
string escape_str(it->second);
|
|
size_t pos = 0;
|
|
|
|
while ((pos = escape_str.find('\'', pos)) != string::npos)
|
|
{
|
|
escape_str.replace(pos,1,"'\\''");
|
|
pos = pos + 4;
|
|
}
|
|
|
|
file << it->first <<"='" << escape_str << "'" << endl;
|
|
}
|
|
|
|
file.close();
|
|
|
|
context->vector_value("DISK_ID", disk_id);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_image_from_disk(int disk_id, bool hot, string& err_str)
|
|
{
|
|
int iid = -1;
|
|
int rc;
|
|
|
|
VectorAttribute * disk;
|
|
|
|
ostringstream oss;
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
goto error_not_found;
|
|
}
|
|
|
|
if(!((disk->vector_value("SAVE_AS")).empty()))
|
|
{
|
|
goto error_saved;
|
|
}
|
|
|
|
if(!(disk->vector_value("PERSISTENT").empty()) && !hot)
|
|
{
|
|
goto error_persistent;
|
|
}
|
|
|
|
rc = disk->vector_value("IMAGE_ID", iid);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_image_id;
|
|
}
|
|
|
|
return iid;
|
|
|
|
error_persistent:
|
|
oss << "Source image for DISK " << disk_id << " is persistent.";
|
|
goto error_common;
|
|
|
|
error_saved:
|
|
oss << "The DISK " << disk_id << " is already going to be saved.";
|
|
goto error_common;
|
|
|
|
error_image_id:
|
|
oss << "The DISK " << disk_id << " does not have a valid IMAGE_ID.";
|
|
goto error_common;
|
|
|
|
error_not_found:
|
|
oss << "The DISK " << disk_id << " does not exist for VM " << oid << ".";
|
|
|
|
error_common:
|
|
err_str = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_saveas_state(int disk_id, bool hot)
|
|
{
|
|
VectorAttribute* disk;
|
|
|
|
switch (state)
|
|
{
|
|
case ACTIVE:
|
|
switch (lcm_state)
|
|
{
|
|
case RUNNING:
|
|
lcm_state = HOTPLUG_SAVEAS;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case POWEROFF:
|
|
state = ACTIVE;
|
|
lcm_state = HOTPLUG_SAVEAS_POWEROFF;
|
|
break;
|
|
|
|
case SUSPENDED:
|
|
state = ACTIVE;
|
|
lcm_state = HOTPLUG_SAVEAS_SUSPENDED;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
if (hot)
|
|
{
|
|
disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES");
|
|
}
|
|
else
|
|
{
|
|
disk->replace("SAVE_AS_ACTIVE", "YES");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::clear_saveas_state(int disk_id, bool hot)
|
|
{
|
|
VectorAttribute * disk;
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if (disk != 0)
|
|
{
|
|
if (hot)
|
|
{
|
|
disk->remove("HOTPLUG_SAVE_AS_ACTIVE");
|
|
disk->remove("HOTPLUG_SAVE_AS");
|
|
disk->remove("HOTPLUG_SAVE_AS_SOURCE");
|
|
}
|
|
else
|
|
{
|
|
disk->remove("SAVE_AS_ACTIVE");
|
|
}
|
|
}
|
|
|
|
switch (lcm_state)
|
|
{
|
|
case HOTPLUG_SAVEAS:
|
|
lcm_state = RUNNING;
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_POWEROFF:
|
|
state = POWEROFF;
|
|
lcm_state = LCM_INIT;
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_SUSPENDED:
|
|
state = SUSPENDED;
|
|
lcm_state = LCM_INIT;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
VectorAttribute* VirtualMachine::get_disk(int disk_id)
|
|
{
|
|
int num_disks;
|
|
int tdisk_id;
|
|
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
disk->vector_value("DISK_ID", tdisk_id);
|
|
|
|
if ( tdisk_id == disk_id )
|
|
{
|
|
return disk;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::save_disk(int disk_id,
|
|
const string& source,
|
|
int img_id)
|
|
{
|
|
VectorAttribute * disk;
|
|
|
|
if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
|
|
&& lcm_state != HOTPLUG_SAVEAS_POWEROFF )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
disk->replace("SAVE_AS_SOURCE", source);
|
|
|
|
disk->replace("SAVE_AS", img_id);
|
|
|
|
disk->replace("SAVE", "YES");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::save_disk_hot(int disk_id,
|
|
const string& source,
|
|
int img_id)
|
|
{
|
|
VectorAttribute * disk;
|
|
|
|
if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
|
|
&& lcm_state != HOTPLUG_SAVEAS_POWEROFF )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
disk = get_disk(disk_id);
|
|
|
|
if ( disk != 0 )
|
|
{
|
|
disk->replace("HOTPLUG_SAVE_AS", img_id);
|
|
disk->replace("HOTPLUG_SAVE_AS_SOURCE", source);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source, int& image_id)
|
|
{
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
int rc;
|
|
int num_disks;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE") == "YES" )
|
|
{
|
|
source = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE");
|
|
|
|
rc = disk->vector_value("HOTPLUG_SAVE_AS", image_id);
|
|
rc += disk->vector_value("DISK_ID", disk_id);
|
|
|
|
if ( rc != 0 || source.empty() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::cancel_saveas_disk(int& image_id)
|
|
{
|
|
vector<Attribute *> disks;
|
|
VectorAttribute * disk;
|
|
|
|
int num_disks;
|
|
|
|
num_disks = obj_template->get("DISK", disks);
|
|
|
|
bool active, hot_active;
|
|
|
|
image_id = -1;
|
|
|
|
for(int i=0; i<num_disks; i++)
|
|
{
|
|
disk = dynamic_cast<VectorAttribute * >(disks[i]);
|
|
|
|
if ( disk == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
disk->vector_value("SAVE_AS_ACTIVE", active);
|
|
disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE", hot_active);
|
|
|
|
if (active)
|
|
{
|
|
disk->vector_value("SAVE_AS", image_id);
|
|
|
|
disk->remove("SAVE_AS_ACTIVE");
|
|
disk->remove("SAVE_AS_SOURCE");
|
|
disk->remove("SAVE_AS");
|
|
|
|
disk->replace("SAVE", "NO");
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (hot_active)
|
|
{
|
|
disk->vector_value("HOTPLUG_SAVE_AS", image_id);
|
|
|
|
disk->remove("HOTPLUG_SAVE_AS_ACTIVE");
|
|
disk->remove("HOTPLUG_SAVE_AS");
|
|
disk->remove("HOTPLUG_SAVE_AS_SOURCE");
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::set_auth_request(int uid,
|
|
AuthRequest& ar,
|
|
VirtualMachineTemplate *tmpl)
|
|
{
|
|
int num;
|
|
vector<Attribute * > vectors;
|
|
VectorAttribute * vector;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
|
|
ImagePool * ipool = nd.get_ipool();
|
|
VirtualNetworkPool * vnpool = nd.get_vnpool();
|
|
|
|
num = tmpl->get("DISK",vectors);
|
|
|
|
for(int i=0; i<num; i++)
|
|
{
|
|
|
|
vector = dynamic_cast<VectorAttribute * >(vectors[i]);
|
|
|
|
if ( vector == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ipool->authorize_disk(vector,uid,&ar);
|
|
}
|
|
|
|
vectors.clear();
|
|
|
|
num = tmpl->get("NIC",vectors);
|
|
|
|
for(int i=0; i<num; i++)
|
|
{
|
|
vector = dynamic_cast<VectorAttribute * >(vectors[i]);
|
|
|
|
if ( vector == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
vnpool->authorize_nic(vector,uid,&ar);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
pthread_mutex_t VirtualMachine::lex_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
extern "C"
|
|
{
|
|
typedef struct yy_buffer_state * YY_BUFFER_STATE;
|
|
|
|
int vm_var_parse (VirtualMachine * vm,
|
|
ostringstream * parsed,
|
|
char ** errmsg);
|
|
|
|
int vm_file_var_parse (VirtualMachine * vm,
|
|
vector<int> * img_ids,
|
|
char ** errmsg);
|
|
|
|
int vm_var_lex_destroy();
|
|
|
|
YY_BUFFER_STATE vm_var__scan_string(const char * str);
|
|
|
|
void vm_var__delete_buffer(YY_BUFFER_STATE);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::parse_template_attribute(const string& attribute,
|
|
string& parsed,
|
|
string& error_str)
|
|
{
|
|
YY_BUFFER_STATE str_buffer = 0;
|
|
const char * str;
|
|
int rc;
|
|
ostringstream oss_parsed;
|
|
char * error_msg = 0;
|
|
|
|
pthread_mutex_lock(&lex_mutex);
|
|
|
|
str = attribute.c_str();
|
|
str_buffer = vm_var__scan_string(str);
|
|
|
|
if (str_buffer == 0)
|
|
{
|
|
goto error_yy;
|
|
}
|
|
|
|
rc = vm_var_parse(this, &oss_parsed, &error_msg);
|
|
|
|
vm_var__delete_buffer(str_buffer);
|
|
|
|
vm_var_lex_destroy();
|
|
|
|
pthread_mutex_unlock(&lex_mutex);
|
|
|
|
if ( rc != 0 && error_msg != 0 )
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Error parsing: " << attribute << ". " << error_msg;
|
|
log("VM", Log::ERROR, oss);
|
|
|
|
error_str = oss.str();
|
|
|
|
free(error_msg);
|
|
}
|
|
|
|
parsed = oss_parsed.str();
|
|
|
|
return rc;
|
|
|
|
error_yy:
|
|
log("VM",Log::ERROR,"Error setting scan buffer");
|
|
pthread_mutex_unlock(&lex_mutex);
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::parse_file_attribute(string attribute,
|
|
vector<int>& img_ids,
|
|
string& error)
|
|
{
|
|
YY_BUFFER_STATE str_buffer = 0;
|
|
const char * str;
|
|
int rc;
|
|
ostringstream oss_parsed;
|
|
char * error_msg = 0;
|
|
|
|
size_t non_blank_pos;
|
|
|
|
//Removes leading blanks from attribute, these are not managed
|
|
//by the parser as it is common to the other VM varibales
|
|
non_blank_pos = attribute.find_first_not_of(" \t\n\v\f\r");
|
|
|
|
if ( non_blank_pos != string::npos )
|
|
{
|
|
attribute.erase(0, non_blank_pos);
|
|
}
|
|
|
|
pthread_mutex_lock(&lex_mutex);
|
|
|
|
str = attribute.c_str();
|
|
str_buffer = vm_var__scan_string(str);
|
|
|
|
if (str_buffer == 0)
|
|
{
|
|
goto error_yy;
|
|
}
|
|
|
|
rc = vm_file_var_parse(this, &img_ids, &error_msg);
|
|
|
|
vm_var__delete_buffer(str_buffer);
|
|
|
|
vm_var_lex_destroy();
|
|
|
|
pthread_mutex_unlock(&lex_mutex);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
ostringstream oss;
|
|
|
|
if ( error_msg != 0 )
|
|
{
|
|
oss << "Error parsing: " << attribute << ". " << error_msg;
|
|
free(error_msg);
|
|
}
|
|
else
|
|
{
|
|
oss << "Unknown error parsing: " << attribute << ".";
|
|
}
|
|
|
|
error = oss.str();
|
|
}
|
|
|
|
return rc;
|
|
|
|
error_yy:
|
|
log("VM",Log::ERROR,"Error setting scan buffer");
|
|
pthread_mutex_unlock(&lex_mutex);
|
|
return -1;
|
|
}
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
|
|
{
|
|
string template_xml;
|
|
string user_template_xml;
|
|
string history_xml;
|
|
string perm_xml;
|
|
ostringstream oss;
|
|
|
|
oss << "<VM>"
|
|
<< "<ID>" << oid << "</ID>"
|
|
<< "<UID>" << uid << "</UID>"
|
|
<< "<GID>" << gid << "</GID>"
|
|
<< "<UNAME>" << uname << "</UNAME>"
|
|
<< "<GNAME>" << gname << "</GNAME>"
|
|
<< "<NAME>" << name << "</NAME>"
|
|
<< perms_to_xml(perm_xml)
|
|
<< "<LAST_POLL>" << last_poll << "</LAST_POLL>"
|
|
<< "<STATE>" << state << "</STATE>"
|
|
<< "<LCM_STATE>" << lcm_state << "</LCM_STATE>"
|
|
<< "<RESCHED>" << resched << "</RESCHED>"
|
|
<< "<STIME>" << stime << "</STIME>"
|
|
<< "<ETIME>" << etime << "</ETIME>"
|
|
<< "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>"
|
|
<< "<MEMORY>" << memory << "</MEMORY>"
|
|
<< "<CPU>" << cpu << "</CPU>"
|
|
<< "<NET_TX>" << net_tx << "</NET_TX>"
|
|
<< "<NET_RX>" << net_rx << "</NET_RX>"
|
|
<< obj_template->to_xml(template_xml)
|
|
<< user_obj_template->to_xml(user_template_xml);
|
|
|
|
if ( hasHistory() && n_history > 0 )
|
|
{
|
|
oss << "<HISTORY_RECORDS>";
|
|
|
|
if ( n_history == 2 )
|
|
{
|
|
for (unsigned int i=0; i < history_records.size(); i++)
|
|
{
|
|
oss << history_records[i]->to_xml(history_xml);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oss << history->to_xml(history_xml);
|
|
}
|
|
|
|
oss << "</HISTORY_RECORDS>";
|
|
}
|
|
else
|
|
{
|
|
oss << "<HISTORY_RECORDS/>";
|
|
}
|
|
|
|
oss << "</VM>";
|
|
|
|
xml = oss.str();
|
|
|
|
return xml;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::from_xml(const string &xml_str)
|
|
{
|
|
vector<xmlNodePtr> content;
|
|
|
|
int istate;
|
|
int ilcmstate;
|
|
int rc = 0;
|
|
|
|
// Initialize the internal XML object
|
|
update_from_str(xml_str);
|
|
|
|
// Get class base attributes
|
|
rc += xpath(oid, "/VM/ID", -1);
|
|
|
|
rc += xpath(uid, "/VM/UID", -1);
|
|
rc += xpath(gid, "/VM/GID", -1);
|
|
|
|
rc += xpath(uname, "/VM/UNAME", "not_found");
|
|
rc += xpath(gname, "/VM/GNAME", "not_found");
|
|
rc += xpath(name, "/VM/NAME", "not_found");
|
|
|
|
rc += xpath(last_poll, "/VM/LAST_POLL", 0);
|
|
rc += xpath(istate, "/VM/STATE", 0);
|
|
rc += xpath(ilcmstate, "/VM/LCM_STATE", 0);
|
|
rc += xpath(resched, "/VM/RESCHED", 0);
|
|
|
|
rc += xpath(stime, "/VM/STIME", 0);
|
|
rc += xpath(etime, "/VM/ETIME", 0);
|
|
rc += xpath(deploy_id, "/VM/DEPLOY_ID","");
|
|
|
|
rc += xpath(memory, "/VM/MEMORY", 0);
|
|
rc += xpath(cpu, "/VM/CPU", 0);
|
|
rc += xpath(net_tx, "/VM/NET_TX", 0);
|
|
rc += xpath(net_rx, "/VM/NET_RX", 0);
|
|
|
|
// Permissions
|
|
rc += perms_from_xml();
|
|
|
|
state = static_cast<VmState>(istate);
|
|
lcm_state = static_cast<LcmState>(ilcmstate);
|
|
|
|
// Virtual Machine template
|
|
ObjectXML::get_nodes("/VM/TEMPLATE", content);
|
|
|
|
if (content.empty())
|
|
{
|
|
return -1;
|
|
}
|
|
rc += obj_template->from_xml_node(content[0]);
|
|
|
|
ObjectXML::free_nodes(content);
|
|
content.clear();
|
|
|
|
// Virtual Machine user template
|
|
|
|
ObjectXML::get_nodes("/VM/USER_TEMPLATE", content);
|
|
|
|
if (content.empty())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
rc += user_obj_template->from_xml_node(content[0]);
|
|
|
|
ObjectXML::free_nodes(content);
|
|
content.clear();
|
|
|
|
// Last history entry
|
|
|
|
ObjectXML::get_nodes("/VM/HISTORY_RECORDS/HISTORY", content);
|
|
|
|
if (!content.empty())
|
|
{
|
|
history = new History(oid);
|
|
rc += history->from_xml_node(content[0]);
|
|
|
|
history_records.resize(history->seq + 1);
|
|
history_records[history->seq] = history;
|
|
|
|
ObjectXML::free_nodes(content);
|
|
}
|
|
|
|
if (rc != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string VirtualMachine::get_system_dir() const
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << history->ds_location << "/" << history->ds_id << "/"<< oid;
|
|
|
|
return oss.str();
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::update_info(
|
|
const int _memory,
|
|
const int _cpu,
|
|
const long long _net_tx,
|
|
const long long _net_rx,
|
|
const map<string, string> &custom)
|
|
{
|
|
map<string, string>::const_iterator it;
|
|
|
|
last_poll = time(0);
|
|
|
|
if (_memory != -1)
|
|
{
|
|
memory = _memory;
|
|
}
|
|
|
|
if (_cpu != -1)
|
|
{
|
|
cpu = _cpu;
|
|
}
|
|
|
|
if (_net_tx != -1)
|
|
{
|
|
net_tx = _net_tx;
|
|
}
|
|
|
|
if (_net_rx != -1)
|
|
{
|
|
net_rx = _net_rx;
|
|
}
|
|
|
|
for (it = custom.begin(); it != custom.end(); it++)
|
|
{
|
|
replace_template_attribute(it->first, it->second);
|
|
}
|
|
|
|
set_vm_info();
|
|
|
|
clear_template_monitor_error();
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::replace_template(
|
|
const string& tmpl_str,
|
|
bool keep_restricted,
|
|
string& error)
|
|
{
|
|
VirtualMachineTemplate * new_tmpl =
|
|
new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
|
|
|
|
if ( new_tmpl == 0 )
|
|
{
|
|
error = "Cannot allocate a new template";
|
|
return -1;
|
|
}
|
|
|
|
if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
|
|
{
|
|
delete new_tmpl;
|
|
return -1;
|
|
}
|
|
|
|
if (keep_restricted)
|
|
{
|
|
new_tmpl->remove_restricted();
|
|
|
|
if (user_obj_template != 0)
|
|
{
|
|
user_obj_template->remove_all_except_restricted();
|
|
|
|
string aux_error;
|
|
new_tmpl->merge(user_obj_template, aux_error);
|
|
}
|
|
}
|
|
|
|
delete user_obj_template;
|
|
|
|
user_obj_template = new_tmpl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::append_template(
|
|
const string& tmpl_str,
|
|
bool keep_restricted,
|
|
string& error)
|
|
{
|
|
VirtualMachineTemplate * new_tmpl =
|
|
new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
|
|
|
|
if ( new_tmpl == 0 )
|
|
{
|
|
error = "Cannot allocate a new template";
|
|
return -1;
|
|
}
|
|
|
|
if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
|
|
{
|
|
delete new_tmpl;
|
|
return -1;
|
|
}
|
|
|
|
if (keep_restricted)
|
|
{
|
|
new_tmpl->remove_restricted();
|
|
}
|
|
|
|
if (user_obj_template != 0)
|
|
{
|
|
user_obj_template->merge(new_tmpl, error);
|
|
delete new_tmpl;
|
|
}
|
|
else
|
|
{
|
|
user_obj_template = new_tmpl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::set_template_error_message(const string& message)
|
|
{
|
|
set_template_error_message("ERROR", message);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::set_template_error_message(const string& name,
|
|
const string& message)
|
|
{
|
|
SingleAttribute * attr;
|
|
ostringstream error_value;
|
|
|
|
error_value << one_util::log_time() << " : " << message;
|
|
|
|
attr = new SingleAttribute(name, error_value.str());
|
|
|
|
user_obj_template->erase(name);
|
|
user_obj_template->set(attr);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::clear_template_error_message()
|
|
{
|
|
user_obj_template->erase("ERROR");
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::set_template_monitor_error(const string& message)
|
|
{
|
|
set_template_error_message("ERROR_MONITOR", message);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::clear_template_monitor_error()
|
|
{
|
|
user_obj_template->erase("ERROR_MONITOR");
|
|
}
|