mirror of
https://github.com/OpenNebula/one.git
synced 2026-11-08 21:16:39 +09:00
3866 lines
104 KiB
C++
3866 lines
104 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2022, OpenNebula Project, OpenNebula Systems */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
|
/* not use this file except in compliance with the License. You may obtain */
|
|
/* a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
|
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
|
/* See the License for the specific language governing permissions and */
|
|
/* limitations under the License. */
|
|
/* -------------------------------------------------------------------------- */
|
|
#include "VirtualMachine.h"
|
|
#include "VirtualMachineManager.h"
|
|
#include "VirtualNetworkPool.h"
|
|
#include "VMGroupPool.h"
|
|
#include "ImagePool.h"
|
|
#include "NebulaLog.h"
|
|
#include "NebulaUtil.h"
|
|
#include "Snapshots.h"
|
|
#include "ScheduledAction.h"
|
|
#include "LifeCycleManager.h"
|
|
#include "ClusterPool.h"
|
|
#include "DatastorePool.h"
|
|
#include "SecurityGroupPool.h"
|
|
#include "Nebula.h"
|
|
|
|
#include "vm_file_var_syntax.h"
|
|
#include "vm_var_syntax.h"
|
|
|
|
#include <sys/stat.h>
|
|
|
|
using namespace std;
|
|
|
|
/* ************************************************************************** */
|
|
/* Virtual Machine :: Constructor/Destructor */
|
|
/* ************************************************************************** */
|
|
|
|
VirtualMachine::VirtualMachine(int id,
|
|
int _uid,
|
|
int _gid,
|
|
const string& _uname,
|
|
const string& _gname,
|
|
int umask,
|
|
unique_ptr<VirtualMachineTemplate> _vm_template):
|
|
PoolObjectSQL(id,VM,"",_uid,_gid,_uname,_gname,one_db::vm_table),
|
|
state(INIT),
|
|
prev_state(INIT),
|
|
lcm_state(LCM_INIT),
|
|
prev_lcm_state(LCM_INIT),
|
|
resched(0),
|
|
stime(time(0)),
|
|
etime(0),
|
|
deploy_id(""),
|
|
history(0),
|
|
previous_history(0),
|
|
disks(false),
|
|
nics(false),
|
|
_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 = move(_vm_template);
|
|
}
|
|
else
|
|
{
|
|
user_obj_template = make_unique<VirtualMachineTemplate>(false,'=',"USER_TEMPLATE");
|
|
}
|
|
|
|
obj_template = make_unique<VirtualMachineTemplate>();
|
|
|
|
set_umask(umask);
|
|
}
|
|
|
|
VirtualMachine::~VirtualMachine()
|
|
{
|
|
for (unsigned int i=0 ; i < history_records.size() ; i++)
|
|
{
|
|
delete history_records[i];
|
|
}
|
|
|
|
delete _log;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::vm_state_from_str(string& st, VmState& state)
|
|
{
|
|
one_util::toupper(st);
|
|
|
|
if ( st == "INIT" ) {
|
|
state = INIT;
|
|
} else if ( st == "PENDING" ) {
|
|
state = PENDING;
|
|
} else if ( st == "HOLD" ) {
|
|
state = HOLD;
|
|
} else if ( st == "ACTIVE" ) {
|
|
state = ACTIVE;
|
|
} else if ( st == "STOPPED" ) {
|
|
state = STOPPED;
|
|
} else if ( st == "SUSPENDED" ) {
|
|
state = SUSPENDED;
|
|
} else if ( st == "DONE" ) {
|
|
state = DONE;
|
|
} else if ( st == "POWEROFF" ) {
|
|
state = POWEROFF;
|
|
} else if ( st == "UNDEPLOYED" ) {
|
|
state = UNDEPLOYED;
|
|
} else if ( st == "CLONING" ) {
|
|
state = CLONING;
|
|
} else if ( st == "CLONING_FAILURE" ) {
|
|
state = CLONING_FAILURE;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::vm_state_to_str(string& st, VmState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case INIT:
|
|
st = "INIT"; break;
|
|
case PENDING:
|
|
st = "PENDING"; break;
|
|
case HOLD:
|
|
st = "HOLD"; break;
|
|
case ACTIVE:
|
|
st = "ACTIVE"; break;
|
|
case STOPPED:
|
|
st = "STOPPED"; break;
|
|
case SUSPENDED:
|
|
st = "SUSPENDED"; break;
|
|
case DONE:
|
|
st = "DONE"; break;
|
|
case POWEROFF:
|
|
st = "POWEROFF"; break;
|
|
case UNDEPLOYED:
|
|
st = "UNDEPLOYED"; break;
|
|
case CLONING:
|
|
st = "CLONING"; break;
|
|
case CLONING_FAILURE:
|
|
st = "CLONING_FAILURE"; break;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::lcm_state_from_str(string& st, LcmState& state)
|
|
{
|
|
one_util::toupper(st);
|
|
|
|
if ( st == "LCM_INIT" ){
|
|
state = LCM_INIT;
|
|
} else if ( st == "PROLOG" ) {
|
|
state = PROLOG;
|
|
} else if ( st == "BOOT" ) {
|
|
state = BOOT;
|
|
} else if ( st == "RUNNING" ) {
|
|
state = RUNNING;
|
|
} else if ( st == "MIGRATE" ) {
|
|
state = MIGRATE;
|
|
} else if ( st == "SAVE_STOP" ) {
|
|
state = SAVE_STOP;
|
|
} else if ( st == "SAVE_SUSPEND" ) {
|
|
state = SAVE_SUSPEND;
|
|
} else if ( st == "SAVE_MIGRATE" ) {
|
|
state = SAVE_MIGRATE;
|
|
} else if ( st == "PROLOG_MIGRATE" ) {
|
|
state = PROLOG_MIGRATE;
|
|
} else if ( st == "PROLOG_RESUME" ) {
|
|
state = PROLOG_RESUME;
|
|
} else if ( st == "EPILOG_STOP" ) {
|
|
state = EPILOG_STOP;
|
|
} else if ( st == "EPILOG" ) {
|
|
state = EPILOG;
|
|
} else if ( st == "SHUTDOWN" ) {
|
|
state = SHUTDOWN;
|
|
} else if ( st == "CLEANUP_RESUBMIT" ) {
|
|
state = CLEANUP_RESUBMIT;
|
|
} else if ( st == "UNKNOWN" ) {
|
|
state = UNKNOWN;
|
|
} else if ( st == "HOTPLUG" ) {
|
|
state = HOTPLUG;
|
|
} else if ( st == "SHUTDOWN_POWEROFF" ) {
|
|
state = SHUTDOWN_POWEROFF;
|
|
} else if ( st == "BOOT_UNKNOWN" ) {
|
|
state = BOOT_UNKNOWN;
|
|
} else if ( st == "BOOT_POWEROFF" ) {
|
|
state = BOOT_POWEROFF;
|
|
} else if ( st == "BOOT_SUSPENDED" ) {
|
|
state = BOOT_SUSPENDED;
|
|
} else if ( st == "BOOT_STOPPED" ) {
|
|
state = BOOT_STOPPED;
|
|
} else if ( st == "CLEANUP_DELETE" ) {
|
|
state = CLEANUP_DELETE;
|
|
} else if ( st == "HOTPLUG_SNAPSHOT" ) {
|
|
state = HOTPLUG_SNAPSHOT;
|
|
} else if ( st == "HOTPLUG_NIC" ) {
|
|
state = HOTPLUG_NIC;
|
|
} else if ( st == "HOTPLUG_SAVEAS" ) {
|
|
state = HOTPLUG_SAVEAS;
|
|
} else if ( st == "HOTPLUG_SAVEAS_POWEROFF" ) {
|
|
state = HOTPLUG_SAVEAS_POWEROFF;
|
|
} else if ( st == "HOTPLUG_SAVEAS_SUSPENDED" ) {
|
|
state = HOTPLUG_SAVEAS_SUSPENDED;
|
|
} else if ( st == "SHUTDOWN_UNDEPLOY" ) {
|
|
state = SHUTDOWN_UNDEPLOY;
|
|
} else if ( st == "EPILOG_UNDEPLOY" ) {
|
|
state = EPILOG_UNDEPLOY;
|
|
} else if ( st == "PROLOG_UNDEPLOY" ) {
|
|
state = PROLOG_UNDEPLOY;
|
|
} else if ( st == "BOOT_UNDEPLOY" ) {
|
|
state = BOOT_UNDEPLOY;
|
|
} else if ( st == "HOTPLUG_PROLOG_POWEROFF" ) {
|
|
state = HOTPLUG_PROLOG_POWEROFF;
|
|
} else if ( st == "HOTPLUG_EPILOG_POWEROFF" ) {
|
|
state = HOTPLUG_EPILOG_POWEROFF;
|
|
} else if ( st == "BOOT_MIGRATE" ) {
|
|
state = BOOT_MIGRATE;
|
|
} else if ( st == "BOOT_FAILURE" ) {
|
|
state = BOOT_FAILURE;
|
|
} else if ( st == "BOOT_MIGRATE_FAILURE" ) {
|
|
state = BOOT_MIGRATE_FAILURE;
|
|
} else if ( st == "PROLOG_MIGRATE_FAILURE" ) {
|
|
state = PROLOG_MIGRATE_FAILURE;
|
|
} else if ( st == "PROLOG_FAILURE" ) {
|
|
state = PROLOG_FAILURE;
|
|
} else if ( st == "EPILOG_FAILURE" ) {
|
|
state = EPILOG_FAILURE;
|
|
} else if ( st == "EPILOG_STOP_FAILURE" ) {
|
|
state = EPILOG_STOP_FAILURE;
|
|
} else if ( st == "EPILOG_UNDEPLOY_FAILURE" ) {
|
|
state = EPILOG_UNDEPLOY_FAILURE;
|
|
} else if ( st == "PROLOG_MIGRATE_POWEROFF" ) {
|
|
state = PROLOG_MIGRATE_POWEROFF;
|
|
} else if ( st == "PROLOG_MIGRATE_POWEROFF_FAILURE" ) {
|
|
state = PROLOG_MIGRATE_POWEROFF_FAILURE;
|
|
} else if ( st == "PROLOG_MIGRATE_SUSPEND" ) {
|
|
state = PROLOG_MIGRATE_SUSPEND;
|
|
} else if ( st == "PROLOG_MIGRATE_SUSPEND_FAILURE" ) {
|
|
state = PROLOG_MIGRATE_SUSPEND_FAILURE;
|
|
} else if ( st == "BOOT_STOPPED_FAILURE" ) {
|
|
state = BOOT_STOPPED_FAILURE;
|
|
} else if ( st == "BOOT_UNDEPLOY_FAILURE" ) {
|
|
state = BOOT_UNDEPLOY_FAILURE;
|
|
} else if ( st == "PROLOG_RESUME_FAILURE" ) {
|
|
state = PROLOG_RESUME_FAILURE;
|
|
} else if ( st == "PROLOG_UNDEPLOY_FAILURE" ) {
|
|
state = PROLOG_UNDEPLOY_FAILURE;
|
|
} else if ( st == "DISK_SNAPSHOT_POWEROFF" ) {
|
|
state = DISK_SNAPSHOT_POWEROFF;
|
|
} else if ( st == "DISK_SNAPSHOT_REVERT_POWEROFF" ) {
|
|
state = DISK_SNAPSHOT_REVERT_POWEROFF;
|
|
} else if ( st == "DISK_SNAPSHOT_DELETE_POWEROFF" ) {
|
|
state = DISK_SNAPSHOT_DELETE_POWEROFF;
|
|
} else if ( st == "DISK_SNAPSHOT_SUSPENDED" ) {
|
|
state = DISK_SNAPSHOT_SUSPENDED;
|
|
} else if ( st == "DISK_SNAPSHOT_REVERT_SUSPENDED" ) {
|
|
state = DISK_SNAPSHOT_REVERT_SUSPENDED;
|
|
} else if ( st == "DISK_SNAPSHOT_DELETE_SUSPENDED" ) {
|
|
state = DISK_SNAPSHOT_DELETE_SUSPENDED;
|
|
} else if ( st == "DISK_SNAPSHOT" ) {
|
|
state = DISK_SNAPSHOT;
|
|
} else if ( st == "DISK_SNAPSHOT_DELETE" ) {
|
|
state = DISK_SNAPSHOT_DELETE;
|
|
} else if ( st == "PROLOG_MIGRATE_UNKNOWN" ) {
|
|
state = PROLOG_MIGRATE_UNKNOWN;
|
|
} else if ( st == "PROLOG_MIGRATE_UNKNOWN_FAILURE" ) {
|
|
state = PROLOG_MIGRATE_UNKNOWN_FAILURE;
|
|
} else if ( st == "DISK_RESIZE" ) {
|
|
state = DISK_RESIZE;
|
|
} else if ( st == "DISK_RESIZE_POWEROFF" ) {
|
|
state = DISK_RESIZE_POWEROFF;
|
|
} else if ( st == "DISK_RESIZE_UNDEPLOYED" ) {
|
|
state = DISK_RESIZE_UNDEPLOYED;
|
|
} else if ( st == "HOTPLUG_NIC_POWEROFF" ) {
|
|
state = HOTPLUG_NIC_POWEROFF;
|
|
} else if ( st == "HOTPLUG_RESIZE" ) {
|
|
state = HOTPLUG_RESIZE;
|
|
} else if ( st == "HOTPLUG_SAVEAS_UNDEPLOYED" ) {
|
|
state = HOTPLUG_SAVEAS_UNDEPLOYED;
|
|
} else if ( st == "HOTPLUG_SAVEAS_STOPPED" ) {
|
|
state = HOTPLUG_SAVEAS_STOPPED;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::lcm_state_to_str(string& st, LcmState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case LCM_INIT:
|
|
st = "LCM_INIT"; break;
|
|
case PROLOG:
|
|
st = "PROLOG"; break;
|
|
case BOOT:
|
|
st = "BOOT"; break;
|
|
case RUNNING:
|
|
st = "RUNNING"; break;
|
|
case MIGRATE:
|
|
st = "MIGRATE"; break;
|
|
case SAVE_STOP:
|
|
st = "SAVE_STOP"; break;
|
|
case SAVE_SUSPEND:
|
|
st = "SAVE_SUSPEND"; break;
|
|
case SAVE_MIGRATE:
|
|
st = "SAVE_MIGRATE"; break;
|
|
case PROLOG_MIGRATE:
|
|
st = "PROLOG_MIGRATE"; break;
|
|
case PROLOG_RESUME:
|
|
st = "PROLOG_RESUME"; break;
|
|
case EPILOG_STOP:
|
|
st = "EPILOG_STOP"; break;
|
|
case EPILOG:
|
|
st = "EPILOG"; break;
|
|
case SHUTDOWN:
|
|
st = "SHUTDOWN"; break;
|
|
case CLEANUP_RESUBMIT:
|
|
st = "CLEANUP_RESUBMIT"; break;
|
|
case UNKNOWN:
|
|
st = "UNKNOWN"; break;
|
|
case HOTPLUG:
|
|
st = "HOTPLUG"; break;
|
|
case SHUTDOWN_POWEROFF:
|
|
st = "SHUTDOWN_POWEROFF"; break;
|
|
case BOOT_UNKNOWN:
|
|
st = "BOOT_UNKNOWN"; break;
|
|
case BOOT_POWEROFF:
|
|
st = "BOOT_POWEROFF"; break;
|
|
case BOOT_SUSPENDED:
|
|
st = "BOOT_SUSPENDED"; break;
|
|
case BOOT_STOPPED:
|
|
st = "BOOT_STOPPED"; break;
|
|
case CLEANUP_DELETE:
|
|
st = "CLEANUP_DELETE"; break;
|
|
case HOTPLUG_SNAPSHOT:
|
|
st = "HOTPLUG_SNAPSHOT"; break;
|
|
case HOTPLUG_NIC:
|
|
st = "HOTPLUG_NIC"; break;
|
|
case HOTPLUG_SAVEAS:
|
|
st = "HOTPLUG_SAVEAS"; break;
|
|
case HOTPLUG_SAVEAS_POWEROFF:
|
|
st = "HOTPLUG_SAVEAS_POWEROFF"; break;
|
|
case HOTPLUG_SAVEAS_SUSPENDED:
|
|
st = "HOTPLUG_SAVEAS_SUSPENDED"; break;
|
|
case SHUTDOWN_UNDEPLOY:
|
|
st = "SHUTDOWN_UNDEPLOY"; break;
|
|
case EPILOG_UNDEPLOY:
|
|
st = "EPILOG_UNDEPLOY"; break;
|
|
case PROLOG_UNDEPLOY:
|
|
st = "PROLOG_UNDEPLOY"; break;
|
|
case BOOT_UNDEPLOY:
|
|
st = "BOOT_UNDEPLOY"; break;
|
|
case HOTPLUG_PROLOG_POWEROFF:
|
|
st = "HOTPLUG_PROLOG_POWEROFF"; break;
|
|
case HOTPLUG_EPILOG_POWEROFF:
|
|
st = "HOTPLUG_EPILOG_POWEROFF"; break;
|
|
case BOOT_MIGRATE:
|
|
st = "BOOT_MIGRATE"; break;
|
|
case BOOT_FAILURE:
|
|
st = "BOOT_FAILURE"; break;
|
|
case BOOT_MIGRATE_FAILURE:
|
|
st = "BOOT_MIGRATE_FAILURE"; break;
|
|
case PROLOG_MIGRATE_FAILURE:
|
|
st = "PROLOG_MIGRATE_FAILURE"; break;
|
|
case PROLOG_FAILURE:
|
|
st = "PROLOG_FAILURE"; break;
|
|
case EPILOG_FAILURE:
|
|
st = "EPILOG_FAILURE"; break;
|
|
case EPILOG_STOP_FAILURE:
|
|
st = "EPILOG_STOP_FAILURE"; break;
|
|
case EPILOG_UNDEPLOY_FAILURE:
|
|
st = "EPILOG_UNDEPLOY_FAILURE"; break;
|
|
case PROLOG_MIGRATE_POWEROFF:
|
|
st = "PROLOG_MIGRATE_POWEROFF"; break;
|
|
case PROLOG_MIGRATE_POWEROFF_FAILURE:
|
|
st = "PROLOG_MIGRATE_POWEROFF_FAILURE"; break;
|
|
case PROLOG_MIGRATE_SUSPEND:
|
|
st = "PROLOG_MIGRATE_SUSPEND"; break;
|
|
case PROLOG_MIGRATE_SUSPEND_FAILURE:
|
|
st = "PROLOG_MIGRATE_SUSPEND_FAILURE"; break;
|
|
case BOOT_STOPPED_FAILURE:
|
|
st = "BOOT_STOPPED_FAILURE"; break;
|
|
case BOOT_UNDEPLOY_FAILURE:
|
|
st = "BOOT_UNDEPLOY_FAILURE"; break;
|
|
case PROLOG_RESUME_FAILURE:
|
|
st = "PROLOG_RESUME_FAILURE"; break;
|
|
case PROLOG_UNDEPLOY_FAILURE:
|
|
st = "PROLOG_UNDEPLOY_FAILURE"; break;
|
|
case DISK_SNAPSHOT_POWEROFF:
|
|
st = "DISK_SNAPSHOT_POWEROFF"; break;
|
|
case DISK_SNAPSHOT_REVERT_POWEROFF:
|
|
st = "DISK_SNAPSHOT_REVERT_POWEROFF"; break;
|
|
case DISK_SNAPSHOT_DELETE_POWEROFF:
|
|
st = "DISK_SNAPSHOT_DELETE_POWEROFF"; break;
|
|
case DISK_SNAPSHOT_SUSPENDED:
|
|
st = "DISK_SNAPSHOT_SUSPENDED"; break;
|
|
case DISK_SNAPSHOT_REVERT_SUSPENDED:
|
|
st = "DISK_SNAPSHOT_REVERT_SUSPENDED"; break;
|
|
case DISK_SNAPSHOT_DELETE_SUSPENDED:
|
|
st = "DISK_SNAPSHOT_DELETE_SUSPENDED"; break;
|
|
case DISK_SNAPSHOT:
|
|
st = "DISK_SNAPSHOT"; break;
|
|
case DISK_SNAPSHOT_DELETE:
|
|
st = "DISK_SNAPSHOT_DELETE"; break;
|
|
case PROLOG_MIGRATE_UNKNOWN:
|
|
st = "PROLOG_MIGRATE_UNKNOWN"; break;
|
|
case PROLOG_MIGRATE_UNKNOWN_FAILURE:
|
|
st = "PROLOG_MIGRATE_UNKNOWN_FAILURE"; break;
|
|
case DISK_RESIZE:
|
|
st = "DISK_RESIZE"; break;
|
|
case DISK_RESIZE_POWEROFF:
|
|
st = "DISK_RESIZE_POWEROFF"; break;
|
|
case DISK_RESIZE_UNDEPLOYED:
|
|
st = "DISK_RESIZE_UNDEPLOYED"; break;
|
|
case HOTPLUG_NIC_POWEROFF:
|
|
st = "HOTPLUG_NIC_POWEROFF"; break;
|
|
case HOTPLUG_RESIZE:
|
|
st = "HOTPLUG_RESIZE"; break;
|
|
case HOTPLUG_SAVEAS_UNDEPLOYED:
|
|
st = "HOTPLUG_SAVEAS_UNDEPLOYED"; break;
|
|
case HOTPLUG_SAVEAS_STOPPED:
|
|
st = "HOTPLUG_SAVEAS_STOPPED"; break;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string VirtualMachine::state_str()
|
|
{
|
|
string st;
|
|
|
|
if (state == ACTIVE)
|
|
{
|
|
return lcm_state_to_str(st, lcm_state);
|
|
}
|
|
|
|
return vm_state_to_str(st, state);
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* Virtual Machine :: Database Access Functions */
|
|
/* ************************************************************************** */
|
|
|
|
int VirtualMachine::bootstrap(SqlDB * db)
|
|
{
|
|
int rc;
|
|
|
|
ostringstream oss_vm;
|
|
|
|
oss_vm << one_db::vm_db_bootstrap;
|
|
|
|
if (db->supports(SqlDB::SqlFeature::FTS))
|
|
{
|
|
oss_vm << ", FULLTEXT ftidx(search_token))";
|
|
}
|
|
else
|
|
{
|
|
oss_vm << ")";
|
|
}
|
|
|
|
ostringstream oss_monit(one_db::vm_monitor_db_bootstrap);
|
|
ostringstream oss_hist(one_db::history_db_bootstrap);
|
|
ostringstream oss_showback(one_db::vm_showback_db_bootstrap);
|
|
|
|
ostringstream oss_index("CREATE INDEX state_oid_idx on vm_pool (state, oid);");
|
|
|
|
rc = db->exec_local_wr(oss_vm);
|
|
rc += db->exec_local_wr(oss_index);
|
|
|
|
rc += db->exec_local_wr(oss_monit);
|
|
rc += db->exec_local_wr(oss_hist);
|
|
rc += db->exec_local_wr(oss_showback);
|
|
|
|
return rc;
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
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.
|
|
if ( hasHistory() )
|
|
{
|
|
last_seq = history->seq;
|
|
|
|
delete history_records[last_seq];
|
|
|
|
for (int i = last_seq; i >= 0; i--)
|
|
{
|
|
History * hp;
|
|
|
|
hp = new History(oid, i);
|
|
history_records[i] = hp;
|
|
|
|
rc = hp->select(db);
|
|
|
|
if ( rc != 0)
|
|
{
|
|
goto error_previous_history;
|
|
}
|
|
|
|
if ( i == last_seq )
|
|
{
|
|
history = hp;
|
|
}
|
|
else if ( i == last_seq - 1 )
|
|
{
|
|
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 SysLog(clevel, oid, obj_type);
|
|
break;
|
|
|
|
case NebulaLog::STD:
|
|
_log = new StdLog(clevel, oid, obj_type);
|
|
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;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
static int set_boot_order(Template * tmpl, string& error_str)
|
|
{
|
|
vector<VectorAttribute *> disk;
|
|
vector<VectorAttribute *> nic;
|
|
|
|
ostringstream oss;
|
|
|
|
int ndisk = tmpl->get("DISK", disk);
|
|
int nnic = tmpl->get("NIC", nic);
|
|
|
|
for (int i=0; i<ndisk; ++i)
|
|
{
|
|
disk[i]->remove("ORDER");
|
|
}
|
|
|
|
for (int i=0; i<nnic; ++i)
|
|
{
|
|
nic[i]->remove("ORDER");
|
|
}
|
|
|
|
VectorAttribute * os = tmpl->get("OS");
|
|
|
|
if ( os == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
string order = os->vector_value("BOOT");
|
|
|
|
if ( order.empty() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
vector<string> bdevs = one_util::split(order, ',');
|
|
|
|
int index = 1;
|
|
|
|
for (auto& str_dev : bdevs)
|
|
{
|
|
vector<VectorAttribute *> * dev;
|
|
int max;
|
|
int disk_id;
|
|
size_t pos;
|
|
|
|
const char * id_name;
|
|
|
|
one_util::toupper(str_dev);
|
|
|
|
int rc = one_util::regex_match("^(DISK|NIC)[[:digit:]]+$", str_dev.c_str());
|
|
|
|
if (rc != 0)
|
|
{
|
|
goto error_parsing;
|
|
}
|
|
|
|
if (str_dev.compare(0,4,"DISK") == 0)
|
|
{
|
|
pos = 4;
|
|
|
|
max = ndisk;
|
|
dev = &disk;
|
|
|
|
id_name = "DISK_ID";
|
|
}
|
|
else if (str_dev.compare(0,3,"NIC") == 0)
|
|
{
|
|
pos = 3;
|
|
|
|
max = nnic;
|
|
dev = &nic;
|
|
|
|
id_name = "NIC_ID";
|
|
}
|
|
else
|
|
{
|
|
goto error_parsing;
|
|
}
|
|
|
|
istringstream iss(str_dev.substr(pos, string::npos));
|
|
|
|
iss >> disk_id;
|
|
|
|
if (iss.fail())
|
|
{
|
|
goto error_parsing;
|
|
}
|
|
|
|
bool found = false;
|
|
|
|
for (int j=0; j<max; ++j)
|
|
{
|
|
int j_disk_id;
|
|
|
|
if ( (*dev)[j]->vector_value(id_name, j_disk_id) == 0 &&
|
|
j_disk_id == disk_id )
|
|
{
|
|
(*dev)[j]->replace("ORDER", index++);
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
oss << "Wrong OS/BOOT value. Device with "
|
|
<< id_name << " " << disk_id << " not found";
|
|
|
|
goto error_common;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_parsing:
|
|
oss << "Wrong OS/BOOT value: \"" << order
|
|
<< "\" should be a comma-separated list of disk# or nic#";
|
|
|
|
error_common:
|
|
error_str = oss.str();
|
|
return -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::insert(SqlDB * db, string& error_str)
|
|
{
|
|
int rc;
|
|
string name;
|
|
string prefix;
|
|
|
|
string value;
|
|
long int ivalue;
|
|
long int memory;
|
|
float fvalue;
|
|
set<int> cluster_ids;
|
|
vector<Template *> quotas;
|
|
ostringstream oss;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Set a name if the VM has not got one and VM_ID
|
|
// ------------------------------------------------------------------------
|
|
user_obj_template->erase("VMID");
|
|
obj_template->add("VMID", oid);
|
|
|
|
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;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Move known attributes that doesn't need additional procesing to template
|
|
// -------------------------------------------------------------------------
|
|
parse_well_known_attributes();
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Parse the Public Cloud specs for this VM
|
|
// ------------------------------------------------------------------------
|
|
if (parse_public_clouds(error_str) != 0)
|
|
{
|
|
goto error_public;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check for EMULATOR attribute
|
|
// ------------------------------------------------------------------------
|
|
user_obj_template->get("EMULATOR", value);
|
|
|
|
if (!value.empty())
|
|
{
|
|
user_obj_template->erase("EMULATOR");
|
|
obj_template->add("EMULATOR", value);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check for CPU, VCPU, MEMORY and TOPOLOGY attributes
|
|
// ------------------------------------------------------------------------
|
|
if ( user_obj_template->get("MEMORY", memory) == false || memory <= 0 )
|
|
{
|
|
goto error_memory;
|
|
}
|
|
|
|
user_obj_template->erase("MEMORY");
|
|
obj_template->add("MEMORY", memory);
|
|
|
|
// Check optional MEMORY_MAX attribute
|
|
if ( user_obj_template->get("MEMORY_MAX", ivalue) && ivalue > 0 )
|
|
{
|
|
user_obj_template->erase("MEMORY_MAX");
|
|
obj_template->add("MEMORY_MAX", 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 optional VCPU_MAX attribute
|
|
if ( user_obj_template->get("VCPU_MAX", ivalue) && ivalue > 0 )
|
|
{
|
|
user_obj_template->erase("VCPU_MAX");
|
|
obj_template->add("VCPU_MAX", ivalue);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check the cost attributes
|
|
// ------------------------------------------------------------------------
|
|
if ( user_obj_template->get("CPU_COST", fvalue) == true )
|
|
{
|
|
if ( fvalue < 0 )
|
|
{
|
|
goto error_cpu_cost;
|
|
}
|
|
|
|
user_obj_template->erase("CPU_COST");
|
|
obj_template->add("CPU_COST", fvalue);
|
|
}
|
|
|
|
if ( user_obj_template->get("MEMORY_COST", fvalue) == true )
|
|
{
|
|
if ( fvalue < 0 )
|
|
{
|
|
goto error_memory_cost;
|
|
}
|
|
|
|
user_obj_template->erase("MEMORY_COST");
|
|
obj_template->add("MEMORY_COST", fvalue);
|
|
}
|
|
|
|
if ( user_obj_template->get("DISK_COST", fvalue) == true )
|
|
{
|
|
if ( fvalue < 0 )
|
|
{
|
|
goto error_disk_cost;
|
|
}
|
|
|
|
user_obj_template->erase("DISK_COST");
|
|
obj_template->add("DISK_COST", fvalue);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check the OS attribute
|
|
// ------------------------------------------------------------------------
|
|
rc = parse_os(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_os;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Check the CPU Model attribute
|
|
// ------------------------------------------------------------------------
|
|
parse_cpu_model(user_obj_template.get());
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Validate RAW attribute
|
|
// ------------------------------------------------------------------------
|
|
rc = Nebula::instance().get_vmm()->validate_raw(obj_template.get(), error_str);
|
|
|
|
if (rc != 0)
|
|
{
|
|
goto error_raw;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// PCI Devices (Needs to be parsed before network)
|
|
// ------------------------------------------------------------------------
|
|
rc = parse_pci(error_str, user_obj_template.get());
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_pci;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Parse the defaults to merge
|
|
// ------------------------------------------------------------------------
|
|
rc = parse_defaults(error_str, user_obj_template.get());
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_defaults;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Parse the virtual router attributes
|
|
// ------------------------------------------------------------------------
|
|
rc = parse_vrouter(error_str, user_obj_template.get());
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_vrouter;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
bool on_hold;
|
|
|
|
if (user_obj_template->get("SUBMIT_ON_HOLD", on_hold) == true)
|
|
{
|
|
user_obj_template->erase("SUBMIT_ON_HOLD");
|
|
|
|
obj_template->replace("SUBMIT_ON_HOLD", on_hold);
|
|
}
|
|
|
|
if ( has_cloning_disks())
|
|
{
|
|
state = VirtualMachine::CLONING;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Set boot order
|
|
// -------------------------------------------------------------------------
|
|
rc = set_boot_order(obj_template.get(), error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_boot_order;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse the context & requirements
|
|
// -------------------------------------------------------------------------
|
|
rc = parse_context(error_str, false); //Don't generate context for auto NICs
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_context;
|
|
}
|
|
|
|
rc = parse_requirements(error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_requirements;
|
|
}
|
|
|
|
rc = automatic_requirements(cluster_ids, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_requirements;
|
|
}
|
|
|
|
if ( parse_graphics(error_str, user_obj_template.get()) != 0 )
|
|
{
|
|
goto error_graphics;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Get and set DEPLOY_ID for imported VMs
|
|
// -------------------------------------------------------------------------
|
|
user_obj_template->get("DEPLOY_ID", value);
|
|
user_obj_template->erase("DEPLOY_ID");
|
|
|
|
if (!value.empty())
|
|
{
|
|
const char * one_vms = "^one-[[:digit:]]+$";
|
|
|
|
if (one_util::regex_match(one_vms, value.c_str()) == 0)
|
|
{
|
|
goto error_one_vms;
|
|
}
|
|
else
|
|
{
|
|
obj_template->add("IMPORTED", "YES");
|
|
deploy_id = value;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Associate to VM Group
|
|
// ------------------------------------------------------------------------
|
|
if ( get_vmgroup(error_str) == -1 )
|
|
{
|
|
goto error_rollback;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Parse VM actions
|
|
// ------------------------------------------------------------------------
|
|
if ( parse_sched_action(error_str) == -1 )
|
|
{
|
|
goto error_rollback;
|
|
}
|
|
|
|
// Encrypt all the secrets
|
|
encrypt();
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Insert the VM
|
|
// ------------------------------------------------------------------------
|
|
rc = insert_replace(db, false, error_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_update;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//Check for missing unlock callbacks during creation
|
|
//-------------------------------------------------------------------------
|
|
if ( state == VirtualMachine::CLONING )
|
|
{
|
|
Nebula::instance().get_lcm()->trigger_disk_lock_success(oid);
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_update:
|
|
goto error_rollback;
|
|
|
|
error_boot_order:
|
|
goto error_rollback;
|
|
|
|
error_context:
|
|
goto error_rollback;
|
|
|
|
error_requirements:
|
|
goto error_rollback;
|
|
|
|
error_graphics:
|
|
goto error_rollback;
|
|
|
|
error_rollback:
|
|
release_disk_images(quotas, true);
|
|
|
|
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_cpu_cost:
|
|
error_str = "CPU_COST attribute must be a positive float or integer value.";
|
|
goto error_common;
|
|
|
|
error_memory_cost:
|
|
error_str = "MEMORY_COST attribute must be a positive float or integer value.";
|
|
goto error_common;
|
|
|
|
error_disk_cost:
|
|
error_str = "DISK_COST attribute must be a positive float or integer value.";
|
|
goto error_common;
|
|
|
|
error_one_vms:
|
|
error_str = "Trying to import an OpenNebula VM: 'one-*'.";
|
|
goto error_common;
|
|
|
|
error_raw:
|
|
error_os:
|
|
error_pci:
|
|
error_defaults:
|
|
error_vrouter:
|
|
error_public:
|
|
error_name:
|
|
error_common:
|
|
NebulaLog::log("ONE",Log::ERROR, error_str);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
/**
|
|
* @return -1 for incompatible datastore IDs, -2 for missing datastore IDs
|
|
*/
|
|
static int check_and_set_datastores_id(const set<int> &csystem_ds,
|
|
set<int> &ds_ids)
|
|
{
|
|
if ( csystem_ds.empty() )
|
|
{
|
|
return -2;
|
|
}
|
|
|
|
if ( ds_ids.empty() )
|
|
{
|
|
ds_ids = csystem_ds;
|
|
|
|
return 0;
|
|
}
|
|
|
|
set<int> intersection = one_util::set_intersection(ds_ids, csystem_ds);
|
|
|
|
if (intersection.empty())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ds_ids = intersection;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
/**
|
|
* @return -1 for incompatible cluster IDs, -2 for missing cluster IDs
|
|
*/
|
|
static int check_and_set_cluster_id(
|
|
const char * id_name,
|
|
const VectorAttribute* vatt,
|
|
set<int> &cluster_ids)
|
|
{
|
|
set<int> vatt_cluster_ids;
|
|
string val;
|
|
|
|
// If the attr does not exist, the vatt is using a manual path/resource.
|
|
// This is different to a resource with 0 clusters
|
|
if (vatt->vector_value(id_name, val) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
one_util::split_unique(val, ',', vatt_cluster_ids);
|
|
|
|
if ( vatt_cluster_ids.empty() )
|
|
{
|
|
return -2;
|
|
}
|
|
|
|
if ( cluster_ids.empty() )
|
|
{
|
|
cluster_ids = vatt_cluster_ids;
|
|
|
|
return 0;
|
|
}
|
|
|
|
set<int> intersection = one_util::set_intersection(cluster_ids,
|
|
vatt_cluster_ids);
|
|
|
|
if (intersection.empty())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
cluster_ids = intersection;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void update_os_file(VectorAttribute * os,
|
|
const string& base_name)
|
|
{
|
|
ClusterPool * clpool = Nebula::instance().get_clpool();
|
|
int ds_id;
|
|
set<int> cluster_ids;
|
|
|
|
string base_name_ds_id = base_name + "_DS_DSID";
|
|
string base_name_cluster = base_name + "_DS_CLUSTER_ID";
|
|
|
|
if (os->vector_value(base_name_ds_id, ds_id) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
clpool->query_datastore_clusters(ds_id, cluster_ids);
|
|
|
|
os->replace(base_name_cluster, one_util::join(cluster_ids, ','));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static void update_disk_cluster_id(VectorAttribute* disk)
|
|
{
|
|
ClusterPool * clpool = Nebula::instance().get_clpool();
|
|
int ds_id;
|
|
set<int> cluster_ids;
|
|
|
|
if (disk->vector_value("DATASTORE_ID", ds_id) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
clpool->query_datastore_clusters(ds_id, cluster_ids);
|
|
|
|
disk->replace("CLUSTER_ID", one_util::join(cluster_ids, ','));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static void update_nic_cluster_id(VectorAttribute* nic)
|
|
{
|
|
ClusterPool * clpool = Nebula::instance().get_clpool();
|
|
int vn_id;
|
|
set<int> cluster_ids;
|
|
|
|
if (nic->vector_value("NETWORK_ID", vn_id) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
clpool->query_vnet_clusters(vn_id, cluster_ids);
|
|
|
|
nic->replace("CLUSTER_ID", one_util::join(cluster_ids, ','));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
/**
|
|
* Returns the list of Cluster IDs where the VM can be deployed, based
|
|
* on the Datastores and VirtualNetworks requested
|
|
*
|
|
* @param tmpl of the VirtualMachine
|
|
* @param cluster_ids set of Cluster IDs
|
|
* @param error_str Returns the error reason, if any
|
|
* @return 0 on success
|
|
*/
|
|
static int get_cluster_requirements(Template *tmpl, set<int>& cluster_ids,
|
|
string& error_str)
|
|
{
|
|
ostringstream oss;
|
|
int num_vatts;
|
|
vector<VectorAttribute*> vatts;
|
|
|
|
int incomp_id;
|
|
int rc;
|
|
|
|
// Get cluster id from the KERNEL and INITRD (FILE Datastores)
|
|
VectorAttribute * osatt = tmpl->get("OS");
|
|
|
|
if ( osatt != 0 )
|
|
{
|
|
update_os_file(osatt, "KERNEL");
|
|
|
|
rc = check_and_set_cluster_id("KERNEL_DS_CLUSTER_ID", osatt, cluster_ids);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_kernel;
|
|
}
|
|
|
|
update_os_file(osatt, "INITRD");
|
|
|
|
rc = check_and_set_cluster_id("INITRD_DS_CLUSTER_ID", osatt, cluster_ids);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
goto error_initrd;
|
|
}
|
|
}
|
|
|
|
// Get cluster id from all DISK vector attributes (IMAGE Datastore)
|
|
num_vatts = tmpl->get("DISK",vatts);
|
|
|
|
for (int i=0; i<num_vatts; i++)
|
|
{
|
|
update_disk_cluster_id(vatts[i]);
|
|
|
|
rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_disk;
|
|
}
|
|
}
|
|
|
|
vatts.clear();
|
|
|
|
// Get cluster id from all NIC vector attributes
|
|
num_vatts = tmpl->get("NIC", vatts);
|
|
|
|
for (int i=0; i<num_vatts; i++)
|
|
{
|
|
update_nic_cluster_id(vatts[i]);
|
|
|
|
rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_nic;
|
|
}
|
|
}
|
|
|
|
vatts.clear();
|
|
|
|
// Get cluster id from all PCI attibutes, TYPE = NIC
|
|
num_vatts = tmpl->get("PCI", vatts);
|
|
|
|
for (int i=0; i<num_vatts; i++)
|
|
{
|
|
if ( vatts[i]->vector_value("TYPE") != "NIC" )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
update_nic_cluster_id(vatts[i]);
|
|
|
|
rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_pci;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_disk:
|
|
if (rc == -1)
|
|
{
|
|
oss << "Incompatible clusters in DISK. Datastore for DISK "<< incomp_id
|
|
<< " is not in the same cluster as the one used by other VM elements "
|
|
<< "(cluster " << one_util::join(cluster_ids, ',') << ")";
|
|
}
|
|
else
|
|
{
|
|
oss << "Missing clusters. Datastore for DISK "<< incomp_id
|
|
<< " is not in any cluster";
|
|
}
|
|
|
|
goto error_common;
|
|
|
|
error_kernel:
|
|
if (rc == -1)
|
|
{
|
|
oss<<"Incompatible cluster in KERNEL datastore, it should be in cluster "
|
|
<< one_util::join(cluster_ids, ',') << ".";
|
|
}
|
|
else
|
|
{
|
|
oss << "Missing clusters. KERNEL datastore is not in any cluster.";
|
|
}
|
|
|
|
goto error_common;
|
|
|
|
error_initrd:
|
|
if (rc == -1)
|
|
{
|
|
oss<<"Incompatible cluster in INITRD datastore, it should be in cluster "
|
|
<< one_util::join(cluster_ids, ',') << ".";
|
|
}
|
|
else
|
|
{
|
|
oss << "Missing clusters. INITRD datastore is not in any cluster.";
|
|
}
|
|
|
|
goto error_common;
|
|
|
|
error_nic:
|
|
if (rc == -1)
|
|
{
|
|
oss << "Incompatible clusters in NIC. Network for NIC "<< incomp_id
|
|
<< " is not in the same cluster as the one used by other VM elements "
|
|
<< "(cluster " << one_util::join(cluster_ids, ',') << ")";
|
|
}
|
|
else
|
|
{
|
|
oss << "Missing clusters. Network for NIC "<< incomp_id
|
|
<< " is not in any cluster";
|
|
}
|
|
|
|
goto error_common;
|
|
|
|
error_pci:
|
|
if (rc == -1)
|
|
{
|
|
oss << "Incompatible clusters in PCI (TYPE=NIC). Network for PCI "
|
|
<< incomp_id
|
|
<< " is not in the same cluster as the one used by other VM elements "
|
|
<< "(cluster " << one_util::join(cluster_ids, ',') << ")";
|
|
}
|
|
else
|
|
{
|
|
oss << "Missing clusters. Network for PCI "<< incomp_id
|
|
<< " is not in any cluster";
|
|
}
|
|
|
|
goto error_common;
|
|
|
|
error_common:
|
|
error_str = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
/**
|
|
* Returns the list of Datastore IDs where the VM can be deployed, based
|
|
* on the images and his image datastores
|
|
*
|
|
* @param tmpl of the VirtualMachine
|
|
* @param datastore_ids set of Cluster IDs
|
|
* @param error_str Returns the error reason, if any
|
|
* @return 0 on success
|
|
*/
|
|
static int get_datastore_requirements(Template *tmpl, set<int>& ds_ids,
|
|
bool& shareable, string& error_str)
|
|
{
|
|
ostringstream oss;
|
|
|
|
vector<VectorAttribute*> vatts;
|
|
set<int> csystem_ds;
|
|
shareable = false;
|
|
|
|
DatastorePool * ds_pool = Nebula::instance().get_dspool();
|
|
|
|
int incomp_id;
|
|
|
|
// Get cluster id from all DISK vector attributes (IMAGE Datastore)
|
|
int num_vatts = tmpl->get("DISK",vatts);
|
|
|
|
for (int i=0; i<num_vatts; i++, csystem_ds.clear())
|
|
{
|
|
bool is_shareable;
|
|
vatts[i]->vector_value("SHAREABLE", is_shareable);
|
|
shareable = shareable || is_shareable;
|
|
|
|
int val;
|
|
|
|
if (vatts[i]->vector_value("DATASTORE_ID", val) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (auto ds = ds_pool->get_ro(val))
|
|
{
|
|
ds->get_compatible_system_ds(csystem_ds);
|
|
|
|
int rc = check_and_set_datastores_id(csystem_ds, ds_ids);
|
|
|
|
if ( rc == -1 )
|
|
{
|
|
incomp_id = i;
|
|
goto error_disk;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_disk:
|
|
oss << "Incompatible system datastore in DISK. Images Datastore for DISK "
|
|
<< incomp_id
|
|
<< " has not the same complatible system datastore"
|
|
<< "(system datastores " << one_util::join(ds_ids, ',') << ")";
|
|
|
|
error_str = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::automatic_requirements(set<int>& cluster_ids,
|
|
string& error_str)
|
|
{
|
|
string tm_mad_system;
|
|
ostringstream oss;
|
|
set<string> clouds;
|
|
bool shareable = false;
|
|
set<int> datastore_ids;
|
|
|
|
obj_template->erase("AUTOMATIC_REQUIREMENTS");
|
|
obj_template->erase("AUTOMATIC_DS_REQUIREMENTS");
|
|
obj_template->erase("AUTOMATIC_NIC_REQUIREMENTS");
|
|
|
|
int rc = get_cluster_requirements(obj_template.get(), cluster_ids, error_str);
|
|
|
|
if (rc != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
rc = get_datastore_requirements(obj_template.get(), datastore_ids,
|
|
shareable, error_str);
|
|
|
|
if (rc == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if ( !cluster_ids.empty() )
|
|
{
|
|
auto i = cluster_ids.begin();
|
|
|
|
oss << "(CLUSTER_ID = " << *i;
|
|
|
|
for (++i; i != cluster_ids.end(); i++)
|
|
{
|
|
oss << " | CLUSTER_ID = " << *i;
|
|
}
|
|
|
|
oss << ") & !(PUBLIC_CLOUD = YES)";
|
|
}
|
|
else
|
|
{
|
|
oss << "!(PUBLIC_CLOUD = YES)";
|
|
}
|
|
|
|
if ( is_pinned() )
|
|
{
|
|
oss << " & (PIN_POLICY = PINNED)";
|
|
}
|
|
else
|
|
{
|
|
oss << " & !(PIN_POLICY = PINNED)";
|
|
}
|
|
|
|
int num_public = get_public_clouds(clouds);
|
|
|
|
if (num_public != 0)
|
|
{
|
|
auto it = clouds.begin();
|
|
|
|
oss << " | (PUBLIC_CLOUD = YES & (";
|
|
|
|
oss << "HYPERVISOR = " << *it;
|
|
|
|
for (++it; it != clouds.end() ; ++it)
|
|
{
|
|
oss << " | HYPERVISOR = " << *it;
|
|
}
|
|
|
|
oss << "))";
|
|
}
|
|
|
|
obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
|
|
|
|
oss.str("");
|
|
|
|
// Set automatic System DS requirements
|
|
|
|
if ( !cluster_ids.empty() || !datastore_ids.empty() )
|
|
{
|
|
if ( !cluster_ids.empty() )
|
|
{
|
|
auto i = cluster_ids.begin();
|
|
|
|
oss << "(\"CLUSTERS/ID\" @> " << *i;
|
|
|
|
for (++i; i != cluster_ids.end(); i++)
|
|
{
|
|
oss << " | \"CLUSTERS/ID\" @> " << *i;
|
|
}
|
|
|
|
oss << ")";
|
|
|
|
obj_template->add("AUTOMATIC_NIC_REQUIREMENTS", oss.str());
|
|
|
|
if ( !datastore_ids.empty() )
|
|
{
|
|
oss << " & ";
|
|
}
|
|
}
|
|
|
|
if ( !datastore_ids.empty() )
|
|
{
|
|
auto i = datastore_ids.begin();
|
|
|
|
oss << "(\"ID\" @> " << *i;
|
|
|
|
for (++i; i != datastore_ids.end(); i++)
|
|
{
|
|
oss << " | \"ID\" @> " << *i;
|
|
}
|
|
|
|
oss << ")";
|
|
|
|
}
|
|
|
|
if ( obj_template->get("TM_MAD_SYSTEM", tm_mad_system) )
|
|
{
|
|
oss << " & (TM_MAD = \"" << one_util::trim(tm_mad_system) << "\")";
|
|
}
|
|
}
|
|
|
|
if (shareable)
|
|
{
|
|
if (!oss.str().empty())
|
|
{
|
|
oss << " & ";
|
|
}
|
|
|
|
oss << "(SHARED = \"YES\")";
|
|
}
|
|
|
|
if (!oss.str().empty())
|
|
{
|
|
obj_template->add("AUTOMATIC_DS_REQUIREMENTS", oss.str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
|
|
{
|
|
ostringstream oss;
|
|
int rc;
|
|
|
|
string xml_body, short_xml_body, text;
|
|
|
|
char * sql_name;
|
|
char * sql_xml;
|
|
char * sql_short_xml;
|
|
char * sql_text;
|
|
|
|
sql_name = db->escape_str(name);
|
|
|
|
if ( sql_name == 0 )
|
|
{
|
|
goto error_generic;
|
|
}
|
|
|
|
sql_xml = db->escape_str(to_xml(xml_body));
|
|
|
|
if ( sql_xml == 0 )
|
|
{
|
|
goto error_body;
|
|
}
|
|
|
|
if ( validate_xml(sql_xml) != 0 )
|
|
{
|
|
goto error_xml;
|
|
}
|
|
|
|
sql_short_xml = db->escape_str(to_xml_short(short_xml_body));
|
|
|
|
if ( sql_short_xml == 0 )
|
|
{
|
|
goto error_body_short;
|
|
}
|
|
|
|
if ( validate_xml(sql_short_xml) != 0 )
|
|
{
|
|
goto error_xml_short;
|
|
}
|
|
|
|
sql_text = db->escape_str(to_token(text));
|
|
|
|
if ( sql_text == 0 )
|
|
{
|
|
goto error_text;
|
|
}
|
|
|
|
if (replace)
|
|
{
|
|
oss << "UPDATE " << one_db::vm_table << " SET "
|
|
<< "name = '" << sql_name << "', "
|
|
<< "body = '" << sql_xml << "', "
|
|
<< "uid = " << uid << ", "
|
|
<< "gid = " << gid << ", "
|
|
<< "state = " << state << ", "
|
|
<< "lcm_state = " << lcm_state << ", "
|
|
<< "owner_u = " << owner_u << ", "
|
|
<< "group_u = " << group_u << ", "
|
|
<< "other_u = " << other_u << ", "
|
|
<< "short_body = '" << sql_short_xml << "' "
|
|
<< "WHERE oid = " << oid;
|
|
}
|
|
else
|
|
{
|
|
oss << "INSERT INTO " << one_db::vm_table
|
|
<< " ("<< one_db::vm_db_names << ") VALUES ("
|
|
<< oid << ","
|
|
<< "'" << sql_name << "',"
|
|
<< "'" << sql_xml << "',"
|
|
<< uid << ","
|
|
<< gid << ","
|
|
<< state << ","
|
|
<< lcm_state << ","
|
|
<< owner_u << ","
|
|
<< group_u << ","
|
|
<< other_u << ","
|
|
<< "'" << sql_short_xml << "',"
|
|
<< "'" << sql_text << "'"
|
|
<< ")";
|
|
}
|
|
|
|
db->free_str(sql_name);
|
|
db->free_str(sql_xml);
|
|
db->free_str(sql_short_xml);
|
|
db->free_str(sql_text);
|
|
|
|
rc = db->exec_wr(oss);
|
|
|
|
return rc;
|
|
|
|
error_text:
|
|
db->free_str(sql_text);
|
|
error_xml_short:
|
|
db->free_str(sql_short_xml);
|
|
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_short:
|
|
db->free_str(sql_xml);
|
|
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_search(SqlDB * db)
|
|
{
|
|
std::ostringstream oss;
|
|
std::string text;
|
|
|
|
char * sql_text = db->escape_str(to_token(text));
|
|
|
|
if ( sql_text == 0 )
|
|
{
|
|
NebulaLog::log("ONE", Log::ERROR, "Error updating VM search token");
|
|
return -1;
|
|
}
|
|
|
|
oss << "UPDATE " << one_db::vm_table << " SET "
|
|
<< "search_token = '" << sql_text << "' "
|
|
<< "WHERE oid = " << oid;
|
|
|
|
db->free_str(sql_text);
|
|
|
|
return db->exec_wr(oss);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::add_history(
|
|
int hid,
|
|
int cid,
|
|
const string& hostname,
|
|
const string& vmm_mad,
|
|
const string& tm_mad,
|
|
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, tm_mad, 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->tm_mad_name,
|
|
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->tm_mad_name,
|
|
previous_history->ds_id,
|
|
vm_xml);
|
|
|
|
previous_history = history;
|
|
history = htmp;
|
|
|
|
history_records.push_back(history);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::get_capacity(HostShareCapacity& sr) const
|
|
{
|
|
float fcpu;
|
|
|
|
sr.pci.clear();
|
|
sr.nodes.clear();
|
|
|
|
sr.vmid = oid;
|
|
|
|
if ((get_template_attribute("MEMORY", sr.mem) == false) ||
|
|
(get_template_attribute("CPU", fcpu) == false))
|
|
{
|
|
sr.cpu = 0;
|
|
sr.mem = 0;
|
|
sr.disk = 0;
|
|
|
|
sr.vcpu = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
sr.cpu = (int) (fcpu * 100); //%
|
|
sr.mem = sr.mem * 1024; //Kb
|
|
sr.disk = 0;
|
|
|
|
get_template_attribute("VCPU", sr.vcpu);
|
|
|
|
obj_template->get("PCI", sr.pci);
|
|
|
|
obj_template->get("NUMA_NODE", sr.nodes);
|
|
|
|
sr.topology = obj_template->get("TOPOLOGY");
|
|
|
|
return;
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::resize(float cpu, long int memory, unsigned int vcpu,
|
|
string& error)
|
|
{
|
|
unsigned int s, c, t;
|
|
|
|
s = c = t = 0;
|
|
|
|
if (cpu > 0)
|
|
{
|
|
replace_template_attribute("CPU", cpu);
|
|
}
|
|
|
|
if (memory > 0)
|
|
{
|
|
replace_template_attribute("MEMORY", memory);
|
|
}
|
|
|
|
if (vcpu > 0)
|
|
{
|
|
replace_template_attribute("VCPU", vcpu);
|
|
}
|
|
else
|
|
{
|
|
get_template_attribute("VCPU", vcpu);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Update the NUMA topology with new size: */
|
|
/* 1. Increase number of cores for new VCPU (keep threads and sockets) */
|
|
/* 2. Clear current nodes and build new ones with new MEMORY/VCPU */
|
|
/* ---------------------------------------------------------------------- */
|
|
VectorAttribute * vtopol = get_template_attribute("TOPOLOGY");
|
|
|
|
if ( vtopol == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
vtopol->vector_value("SOCKETS", s);
|
|
vtopol->vector_value("CORES", c);
|
|
vtopol->vector_value("THREADS", t);
|
|
|
|
if ( s != 0 && c != 0 && t != 0 && (s * c * t) != vcpu)
|
|
{
|
|
if ( vcpu%(t * s) != 0 )
|
|
{
|
|
error = "new VCPU is not multiple of the total number of threads";
|
|
return -1;
|
|
}
|
|
|
|
c = vcpu/(t * s);
|
|
|
|
vtopol->replace("CORES", c);
|
|
}
|
|
|
|
remove_template_attribute("NUMA_NODE");
|
|
|
|
return parse_topology(obj_template.get(), error);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::store_resize(float cpu, long int memory, unsigned int vcpu)
|
|
{
|
|
auto vattr = new VectorAttribute("RESIZE");
|
|
vattr->replace("CPU", cpu);
|
|
vattr->replace("VCPU", vcpu);
|
|
vattr->replace("MEMORY", memory);
|
|
|
|
obj_template->erase("RESIZE");
|
|
obj_template->set(vattr);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::reset_resize()
|
|
{
|
|
obj_template->erase("RESIZE");
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool VirtualMachine::is_imported() const
|
|
{
|
|
bool imported = false;
|
|
|
|
get_template_attribute("IMPORTED", imported);
|
|
|
|
return imported;
|
|
}
|
|
|
|
string VirtualMachine::get_import_state() const
|
|
{
|
|
string import_state;
|
|
|
|
user_obj_template->get("IMPORT_STATE", import_state);
|
|
user_obj_template->erase("IMPORT_STATE");
|
|
|
|
return import_state;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool VirtualMachine::is_imported_action_supported(VMActions::Action action) const
|
|
{
|
|
if (!hasHistory())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VirtualMachineManager * vmm = Nebula::instance().get_vmm();
|
|
|
|
return vmm->is_imported_action_supported(get_vmm_mad(), action);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::remove_security_group(int sgid)
|
|
{
|
|
int num_sgs;
|
|
int ssgid;
|
|
|
|
vector<VectorAttribute *> sgs;
|
|
|
|
num_sgs = obj_template->get("SECURITY_GROUP_RULE", sgs);
|
|
|
|
for (int i=0; i<num_sgs; i++)
|
|
{
|
|
sgs[i]->vector_value("SECURITY_GROUP_ID", ssgid);
|
|
|
|
if ( ssgid == sgid )
|
|
{
|
|
obj_template->remove(sgs[i]);
|
|
delete sgs[i];
|
|
}
|
|
}
|
|
|
|
SecurityGroupPool* sgpool = Nebula::instance().get_secgrouppool();
|
|
sgpool->release_security_group(oid, sgid);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_vrouter_id() const
|
|
{
|
|
int vrid;
|
|
|
|
if (!obj_template->get("VROUTER_ID", vrid))
|
|
{
|
|
vrid = -1;
|
|
}
|
|
|
|
return vrid;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool VirtualMachine::is_vrouter() const
|
|
{
|
|
return get_vrouter_id() != -1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::set_auth_request(int uid,
|
|
AuthRequest& ar,
|
|
VirtualMachineTemplate *tmpl,
|
|
bool check_lock)
|
|
{
|
|
VirtualMachineDisks tdisks(tmpl, false);
|
|
|
|
for (auto disk : tdisks)
|
|
{
|
|
disk->authorize(uid, &ar, check_lock);
|
|
}
|
|
|
|
VirtualMachineNics tnics(tmpl);
|
|
|
|
for (auto nic : tnics)
|
|
{
|
|
nic->authorize(uid, &ar, check_lock);
|
|
}
|
|
|
|
const VectorAttribute * vmgroup = tmpl->get("VMGROUP");
|
|
|
|
if ( vmgroup != 0 )
|
|
{
|
|
VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
|
|
|
|
vmgrouppool->authorize(vmgroup, uid, &ar);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
|
|
{
|
|
string template_xml;
|
|
string user_template_xml;
|
|
string history_xml;
|
|
string perm_xml;
|
|
string snap_xml;
|
|
string lock_str;
|
|
|
|
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>" << monitoring.timestamp() << "</LAST_POLL>"
|
|
<< "<STATE>" << state << "</STATE>"
|
|
<< "<LCM_STATE>" << lcm_state << "</LCM_STATE>"
|
|
<< "<PREV_STATE>" << prev_state << "</PREV_STATE>"
|
|
<< "<PREV_LCM_STATE>" << prev_lcm_state << "</PREV_LCM_STATE>"
|
|
<< "<RESCHED>" << resched << "</RESCHED>"
|
|
<< "<STIME>" << stime << "</STIME>"
|
|
<< "<ETIME>" << etime << "</ETIME>"
|
|
<< "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>"
|
|
<< lock_db_to_xml(lock_str)
|
|
<< monitoring.to_xml()
|
|
<< 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/>";
|
|
}
|
|
|
|
VirtualMachineDisks::disk_iterator disk;
|
|
|
|
for (auto disk = const_cast<VirtualMachineDisks *>(&disks)->begin() ;
|
|
disk != const_cast<VirtualMachineDisks *>(&disks)->end() ; ++disk)
|
|
{
|
|
const Snapshots * snapshots = (*disk)->get_snapshots();
|
|
|
|
if ( snapshots != 0 )
|
|
{
|
|
oss << snapshots->to_xml(snap_xml);
|
|
}
|
|
}
|
|
|
|
oss << "</VM>";
|
|
|
|
xml = oss.str();
|
|
|
|
return xml;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::to_json(string& json) const
|
|
{
|
|
string template_json;
|
|
string user_template_json;
|
|
string history_json;
|
|
|
|
ostringstream oss;
|
|
|
|
oss << "{\"VM\":{"
|
|
<< "\"ID\": \""<< oid << "\","
|
|
<< "\"UID\": \""<< uid << "\","
|
|
<< "\"GID\": \""<< gid << "\","
|
|
<< "\"UNAME\": \""<< uname << "\","
|
|
<< "\"GNAME\": \""<< gname << "\","
|
|
<< "\"NAME\": \""<< name << "\","
|
|
<< "\"LAST_POLL\": \""<< monitoring.timestamp() << "\","
|
|
<< "\"STATE\": \""<< state << "\","
|
|
<< "\"LCM_STATE\": \""<< lcm_state << "\","
|
|
<< "\"PREV_STATE\": \""<< prev_state << "\","
|
|
<< "\"PREV_LCM_STATE\": \""<< prev_lcm_state << "\","
|
|
<< "\"RESCHED\": \""<< resched << "\","
|
|
<< "\"STIME\": \""<< stime << "\","
|
|
<< "\"ETIME\": \""<< etime << "\","
|
|
<< "\"DEPLOY_ID\": \""<< deploy_id << "\","
|
|
<< obj_template->to_json(template_json) << ","
|
|
<< user_obj_template->to_json(user_template_json);
|
|
|
|
if ( hasHistory() )
|
|
{
|
|
oss << ",\"HISTORY_RECORDS\": [";
|
|
|
|
oss << history->to_json(history_json);
|
|
|
|
oss << "]";
|
|
}
|
|
|
|
oss << "}}";
|
|
|
|
|
|
json = oss.str();
|
|
|
|
return json;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::to_token(string& text) const
|
|
{
|
|
string template_text;
|
|
string user_template_text;
|
|
string history_text;
|
|
|
|
ostringstream oss;
|
|
|
|
oss << "UNAME="<< uname << "\n"
|
|
<< "GNAME="<< gname << "\n"
|
|
<< obj_template->to_token(template_text) << "\n"
|
|
<< user_obj_template->to_token(user_template_text)
|
|
<< "NAME=";
|
|
|
|
one_util::escape_token(name, oss);
|
|
|
|
oss << "\n";
|
|
|
|
if ( hasHistory() )
|
|
{
|
|
oss << "\n" << history->to_token(history_text);
|
|
}
|
|
|
|
text = oss.str();
|
|
|
|
return text;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string& VirtualMachine::to_xml_short(string& xml)
|
|
{
|
|
string disks_xml, user_template_xml, history_xml, nics_xml;
|
|
string cpu_tmpl, mem_tmpl;
|
|
|
|
ostringstream oss;
|
|
|
|
obj_template->get("CPU", cpu_tmpl);
|
|
obj_template->get("MEMORY", mem_tmpl);
|
|
|
|
oss << "<VM>"
|
|
<< "<ID>" << oid << "</ID>"
|
|
<< "<UID>" << uid << "</UID>"
|
|
<< "<GID>" << gid << "</GID>"
|
|
<< "<UNAME>" << uname << "</UNAME>"
|
|
<< "<GNAME>" << gname << "</GNAME>"
|
|
<< "<NAME>" << name << "</NAME>"
|
|
<< "<LAST_POLL>" << monitoring.timestamp() << "</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>";
|
|
|
|
if (locked != PoolObjectSQL::ST_NONE)
|
|
{
|
|
oss << "<LOCK><LOCKED>" << static_cast<int>(locked) << "</LOCKED></LOCK>";
|
|
}
|
|
|
|
oss << "<TEMPLATE>"
|
|
<< "<CPU>" << cpu_tmpl << "</CPU>"
|
|
<< "<MEMORY>" << mem_tmpl << "</MEMORY>"
|
|
<< disks.to_xml_short(disks_xml)
|
|
<< nics.to_xml_short(nics_xml);
|
|
|
|
VectorAttribute * graph = obj_template->get("GRAPHICS");
|
|
|
|
if ( graph != 0 )
|
|
{
|
|
graph->to_xml(oss);
|
|
}
|
|
|
|
oss << "</TEMPLATE>"
|
|
<< monitoring.to_xml_short()
|
|
<< user_obj_template->to_xml_short(user_template_xml);
|
|
|
|
if ( hasHistory() )
|
|
{
|
|
oss << "<HISTORY_RECORDS>";
|
|
oss << history_records[history_records.size() - 1]->to_xml_short(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
|
|
rc = update_from_str(xml_str);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// 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(resched, "/VM/RESCHED", 0);
|
|
|
|
rc += xpath<time_t>(stime, "/VM/STIME", 0);
|
|
rc += xpath<time_t>(etime, "/VM/ETIME", 0);
|
|
rc += xpath(deploy_id, "/VM/DEPLOY_ID","");
|
|
|
|
// Permissions
|
|
rc += perms_from_xml();
|
|
|
|
//VM states
|
|
rc += xpath(istate, "/VM/STATE", 0);
|
|
rc += xpath(ilcmstate, "/VM/LCM_STATE", 0);
|
|
|
|
state = static_cast<VmState>(istate);
|
|
lcm_state = static_cast<LcmState>(ilcmstate);
|
|
|
|
xpath(istate, "/VM/PREV_STATE", istate);
|
|
xpath(ilcmstate, "/VM/PREV_LCM_STATE", ilcmstate);
|
|
|
|
prev_state = static_cast<VmState>(istate);
|
|
prev_lcm_state = static_cast<LcmState>(ilcmstate);
|
|
|
|
rc += lock_db_from_xml();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Virtual Machine template and attributes
|
|
// -------------------------------------------------------------------------
|
|
ObjectXML::get_nodes("/VM/TEMPLATE", content);
|
|
|
|
if (content.empty())
|
|
{
|
|
return -1;
|
|
}
|
|
rc += obj_template->from_xml_node(content[0]);
|
|
|
|
vector<VectorAttribute *> vdisks, vnics, alias, pcis;
|
|
|
|
obj_template->get("DISK", vdisks);
|
|
|
|
disks.init(vdisks, true);
|
|
|
|
obj_template->get("NIC", vnics);
|
|
|
|
obj_template->get("NIC_ALIAS", alias);
|
|
|
|
obj_template->get("PCI", pcis);
|
|
|
|
for (auto vattr : pcis)
|
|
{
|
|
if ( vattr->vector_value("TYPE") == "NIC" )
|
|
{
|
|
vnics.push_back(vattr);
|
|
}
|
|
}
|
|
|
|
for (auto vattr : alias)
|
|
{
|
|
vnics.push_back(vattr);
|
|
}
|
|
|
|
nics.init(vnics, true);
|
|
|
|
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
|
|
// -------------------------------------------------------------------------
|
|
int last_seq;
|
|
|
|
if ( xpath(last_seq,"/VM/HISTORY_RECORDS/HISTORY/SEQ", -1) == 0 &&
|
|
last_seq != -1 )
|
|
{
|
|
history_records.resize(last_seq + 1);
|
|
|
|
for (int i=0; i <= last_seq; ++i)
|
|
{
|
|
history_records[i] = 0;
|
|
}
|
|
|
|
history = new History(oid, last_seq);
|
|
|
|
history_records[last_seq] = history;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Virtual Machine Snapshots
|
|
// -------------------------------------------------------------------------
|
|
ObjectXML::get_nodes("/VM/SNAPSHOTS", content);
|
|
|
|
for (auto node : content)
|
|
{
|
|
Snapshots * snap = new Snapshots(-1, Snapshots::DENY);
|
|
|
|
rc += snap->from_xml_node(node);
|
|
|
|
if ( rc != 0)
|
|
{
|
|
delete snap;
|
|
break;
|
|
}
|
|
|
|
disks.set_snapshots(snap->get_disk_id(), snap);
|
|
}
|
|
|
|
if (!content.empty())
|
|
{
|
|
ObjectXML::free_nodes(content);
|
|
content.clear();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------
|
|
if (rc != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::load_monitoring()
|
|
{
|
|
// Get last monitoring record
|
|
auto vmpool = Nebula::instance().get_vmpool();
|
|
monitoring = vmpool->get_monitoring(oid);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::replace_template(
|
|
const string& tmpl_str,
|
|
bool keep_restricted,
|
|
string& error)
|
|
{
|
|
string ra;
|
|
|
|
auto new_tmpl =
|
|
make_unique<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 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Replace new_tmpl to the current user_template */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
if (user_obj_template)
|
|
{
|
|
if (keep_restricted &&
|
|
new_tmpl->check_restricted(ra, user_obj_template.get()))
|
|
{
|
|
error = "Tried to change restricted attribute: " + ra;
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
else if (keep_restricted && new_tmpl->check_restricted(ra))
|
|
{
|
|
error = "Tried to set restricted attribute: " + ra;
|
|
|
|
return -1;
|
|
}
|
|
|
|
auto old_user_tmpl = move(user_obj_template);
|
|
user_obj_template = move(new_tmpl);
|
|
|
|
if (post_update_template(error) == -1)
|
|
{
|
|
user_obj_template = move(old_user_tmpl);
|
|
|
|
return -1;
|
|
}
|
|
|
|
encrypt();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::append_template(
|
|
const string& tmpl_str,
|
|
bool keep_restricted,
|
|
string& error)
|
|
{
|
|
auto new_tmpl =
|
|
make_unique<VirtualMachineTemplate>(false,'=',"USER_TEMPLATE");
|
|
string rname;
|
|
|
|
if ( new_tmpl == 0 )
|
|
{
|
|
error = "Cannot allocate a new template";
|
|
return -1;
|
|
}
|
|
|
|
if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Append new_tmpl to the current user_template */
|
|
/* ---------------------------------------------------------------------- */
|
|
auto old_user_tmpl = make_unique<VirtualMachineTemplate>(*user_obj_template);
|
|
|
|
if (user_obj_template != 0)
|
|
{
|
|
if (keep_restricted &&
|
|
new_tmpl->check_restricted(rname, user_obj_template.get()))
|
|
{
|
|
error ="User Template includes a restricted attribute " + rname;
|
|
|
|
return -1;
|
|
}
|
|
|
|
user_obj_template->merge(new_tmpl.get());
|
|
}
|
|
else
|
|
{
|
|
if (keep_restricted && new_tmpl->check_restricted(rname))
|
|
{
|
|
error ="User Template includes a restricted attribute " + rname;
|
|
|
|
return -1;
|
|
}
|
|
|
|
user_obj_template = move(new_tmpl);
|
|
}
|
|
|
|
if (post_update_template(error) == -1)
|
|
{
|
|
user_obj_template = move(old_user_tmpl);
|
|
|
|
return -1;
|
|
}
|
|
|
|
encrypt();
|
|
|
|
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::get_public_clouds(const string& pname, set<string> &clouds) const
|
|
{
|
|
vector<VectorAttribute *> attrs;
|
|
|
|
user_obj_template->get(pname, attrs);
|
|
|
|
if ( !attrs.empty() && pname == "EC2" )
|
|
{
|
|
clouds.insert("ec2");
|
|
}
|
|
|
|
for (auto vattr : attrs)
|
|
{
|
|
string type = vattr->vector_value("TYPE");
|
|
|
|
if (!type.empty())
|
|
{
|
|
clouds.insert(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
|
/**
|
|
* Replaces the values of a vector value, preserving the existing ones
|
|
*/
|
|
static void replace_vector_values(Template *old_tmpl, Template *new_tmpl,
|
|
const char * name, bool append)
|
|
{
|
|
string value;
|
|
|
|
VectorAttribute * new_attr = new_tmpl->get(name);
|
|
VectorAttribute * old_attr = old_tmpl->get(name);
|
|
|
|
if ( new_attr == 0 )
|
|
{
|
|
if ( !append )
|
|
{
|
|
old_tmpl->erase(name);
|
|
}
|
|
}
|
|
else if ( old_attr == 0 )
|
|
{
|
|
old_tmpl->set(new_attr->clone());
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> vnames = VirtualMachineTemplate::UPDATECONF_ATTRS[name];
|
|
|
|
for (const auto& vname : vnames)
|
|
{
|
|
if ( new_attr->vector_value(vname, value) == -1 )
|
|
{
|
|
if ( !append )
|
|
{
|
|
old_attr->remove(vname);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
old_attr->replace(vname, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::updateconf(VirtualMachineTemplate* tmpl, string &err,
|
|
bool append)
|
|
{
|
|
switch (state)
|
|
{
|
|
case PENDING:
|
|
case HOLD:
|
|
case POWEROFF:
|
|
case UNDEPLOYED:
|
|
case CLONING:
|
|
case CLONING_FAILURE:
|
|
break;
|
|
|
|
case ACTIVE:
|
|
switch (lcm_state)
|
|
{
|
|
case LCM_INIT:
|
|
case PROLOG:
|
|
case RUNNING:
|
|
case EPILOG:
|
|
case SHUTDOWN:
|
|
case CLEANUP_RESUBMIT:
|
|
case SHUTDOWN_POWEROFF:
|
|
case CLEANUP_DELETE:
|
|
case HOTPLUG_SAVEAS_POWEROFF:
|
|
case SHUTDOWN_UNDEPLOY:
|
|
case EPILOG_UNDEPLOY:
|
|
case PROLOG_UNDEPLOY:
|
|
case HOTPLUG_PROLOG_POWEROFF:
|
|
case HOTPLUG_EPILOG_POWEROFF:
|
|
case BOOT_FAILURE:
|
|
case PROLOG_FAILURE:
|
|
case EPILOG_FAILURE:
|
|
case EPILOG_UNDEPLOY_FAILURE:
|
|
case PROLOG_MIGRATE_POWEROFF:
|
|
case PROLOG_MIGRATE_POWEROFF_FAILURE:
|
|
case BOOT_UNDEPLOY_FAILURE:
|
|
case PROLOG_UNDEPLOY_FAILURE:
|
|
case DISK_SNAPSHOT_POWEROFF:
|
|
case DISK_SNAPSHOT_REVERT_POWEROFF:
|
|
case DISK_SNAPSHOT_DELETE_POWEROFF:
|
|
break;
|
|
|
|
default:
|
|
err = "configuration cannot be updated in state " + state_str();
|
|
return -1;
|
|
};
|
|
break;
|
|
|
|
case INIT:
|
|
case DONE:
|
|
case SUSPENDED:
|
|
case STOPPED:
|
|
|
|
err = "configuration cannot be updated in state " + state_str();
|
|
return -1;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Validates RAW data section
|
|
// -------------------------------------------------------------------------
|
|
if (Nebula::instance().get_vmm()->validate_raw(tmpl, err) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Update OS, FEATURES, INPUT, GRAPHICS, RAW, CPU_MODEL
|
|
// -------------------------------------------------------------------------
|
|
replace_vector_values(obj_template.get(), tmpl, "OS", append);
|
|
|
|
if ( set_boot_order(obj_template.get(), err) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
replace_vector_values(obj_template.get(), tmpl, "FEATURES", append);
|
|
|
|
replace_vector_values(obj_template.get(), tmpl, "INPUT", append);
|
|
|
|
replace_vector_values(obj_template.get(), tmpl, "GRAPHICS", append);
|
|
|
|
replace_vector_values(obj_template.get(), tmpl, "RAW", append);
|
|
|
|
replace_vector_values(obj_template.get(), tmpl, "CPU_MODEL", append);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Update CONTEXT: any value
|
|
// -------------------------------------------------------------------------
|
|
VectorAttribute * context_bck = obj_template->get("CONTEXT");
|
|
VectorAttribute * context_new = tmpl->get("CONTEXT");
|
|
|
|
if ( context_bck == 0 && context_new != 0 )
|
|
{
|
|
err = "Virtual machine does not have context, cannot add a new one.";
|
|
|
|
return -1;
|
|
}
|
|
else if ( context_bck != 0 && context_new != 0 )
|
|
{
|
|
context_new = context_new->clone();
|
|
|
|
// Remove equal values from the new context
|
|
map<string, string> equal_values;
|
|
for (auto in = context_new->value().cbegin(),
|
|
ib = context_bck->value().cbegin(),
|
|
endn = context_new->value().cend(),
|
|
endb = context_bck->value().cend();
|
|
in != endn && ib != endb;)
|
|
{
|
|
if (in->first < ib->first)
|
|
++in;
|
|
else if (ib->first < in->first)
|
|
++ib;
|
|
else
|
|
{
|
|
if (in->second == ib->second)
|
|
{
|
|
equal_values.insert(make_pair(in->first, in->second));
|
|
}
|
|
++in;
|
|
++ib;
|
|
}
|
|
}
|
|
|
|
for (const auto& attr : equal_values)
|
|
{
|
|
context_new->remove(attr.first);
|
|
}
|
|
|
|
context_new->replace("TARGET", context_bck->vector_value("TARGET"));
|
|
context_new->replace("DISK_ID", context_bck->vector_value("DISK_ID"));
|
|
|
|
obj_template->remove(context_bck);
|
|
obj_template->set(context_new);
|
|
|
|
if ( parse_context(err, true) != 0 )
|
|
{
|
|
obj_template->erase("CONTEXT");
|
|
obj_template->set(context_bck);
|
|
|
|
return -1;
|
|
}
|
|
|
|
context_new = obj_template->get("CONTEXT");
|
|
|
|
if (append)
|
|
{
|
|
obj_template->remove(context_new);
|
|
obj_template->set(context_bck);
|
|
|
|
context_bck->merge(context_new, true);
|
|
|
|
delete context_new;
|
|
}
|
|
else
|
|
{
|
|
for (const auto& attr : equal_values)
|
|
{
|
|
context_new->replace(attr.first, attr.second);
|
|
}
|
|
|
|
delete context_bck;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Parse graphics attribute
|
|
// -------------------------------------------------------------------------
|
|
if ( parse_graphics(err, obj_template.get()) != 0 )
|
|
{
|
|
NebulaLog::log("ONE",Log::ERROR, err);
|
|
return -1;
|
|
}
|
|
|
|
encrypt();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* VirtualMachine Disks Interface */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_disk_images(string& error_str)
|
|
{
|
|
vector<Attribute *> adisks;
|
|
vector<Attribute *> acontext_disks;
|
|
|
|
int num_context = user_obj_template->remove("CONTEXT", acontext_disks);
|
|
int num_disks = user_obj_template->remove("DISK", adisks);
|
|
|
|
for (auto it = acontext_disks.begin(); it != acontext_disks.end(); )
|
|
{
|
|
if ( (*it)->type() != Attribute::VECTOR )
|
|
{
|
|
delete *it;
|
|
num_context--;
|
|
it = acontext_disks.erase(it);
|
|
}
|
|
else
|
|
{
|
|
obj_template->set(*it);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
for (auto it = adisks.begin(); it != adisks.end(); )
|
|
{
|
|
if ( (*it)->type() != Attribute::VECTOR )
|
|
{
|
|
delete *it;
|
|
num_disks--;
|
|
it = adisks.erase(it);
|
|
}
|
|
else
|
|
{
|
|
obj_template->set(*it);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if ( num_disks > 20 )
|
|
{
|
|
error_str = "Exceeded the maximum number of disks (20)";
|
|
return -1;
|
|
}
|
|
|
|
VectorAttribute * context = 0;
|
|
|
|
if ( num_context > 0 )
|
|
{
|
|
context = static_cast<VectorAttribute * >(acontext_disks[0]);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Deployment mode for the VM disks
|
|
// -------------------------------------------------------------------------
|
|
std::string tm_mad_sys;
|
|
|
|
if ( user_obj_template->get("TM_MAD_SYSTEM", tm_mad_sys) == true )
|
|
{
|
|
user_obj_template->erase("TM_MAD_SYSTEM");
|
|
|
|
obj_template->add("TM_MAD_SYSTEM", tm_mad_sys);
|
|
}
|
|
|
|
return disks.get_images(oid, uid, tm_mad_sys, adisks, context, error_str);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::release_disk_images(vector<Template *>& quotas,
|
|
bool set_state)
|
|
{
|
|
bool image_error;
|
|
|
|
if ( set_state )
|
|
{
|
|
image_error = (state == ACTIVE && lcm_state != EPILOG) &&
|
|
state != PENDING && state != HOLD &&
|
|
state != CLONING && state != CLONING_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
image_error = false;
|
|
}
|
|
|
|
disks.release_images(oid, image_error, quotas);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_up_attach_disk(VirtualMachineTemplate * tmpl, string& err)
|
|
{
|
|
VectorAttribute * new_vdisk = tmpl->get("DISK");
|
|
|
|
if ( new_vdisk == 0 )
|
|
{
|
|
err = "Internal error parsing DISK attribute";
|
|
return -1;
|
|
}
|
|
|
|
new_vdisk = new_vdisk->clone();
|
|
|
|
VectorAttribute * context = get_template_attribute("CONTEXT");
|
|
|
|
VirtualMachineDisk * new_disk;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Deployment mode for the VM disks
|
|
// -------------------------------------------------------------------------
|
|
std::string tm_mad_sys;
|
|
|
|
obj_template->get("TM_MAD_SYSTEM", tm_mad_sys);
|
|
|
|
new_disk = disks.set_up_attach(oid, uid, get_cid(), new_vdisk, tm_mad_sys, context, err);
|
|
|
|
if ( new_disk == 0 )
|
|
{
|
|
delete new_vdisk;
|
|
return -1;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Add new disk to template and set info in history before attaching
|
|
// -------------------------------------------------------------------------
|
|
set_vm_info();
|
|
|
|
obj_template->set(new_disk->vector_attribute());
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Disk save as interface */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_saveas_state()
|
|
{
|
|
switch (state)
|
|
{
|
|
case ACTIVE:
|
|
if (lcm_state != RUNNING)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
set_state(HOTPLUG_SAVEAS);
|
|
break;
|
|
|
|
case POWEROFF:
|
|
set_state(ACTIVE);
|
|
set_state(HOTPLUG_SAVEAS_POWEROFF);
|
|
break;
|
|
|
|
case SUSPENDED:
|
|
set_state(ACTIVE);
|
|
set_state(HOTPLUG_SAVEAS_SUSPENDED);
|
|
break;
|
|
|
|
case UNDEPLOYED:
|
|
set_state(ACTIVE);
|
|
set_state(HOTPLUG_SAVEAS_UNDEPLOYED);
|
|
break;
|
|
|
|
case STOPPED:
|
|
set_state(ACTIVE);
|
|
set_state(HOTPLUG_SAVEAS_STOPPED);
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::clear_saveas_state()
|
|
{
|
|
switch (lcm_state)
|
|
{
|
|
case HOTPLUG_SAVEAS:
|
|
set_state(RUNNING);
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_POWEROFF:
|
|
set_state(POWEROFF);
|
|
set_state(LCM_INIT);
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_SUSPENDED:
|
|
set_state(SUSPENDED);
|
|
set_state(LCM_INIT);
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_UNDEPLOYED:
|
|
set_state(UNDEPLOYED);
|
|
set_state(LCM_INIT);
|
|
break;
|
|
|
|
case HOTPLUG_SAVEAS_STOPPED:
|
|
set_state(STOPPED);
|
|
set_state(LCM_INIT);
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* VirtualMachine Nic interface */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_auto_network_leases(VirtualMachineTemplate * tmpl,
|
|
string& estr)
|
|
{
|
|
vector<VectorAttribute *> vnics;
|
|
|
|
int nic_id;
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Update auto NICs with the scheduling resulti */
|
|
/* ---------------------------------------------------------------------- */
|
|
tmpl->get("NIC", vnics);
|
|
|
|
for (auto vattr : vnics)
|
|
{
|
|
std::string net_mode;
|
|
|
|
vattr->vector_value("NIC_ID", nic_id);
|
|
|
|
VirtualMachineNic * nic = get_nic(nic_id);
|
|
|
|
net_mode = nic->vector_value("NETWORK_MODE");
|
|
|
|
string network_id = nic->vector_value("NETWORK_ID");
|
|
|
|
if (nic == 0 || !one_util::icasecmp(net_mode, "AUTO") || !network_id.empty())
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
oss << "NIC_ID "<< nic_id << " not found or not AUTO";
|
|
estr = oss.str();
|
|
|
|
return -1;
|
|
}
|
|
|
|
nic->replace("NETWORK_ID", vattr->vector_value("NETWORK_ID"));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the network leases & security groups for NICs in auto mode */
|
|
/* ---------------------------------------------------------------------- */
|
|
vector<VectorAttribute*> sgs;
|
|
|
|
vector<Attribute *> anics;
|
|
|
|
VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
|
|
|
|
if (nics.get_auto_network_leases(oid, uid, nic_default, sgs, estr) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
obj_template->set(sgs);
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Generate the CONTEXT for NICs in auto mode */
|
|
/* ---------------------------------------------------------------------- */
|
|
VectorAttribute * context = obj_template->get("CONTEXT");
|
|
|
|
if ( context == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( generate_network_context(context, estr, true) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VirtualMachine::get_network_leases(string& estr)
|
|
{
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the NIC attributes: */
|
|
/* * NIC */
|
|
/* * NIC_ALIAS */
|
|
/* * PCI + TYPE = NIC */
|
|
/* ---------------------------------------------------------------------- */
|
|
vector<Attribute *> anics;
|
|
vector<Attribute *> alias;
|
|
|
|
user_obj_template->remove("NIC", anics);
|
|
|
|
for (auto it = anics.begin(); it != anics.end(); )
|
|
{
|
|
if ( (*it)->type() != Attribute::VECTOR )
|
|
{
|
|
delete *it;
|
|
it = anics.erase(it);
|
|
}
|
|
else
|
|
{
|
|
obj_template->set(*it);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
user_obj_template->remove("NIC_ALIAS", alias);
|
|
|
|
for (auto it = alias.begin(); it != alias.end(); )
|
|
{
|
|
if ( (*it)->type() != Attribute::VECTOR )
|
|
{
|
|
delete *it;
|
|
it = alias.erase(it);
|
|
}
|
|
else
|
|
{
|
|
obj_template->set(*it);
|
|
anics.push_back(*it);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
vector<VectorAttribute *> pcis;
|
|
|
|
get_template_attribute("PCI", pcis);
|
|
|
|
for (auto vattr : pcis)
|
|
{
|
|
if ( vattr->vector_value("TYPE") == "NIC" )
|
|
{
|
|
anics.push_back(vattr);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the network leases & security groups for the NICs and PCIs */
|
|
/* ---------------------------------------------------------------------- */
|
|
vector<VectorAttribute*> sgs;
|
|
|
|
VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
|
|
|
|
if (nics.get_network_leases(oid, uid, anics, nic_default, sgs, estr) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Get the associated secutiry groups for NICs and PCI TYPE=NIC */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
obj_template->set(sgs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_up_attach_nic(VirtualMachineTemplate * tmpl, string& err)
|
|
{
|
|
// -------------------------------------------------------------------------
|
|
// Get the new NIC attribute from the template
|
|
// -------------------------------------------------------------------------
|
|
VectorAttribute * new_nic = tmpl->get("NIC");
|
|
|
|
if ( new_nic == 0 )
|
|
{
|
|
new_nic = tmpl->get("NIC_ALIAS");
|
|
|
|
if ( new_nic == 0 )
|
|
{
|
|
err = "Wrong format or missing NIC/NIC_ALIAS attribute";
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
new_nic = new_nic->clone();
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Setup nic for attachment
|
|
// -------------------------------------------------------------------------
|
|
vector<VectorAttribute *> sgs;
|
|
|
|
VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
|
|
|
|
int rc = nics.set_up_attach_nic(oid, uid, get_cid(), new_nic, nic_default,
|
|
sgs, err);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
delete new_nic;
|
|
return -1;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Add new nic to template and set info in history before attaching
|
|
// -------------------------------------------------------------------------
|
|
set_vm_info();
|
|
|
|
obj_template->set(new_nic);
|
|
|
|
for (auto vattr : sgs)
|
|
{
|
|
obj_template->set(vattr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::set_detach_nic(int nic_id)
|
|
{
|
|
std::set<int> a_ids;
|
|
|
|
int parent_id, alias_id;
|
|
|
|
VirtualMachineNic * nic = nics.get_nic(nic_id);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
nic->set_attach();
|
|
|
|
if ( nic->is_alias() )
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
if ( nic->vector_value("ALIAS_ID", alias_id) != 0 ||
|
|
nic->vector_value("PARENT_ID", parent_id) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
nic = nics.get_nic(parent_id);
|
|
|
|
if ( nic == 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
|
|
|
|
for (const auto& id : a_ids)
|
|
{
|
|
if ( id == nic_id )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( !oss.str().empty() )
|
|
{
|
|
oss << ",";
|
|
}
|
|
|
|
oss << id;
|
|
}
|
|
|
|
nic->replace("ALIAS_IDS", oss.str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::delete_attach_alias(VirtualMachineNic *nic)
|
|
{
|
|
std::set<int> a_ids;
|
|
|
|
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
|
|
|
|
for (auto id : a_ids)
|
|
{
|
|
VirtualMachineNic * nic_a = nics.delete_nic(id);
|
|
|
|
if (nic_a)
|
|
{
|
|
obj_template->remove(nic_a->vector_attribute());
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* VirtualMachine VMGroup interface */
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int VirtualMachine::get_vmgroup(string& error)
|
|
{
|
|
vector<Attribute *> vmgroups;
|
|
|
|
bool found = false;
|
|
VectorAttribute * thegroup = 0;
|
|
|
|
user_obj_template->remove("VMGROUP", vmgroups);
|
|
|
|
for (auto it = vmgroups.begin(); it != vmgroups.end(); )
|
|
{
|
|
if ( (*it)->type() != Attribute::VECTOR || found )
|
|
{
|
|
delete *it;
|
|
it = vmgroups.erase(it);
|
|
}
|
|
else
|
|
{
|
|
thegroup = dynamic_cast<VectorAttribute *>(*it);
|
|
found = true;
|
|
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if ( thegroup == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
|
|
int rc;
|
|
|
|
rc = vmgrouppool->vmgroup_attribute(thegroup, get_uid(), get_oid(), error);
|
|
|
|
if ( rc != 0 )
|
|
{
|
|
delete thegroup;
|
|
|
|
return -1;
|
|
}
|
|
|
|
obj_template->set(thegroup);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::release_vmgroup()
|
|
{
|
|
VectorAttribute * thegroup = obj_template->get("VMGROUP");
|
|
|
|
if ( thegroup == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
|
|
|
|
vmgrouppool->del_vm(thegroup, get_oid());
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::parse_sched_action(string& error_str)
|
|
{
|
|
vector<VectorAttribute*> vas;
|
|
|
|
if (user_obj_template->remove("SCHED_ACTION", vas) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int rc = SchedActions::parse(vas, error_str, true, true);
|
|
|
|
obj_template->set(vas);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::check_tm_mad_disks(const string& tm_mad, string& error)
|
|
{
|
|
string tm_mad_sys;
|
|
|
|
obj_template->get("TM_MAD_SYSTEM", tm_mad_sys);
|
|
|
|
if ( !tm_mad_sys.empty() ) // VM has TM_MAD_SYSTEM already defined
|
|
{
|
|
return 0;
|
|
}
|
|
if ( disks.check_tm_mad(tm_mad, error) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
obj_template->add("TM_MAD_SYSTEM", tm_mad);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::check_shareable_disks(const string& vmm_mad, string& error)
|
|
{
|
|
VirtualMachineManager * vmm = Nebula::instance().get_vmm();
|
|
const VirtualMachineManagerDriver * vmmd = vmm->get(vmm_mad);
|
|
|
|
if ( vmmd == nullptr )
|
|
{
|
|
error = "Cannot find vmm driver: " + vmm_mad;
|
|
|
|
return -1;
|
|
}
|
|
|
|
if ( vmmd->support_shareable() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (const auto disk : disks)
|
|
{
|
|
bool shareable;
|
|
disk->vector_value("SHAREABLE", shareable);
|
|
|
|
if (shareable)
|
|
{
|
|
error = "VM has shareable disk, but vmm driver: '"
|
|
+ vmm_mad + "' doesn't support shareable disks";
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::sched_action_add(const string& sched_template,
|
|
std::string& error)
|
|
{
|
|
// Read and verify SCHED_ACTION in incoming string
|
|
VirtualMachineTemplate new_tmpl(false, '=', "TEMPLATE");
|
|
|
|
if (new_tmpl.parse_str_or_xml(sched_template, error) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
vector<VectorAttribute*> sa;
|
|
|
|
if (new_tmpl.remove("SCHED_ACTION", sa) == 0 || sa.empty())
|
|
{
|
|
error = "Cannot read SCHED_ACTION from the template: " + sched_template;
|
|
return -1;
|
|
}
|
|
|
|
vector<const VectorAttribute*> vm_sa;
|
|
|
|
obj_template->get("SCHED_ACTION", vm_sa);
|
|
|
|
VectorAttribute * new_sa = SchedActions::new_action(vm_sa, sa[0], error);
|
|
|
|
if (!new_sa)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
obj_template->set(new_sa);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::sched_action_delete(int sched_id, std::string& error)
|
|
{
|
|
vector<VectorAttribute*> sched_actions;
|
|
|
|
obj_template->get("SCHED_ACTION", sched_actions);
|
|
|
|
VectorAttribute* sa = SchedActions::get_action(sched_actions, sched_id);
|
|
|
|
if (!sa)
|
|
{
|
|
error = "Sched action with id = " + to_string(sched_id) +
|
|
"doesn't exist";
|
|
return -1;
|
|
}
|
|
|
|
obj_template->remove(sa);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int VirtualMachine::sched_action_update(int sched_id,
|
|
const string& sched_template,
|
|
std::string& error)
|
|
{
|
|
// Get SchedAction with ID = sched_id
|
|
vector<VectorAttribute*> sched_actions;
|
|
|
|
obj_template->get("SCHED_ACTION", sched_actions);
|
|
|
|
VectorAttribute* sa = SchedActions::get_action(sched_actions, sched_id);
|
|
|
|
if (!sa)
|
|
{
|
|
error = "Sched action with id = " + to_string(sched_id) +
|
|
"doesn't exist";
|
|
return -1;
|
|
}
|
|
|
|
// Read and verify SCHED_ACTION in incoming string
|
|
VirtualMachineTemplate new_tmpl(false, '=', "TEMPLATE");
|
|
|
|
if (new_tmpl.parse_str_or_xml(sched_template, error) != 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
vector<VectorAttribute*> new_sa_v;
|
|
|
|
if (new_tmpl.remove("SCHED_ACTION", new_sa_v) == 0 || new_sa_v.empty())
|
|
{
|
|
error = "Cannot read SCHED_ACTION from the template: " + sched_template;
|
|
return -1;
|
|
}
|
|
|
|
SchedAction new_sa(new_sa_v[0], sched_id);
|
|
|
|
if ( new_sa.parse(error, false) == -1 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
new_sa_v[0]->replace("ID", sched_id);
|
|
|
|
sa->replace(new_sa_v[0]->value());
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void VirtualMachine::encrypt()
|
|
{
|
|
std::string one_key;
|
|
Nebula::instance().get_configuration_attribute("ONE_KEY", one_key);
|
|
|
|
obj_template->encrypt(one_key);
|
|
user_obj_template->encrypt(one_key);
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void VirtualMachine::decrypt()
|
|
{
|
|
std::string one_key;
|
|
Nebula::instance().get_configuration_attribute("ONE_KEY", one_key);
|
|
|
|
obj_template->decrypt(one_key);
|
|
user_obj_template->decrypt(one_key);
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl,
|
|
bool only_running)
|
|
{
|
|
std::string memory, cpu;
|
|
|
|
get_template_attribute("MEMORY", memory);
|
|
get_template_attribute("CPU", cpu);
|
|
|
|
if ((state == VirtualMachine::ACTIVE) ||
|
|
(state == VirtualMachine::PENDING) ||
|
|
(state == VirtualMachine::CLONING) ||
|
|
(state == VirtualMachine::CLONING_FAILURE) ||
|
|
(state == VirtualMachine::HOLD) )
|
|
{
|
|
quota_tmpl.add("RUNNING_MEMORY", memory);
|
|
quota_tmpl.add("RUNNING_CPU", cpu);
|
|
quota_tmpl.add("RUNNING_VMS", 1);
|
|
|
|
if (only_running)
|
|
{
|
|
quota_tmpl.add("MEMORY", 0);
|
|
quota_tmpl.add("CPU", 0);
|
|
quota_tmpl.add("VMS", 0);
|
|
}
|
|
else
|
|
{
|
|
quota_tmpl.add("MEMORY", memory);
|
|
quota_tmpl.add("CPU", cpu);
|
|
quota_tmpl.add("VMS", 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::release_previous_vnc_port()
|
|
{
|
|
ClusterPool * cpool = Nebula::instance().get_clpool();
|
|
|
|
VectorAttribute * graphics = get_template_attribute("GRAPHICS");
|
|
|
|
unsigned int previous_port;
|
|
|
|
if (graphics == nullptr ||
|
|
graphics->vector_value("PREVIOUS_PORT", previous_port) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cpool->release_vnc_port(previous_history->cid, previous_port);
|
|
|
|
graphics->remove("PREVIOUS_PORT");
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void VirtualMachine::rollback_previous_vnc_port()
|
|
{
|
|
ClusterPool * cpool = Nebula::instance().get_clpool();
|
|
|
|
VectorAttribute * graphics = get_template_attribute("GRAPHICS");
|
|
|
|
unsigned int previous_port;
|
|
unsigned int port;
|
|
|
|
if (graphics == nullptr ||
|
|
graphics->vector_value("PREVIOUS_PORT", previous_port) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( graphics->vector_value("PORT", port) == 0 )
|
|
{
|
|
cpool->release_vnc_port(history->cid, port);
|
|
}
|
|
|
|
graphics->replace("PORT", previous_port);
|
|
|
|
graphics->remove("PREVIOUS_PORT");
|
|
};
|
|
|