1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-26 09:57:23 +03:00

F #4393: Moved Saveas implementation to VirtualMachineDiks. Fix bugs

This commit is contained in:
Ruben S. Montero 2016-12-12 10:26:55 +01:00
parent 033f8853da
commit 178489ef11
11 changed files with 1879 additions and 1719 deletions

View File

@ -982,28 +982,6 @@ public:
// ------------------------------------------------------------------------
// Template
// ------------------------------------------------------------------------
/**
* Parse a string and substitute variables (e.g. $NAME) using the VM
* template values:
* @param attribute, the string to be parsed
* @param parsed, the resulting parsed string
* @param error description in case of failure
* @return 0 on success.
*/
int parse_template_attribute(const string& attribute,
string& parsed,
string& error);
/**
* Parse a file string variable (i.e. $FILE) using the FILE_DS datastores.
* It should be used for OS/DS_KERNEL, OS/DS_INITRD, CONTEXT/DS_FILES.
* @param attribute the string to be parsed
* @param img_ids ids of the FILE images in the attribute
* @param error description in case of failure
* @return 0 on success.
*/
int parse_file_attribute(string attribute,
vector<int>& img_ids,
string& error);
/**
* Updates the configuration attributes based on a template, the state of
* the virtual machine is checked to assure operation consistency
@ -1378,7 +1356,11 @@ public:
* @param err_str describing the error if any
* @return -1 if the image cannot saveas, 0 on success
*/
int set_saveas_disk(int disk_id, int snap_id, int &img_id, long long &size, string& err_str);
int set_saveas_disk(int disk_id, int snap_id, int &img_id, long long &size,
string& err_str)
{
return disks.set_saveas(disk_id, snap_id, img_id, size, err_str);
}
/**
* Set save attributes for the disk
@ -1386,7 +1368,16 @@ public:
* @param source to save the disk
* @param img_id ID of the image this disk will be saved to
*/
int set_saveas_disk(int disk_id, const string& source, int img_id);
int set_saveas_disk(int disk_id, const string& source, int img_id)
{
if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
&& lcm_state != HOTPLUG_SAVEAS_POWEROFF )
{
return -1;
}
return disks.set_saveas(disk_id, source, img_id);
}
/**
* Sets the corresponding state to save the disk.
@ -1405,7 +1396,10 @@ public:
* @return the ID of the image this disk will be saved to or -1 if it
* is not found.
*/
int clear_saveas_disk();
int clear_saveas_disk()
{
return disks.clear_saveas();
}
/**
* Get the original image id of the disk. It also checks that the disk can
@ -1418,7 +1412,11 @@ public:
* @return -1 if failure
*/
int get_saveas_disk(int& disk_id, string& source, int& image_id,
string& snap_id, string& tm_mad, string& ds_id);
string& snap_id, string& tm_mad, string& ds_id)
{
return disks.get_saveas_info(disk_id, source, image_id, snap_id,
tm_mad, ds_id);
}
// ------------------------------------------------------------------------
// Authorization related functions
@ -1473,7 +1471,10 @@ public:
*/
VirtualMachineDisk * delete_attach_disk()
{
return disks.delete_attach();
VirtualMachineDisk * disk = disks.delete_attach();
obj_template->remove(disk->vector_attribute());
return disk;
}
/**
@ -1514,6 +1515,19 @@ public:
*/
int set_resize_disk(int disk_id);
/**
* Prepares a disk to be resized.
* @param disk_id of disk
* @param size new size for the disk (needs to be greater than current)
* @param error
*
* @return 0 on success
*/
int set_up_resize_disk(int disk_id, long size, string& error)
{
return disks.set_up_resize(disk_id, size, error);
}
// ------------------------------------------------------------------------
// NIC Hotplug related functions
// ------------------------------------------------------------------------
@ -1860,11 +1874,9 @@ private:
*/
Log * _log;
// *************************************************************************
// DataBase implementation (Private)
// *************************************************************************
/**
* Bootstraps the database table(s) associated to the VirtualMachine
* @return 0 on success
@ -1943,15 +1955,64 @@ private:
*/
int update_monitoring(SqlDB * db);
/**
* Function that renders the VM in XML format optinally including
* extended information (all history records)
* @param xml the resulting XML string
* @param n_history Number of history records to include:
* 0: none
* 1: the last one
* 2: all
* @return a reference to the generated string
*/
string& to_xml_extended(string& xml, int n_history) const;
// -------------------------------------------------------------------------
// Attribute Parser
// -------------------------------------------------------------------------
/**
* Mutex to perform just one attribute parse at a time
*/
static pthread_mutex_t lex_mutex;
/**
* Attributes not allowed in NIC_DEFAULT to avoid authorization bypass and
* inconsistencies for NIC_DEFAULTS
*/
static const char* NO_NIC_DEFAULTS[];
static const int NUM_NO_NIC_DEFAULTS;
/**
* Known Virtual Router attributes, to be moved from the user template
* to the template
*/
static const char* VROUTER_ATTRIBUTES[];
static const int NUM_VROUTER_ATTRIBUTES;
/**
* Parse a string and substitute variables (e.g. $NAME) using the VM
* template values:
* @param attribute, the string to be parsed
* @param parsed, the resulting parsed string
* @param error description in case of failure
* @return 0 on success.
*/
int parse_template_attribute(const string& attribute,
string& parsed,
string& error);
/**
* Parse a file string variable (i.e. $FILE) using the FILE_DS datastores.
* It should be used for OS/DS_KERNEL, OS/DS_INITRD, CONTEXT/DS_FILES.
* @param attribute the string to be parsed
* @param img_ids ids of the FILE images in the attribute
* @param error description in case of failure
* @return 0 on success.
*/
int parse_file_attribute(string attribute,
vector<int>& img_ids,
string& error);
/**
* Generates image attributes (DS_ID, TM_MAD, SOURCE...) for KERNEL and
* INITRD files.
@ -1959,12 +2020,11 @@ private:
* @param base_name of the attribute "KERNEL", or "INITRD"
* @param base_type of the image attribute KERNEL, RAMDISK
* @param error_str Returns the error reason, if any
* @return 0 on success
* @return 0 on succes
*/
int set_os_file(VectorAttribute * os,
const string& base_name,
Image::ImageType base_type,
string& error_str);
int set_os_file(VectorAttribute* os, const string& base_name,
Image::ImageType base_type, string& error_str);
/**
* Parse the "OS" attribute of the template by substituting
* $FILE variables
@ -1973,49 +2033,6 @@ private:
*/
int parse_os(string& error_str);
/**
* Attributes not allowed in NIC_DEFAULT to avoid authorization bypass and
* inconsistencies for NIC_DEFAULTS
*/
static const char * NO_NIC_DEFAULTS[];
static const int NUM_NO_NIC_DEFAULTS;
/**
* Parse and generate the ETH_ network attributed of a NIC
* @param context attribute
* @param nic attribute
*
* @return 0 on success
*/
void parse_nic_context(VectorAttribute * context, VectorAttribute * nic);
/**
* Generate the NETWORK related CONTEXT setions, i.e. ETH_*. This function
* is invoked when ever the context is prepared for the VM to capture
* netowrking updates.
* @param context attribute of the VM
* @param error string if any
* @return 0 on success
*/
int generate_network_context(VectorAttribute * context, string& error);
/**
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
* is also adds basic network attributes for pass-through NICs
* @param context attribute of the VM
* @return true if the net context was generated.
*/
bool generate_pci_context(VectorAttribute * context);
/**
* Generate the ONE_GATE token & url
* @param context attribute of the VM
* @param error_str describing the error
* @return 0 if success
*/
int generate_token_context(VectorAttribute * context, string& error_str);
/**
* Parse the "NIC_DEFAULT" attribute
* @param error_str Returns the error reason, if any
@ -2031,12 +2048,35 @@ private:
int parse_vrouter(string& error_str);
/**
* Known Virtual Router attributes, to be moved from the user template
* to the template
* Parse the "PCI" attribute of the template and checks mandatory attributes
* @param error_str Returns the error reason, if any
* @return 0 on success
*/
static const char* VROUTER_ATTRIBUTES[];
static const int NUM_VROUTER_ATTRIBUTES;
int parse_pci(string& error_str);
/**
* Parse the "SCHED_REQUIREMENTS" attribute of the template by substituting
* $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE]
* @param error_str Returns the error reason, if any
* @return 0 on success
*/
int parse_requirements(string& error_str);
/**
* Parse the "GRAPHICS" attribute and generates a default PORT if not
* defined
*/
int parse_graphics(string& error_str);
/**
* Searches the meaningful attributes and moves them from the user template
* to the internal template
*/
void parse_well_known_attributes();
// -------------------------------------------------------------------------
// Context related functions
// -------------------------------------------------------------------------
/**
* Known attributes for network contextualization rendered as:
* ETH_<nicid>_<context[0]> = $NETWORK[context[1], vnet_name]
@ -2066,11 +2106,30 @@ private:
static const int NUM_NETWORK6_CONTEXT;
/**
* Parse the "PCI" attribute of the template and checks mandatory attributes
* @param error_str Returns the error reason, if any
* Generate the NETWORK related CONTEXT setions, i.e. ETH_*. This function
* is invoked when ever the context is prepared for the VM to capture
* netowrking updates.
* @param context attribute of the VM
* @param error string if any
* @return 0 on success
*/
int parse_pci(string& error_str);
int generate_network_context(VectorAttribute * context, string& error);
/**
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
* is also adds basic network attributes for pass-through NICs
* @param context attribute of the VM
* @return true if the net context was generated.
*/
bool generate_pci_context(VectorAttribute * context);
/**
* Generate the ONE_GATE token & url
* @param context attribute of the VM
* @param error_str describing the error
* @return 0 if success
*/
int generate_token_context(VectorAttribute * context, string& error_str);
/**
* Parse the "CONTEXT" attribute of the template by substituting
@ -2091,44 +2150,6 @@ private:
*/
int parse_context_variables(VectorAttribute ** context, string& error_str);
/**
* Parse the "SCHED_REQUIREMENTS" attribute of the template by substituting
* $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE]
* @param error_str Returns the error reason, if any
* @return 0 on success
*/
int parse_requirements(string& error_str);
/**
* Parse the "GRAPHICS" attribute and generates a default PORT if not
* defined
*/
int parse_graphics(string& error_str);
/**
* Searches the meaningful attributes and moves them from the user template
* to the internal template
*/
void parse_well_known_attributes();
/**
* Function that renders the VM in XML format optinally including
* extended information (all history records)
* @param xml the resulting XML string
* @param n_history Number of history records to include:
* 0: none
* 1: the last one
* 2: all
* @return a reference to the generated string
*/
string& to_xml_extended(string& xml, int n_history) const;
/**
* Merges NIC_DEFAULT with the given NIC
* @param nic NIC to process
*/
void merge_nic_defaults(VectorAttribute* nic);
// -------------------------------------------------------------------------
// NIC & DISK Management Helpers
// -------------------------------------------------------------------------
@ -2155,6 +2176,12 @@ private:
*/
VectorAttribute* get_attach_nic();
/**
* Merges NIC_DEFAULT with the given NIC
* @param nic NIC to process
*/
void merge_nic_defaults(VectorAttribute* nic);
// ------------------------------------------------------------------------
// Public cloud templates related functions
// ------------------------------------------------------------------------

View File

@ -169,17 +169,9 @@ class VirtualMachineAttributeSet
{
protected:
/**
* Creates the VirtualMachineAttribute set from the Template or vector with
* all the attributes.
* @param a_name the attribute name (e.g. "DISK")
* @param id_name to search for attributes (e.g. "DISK_ID")
* Creates the VirtualMachineAttribute set
* @param dispose elements upon set destruction
*/
VirtualMachineAttributeSet(const std::string a_name,
const std::string& id_name, Template * tmpl);
VirtualMachineAttributeSet(const std::string& id_name,
std::vector<VectorAttribute *>& vas, bool dispose);
VirtualMachineAttributeSet(bool _dispose):dispose(_dispose){};
virtual ~VirtualMachineAttributeSet();

View File

@ -84,7 +84,7 @@ public:
void clear_active_snapshot()
{
set_flag("DISK_SNAPSHOT_ACTIVE");
clear_flag("DISK_SNAPSHOT_ACTIVE");
};
bool is_active_snapshot()
@ -92,6 +92,16 @@ public:
return is_flag("DISK_SNAPSHOT_ACTIVE");
}
void set_saveas()
{
set_flag("HOTPLUG_SAVE_AS_ACTIVE");
};
void clear_saveas()
{
clear_flag("HOTPLUG_SAVE_AS_ACTIVE");
};
/* ---------------------------------------------------------------------- */
/* Disk attributes, not accesible through vector_value */
/* ---------------------------------------------------------------------- */
@ -243,7 +253,14 @@ public:
* @param tmpl template with DISK
*/
VirtualMachineDisks(Template * tmpl, bool has_id):
VirtualMachineAttributeSet(DISK_NAME, id_name(has_id), tmpl){};
VirtualMachineAttributeSet(false)
{
std::vector<VectorAttribute *> vas;
tmpl->get(DISK_NAME, vas);
init(vas, has_id);
};
/**
* Creates the VirtualMachineDisk set from a vector of DISK VectorAttribute
@ -251,7 +268,10 @@ public:
* @param va vector of DISK Vector Attributes
*/
VirtualMachineDisks(vector<VectorAttribute *>& va, bool has_id, bool dispose):
VirtualMachineAttributeSet(id_name(has_id), va, dispose){};
VirtualMachineAttributeSet(dispose)
{
init(va, has_id);
};
/**
* Creates an empty disk set
@ -401,6 +421,22 @@ public:
/* ---------------------------------------------------------------------- */
/* Attach disk Interface */
/* ---------------------------------------------------------------------- */
/**
* Clear attach status from the attach disk (ATTACH=YES)
*/
VirtualMachineDisk * delete_attach()
{
return static_cast<VirtualMachineDisk *>(remove_attribute("ATTACH"));
}
/**
* Get the attach disk (ATTACH=YES)
*/
VirtualMachineDisk * get_attach()
{
return static_cast<VirtualMachineDisk *>(get_attribute("ATTACH"));
}
/**
* Sets the attach attribute to the given disk
* @param disk_id of the DISK
@ -416,16 +452,6 @@ public:
clear_flag("ATTACH");
}
VirtualMachineDisk * delete_attach()
{
return static_cast<VirtualMachineDisk *>(remove_attribute("ATTACH"));
}
VirtualMachineDisk * get_attach()
{
return static_cast<VirtualMachineDisk *>(get_attribute("ATTACH"));
}
/**
* Prepares a disk to be attached to the virtual machine and adds it to the
* disk set. It checks target assigment and cluster compatibility.
@ -441,6 +467,59 @@ public:
VirtualMachineDisk * set_up_attach(int vmid, int uid, int cluster_id,
VectorAttribute * vdisk, VectorAttribute * vcontext, string& error);
/* ---------------------------------------------------------------------- */
/* Save as Interface */
/* ---------------------------------------------------------------------- */
/**
* Get the saveas disk (HOTPLUG_SAVE_AS_ACTIVE = YES)
*/
VirtualMachineDisk * get_saveas()
{
return static_cast<VirtualMachineDisk *>(
get_attribute("HOTPLUG_SAVE_AS_ACTIVE"));
}
/**
* Mark the disk that is going to be "save as"
* @param disk_id of the VM
* @param snap_id of the disk to save, -1 to select the active snapshot
* @param iid The image id used by the disk
* @param size The disk size. This may be different to the original
* image size
* @param err_str describing the error if any
* @return -1 if the image cannot saveas, 0 on success
*/
int set_saveas(int disk_id, int snap_id, int &iid, long long &size,
string& err_str);
/**
* Set save attributes for the disk
* @param disk_id Index of the disk to save
* @param source to save the disk
* @param img_id ID of the image this disk will be saved to
*/
int set_saveas(int disk_id, const string& source, int iid);
/**
* Clears the SAVE_AS_* attributes of the disk being saved as
* @return the ID of the image this disk will be saved to or -1 if it
* is not found.
*/
int clear_saveas();
/**
* Get the original image id of the disk. It also checks that the disk can
* be saved_as.
* @param disk_id Index of the disk to save
* @param source of the image to save the disk to
* @param image_id of the image to save the disk to
* @param tm_mad in use by the disk
* @param ds_id of the datastore in use by the disk
* @return -1 if failure
*/
int get_saveas_info(int& disk_id, string& source, int& image_id,
string& snap_id, string& tm_mad, string& ds_id);
/* ---------------------------------------------------------------------- */
/* Resize disk Interface */
/* ---------------------------------------------------------------------- */
@ -467,9 +546,25 @@ public:
return static_cast<VirtualMachineDisk *>(get_attribute("RESIZE"));
}
/**
* Prepares a disk to be resized.
* @param disk_id of disk
* @param size new size for the disk (needs to be greater than current)
* @param error
*
* @return 0 on success
*/
int set_up_resize(int disk_id, long size, string& error);
/* ---------------------------------------------------------------------- */
/* SNAPSHOT interface */
/* ---------------------------------------------------------------------- */
VirtualMachineDisk * get_active_snapshot()
{
return static_cast<VirtualMachineDisk *>(
get_attribute("DISK_SNAPSHOT_ACTIVE"));
}
/**
* Set the snapshots for a disk
* @param id of disk
@ -562,18 +657,6 @@ private:
void assign_disk_targets(
std::queue<pair <std::string, VirtualMachineDisk *> >& dqueue,
std::set<std::string>& used_targets);
static const char * id_name(bool has_id)
{
if (has_id)
{
return DISK_ID_NAME;
}
else
{
return "";
}
}
};
#endif /*VIRTUAL_MACHINE_DISK_H_*/

View File

@ -815,6 +815,7 @@ VM_RESTRICTED_ATTR = "DISK/READ_IOPS_SEC"
VM_RESTRICTED_ATTR = "DISK/WRITE_IOPS_SEC"
#VM_RESTRICTED_ATTR = "DISK/SIZE"
VM_RESTRICTED_ATTR = "DISK/ORIGINAL_SIZE"
VM_RESTRICTED_ATTR = "DISK/SIZE_PREV"
VM_RESTRICTED_ATTR = "CPU_COST"
VM_RESTRICTED_ATTR = "MEMORY_COST"
VM_RESTRICTED_ATTR = "DISK_COST"

View File

@ -31,7 +31,7 @@ require 'nokogiri'
module OneDBFsck
VERSION = "5.2.0"
LOCAL_VERSION = "4.90.0"
LOCAL_VERSION = "5.2.0"
def check_db_version()
db_version = read_db_version()

View File

@ -51,6 +51,8 @@ source_files=[
'VirtualMachineAttribute.cc',
'VirtualMachineDisk.cc',
'VirtualMachineSystemSnapshot.cc',
'VirtualMachineParser.cc',
'VirtualMachineContext.cc',
'Snapshots.cc'
]

File diff suppressed because it is too large Load Diff

View File

@ -16,26 +16,6 @@
#include "VirtualMachineAttribute.h"
VirtualMachineAttributeSet::VirtualMachineAttributeSet(const std::string anam,
const std::string& idnam, Template * tmpl):dispose(false)
{
std::vector<VectorAttribute *> vas;
tmpl->get(anam, vas);
init_attribute_map(idnam, vas);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
VirtualMachineAttributeSet::VirtualMachineAttributeSet(const std::string& idnam,
std::vector<VectorAttribute *>& vas, bool _dispose):dispose(_dispose)
{
init_attribute_map(idnam, vas);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -0,0 +1,579 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2016, 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 <limits.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <regex.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <queue>
#include "VirtualMachine.h"
#include "VirtualNetworkPool.h"
#include "ImagePool.h"
#include "NebulaLog.h"
#include "NebulaUtil.h"
#include "Snapshots.h"
#include "Nebula.h"
#include "vm_file_var_syntax.h"
#include "vm_var_syntax.h"
/* -------------------------------------------------------------------------- */
/* Context constants */
/* -------------------------------------------------------------------------- */
const char * VirtualMachine::NETWORK_CONTEXT[][2] = {
{"IP", "IP"},
{"MAC", "MAC"},
{"MASK", "NETWORK_MASK"},
{"NETWORK", "NETWORK_ADDRESS"},
{"GATEWAY", "GATEWAY"},
{"DNS", "DNS"},
{"SEARCH_DOMAIN", "SEARCH_DOMAIN"},
{"MTU", "GUEST_MTU"},
{"VLAN_ID", "VLAN_ID"},
{"VROUTER_IP", "VROUTER_IP"},
{"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT"}};
const int VirtualMachine::NUM_NETWORK_CONTEXT = 11;
const char* VirtualMachine::NETWORK6_CONTEXT[][2] = {
{"IP6", "IP6_GLOBAL"},
{"IP6_ULA", "IP6_ULA"},
{"GATEWAY6", "GATEWAY6"},
{"CONTEXT_FORCE_IPV4", "CONTEXT_FORCE_IPV4"},
{"VROUTER_IP6", "VROUTER_IP6_GLOBAL"}};
const int VirtualMachine::NUM_NETWORK6_CONTEXT = 5;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* CONTEXT - Public Interface */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::generate_context(string &files, int &disk_id,
const string& token_password)
{
ofstream file;
string files_ds, error_str;
vector<const VectorAttribute*> attrs;
map<string, string>::const_iterator it;
files = "";
bool token;
if ( history == 0 )
{
return -1;
}
VectorAttribute * context = obj_template->get("CONTEXT");
if ( context == 0 )
{
log("VM", Log::INFO, "Virtual Machine has no context");
return 0;
}
//Generate dynamic context attributes
if ( generate_network_context(context, error_str) != 0 )
{
ostringstream oss;
oss << "Cannot parse network context:: " << error_str;
log("VM", Log::ERROR, oss);
return -1;
}
file.open(history->context_file.c_str(),ios::out);
if (file.fail() == true)
{
ostringstream oss;
oss << "Could not open context file: " << history->context_file;
log("VM", Log::ERROR, oss);
return -1;
}
files = context->vector_value("FILES");
files_ds = context->vector_value("FILES_DS");
if (!files_ds.empty())
{
files += " ";
files += files_ds;
}
for (size_t i=0;i<files.length();i++)
{
if (files[i] == '\n')
{
files[i] = ' ';
}
}
context->vector_value("TOKEN", token);
if (token)
{
ofstream token_file;
ostringstream oss;
string* encrypted;
string tk_error;
if (token_password.empty())
{
tk_error = "Cannot generate OneGate token: TOKEN_PASSWORD not set in"
" the user template.";
file.close();
log("VM", Log::ERROR, tk_error.c_str());
set_template_error_message(tk_error);
return -1;
}
token_file.open(history->token_file.c_str(), ios::out);
if (token_file.fail())
{
tk_error = "Cannot create token file";
file.close();
log("VM", Log::ERROR, tk_error.c_str());
set_template_error_message(tk_error);
return -1;
}
oss << oid << ':' << stime;
encrypted = one_util::aes256cbc_encrypt(oss.str(), token_password);
token_file << *encrypted << endl;
token_file.close();
delete encrypted;
files += (" " + history->token_file);
}
const map<string, string> values = context->value();
file << "# Context variables generated by OpenNebula\n";
for (it=values.begin(); it != values.end(); it++ )
{
//Replace every ' in value by '\''
string escape_str(it->second);
size_t pos = 0;
while ((pos = escape_str.find('\'', pos)) != string::npos)
{
escape_str.replace(pos,1,"'\\''");
pos = pos + 4;
}
file << it->first <<"='" << escape_str << "'" << endl;
}
file.close();
context->vector_value("DISK_ID", disk_id);
return 1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::get_created_by_uid() const
{
int created_by_uid;
if (obj_template->get("CREATED_BY", created_by_uid))
{
return created_by_uid;
}
return get_uid();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* CONTEXT - Private Interface */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void parse_context_network(const char* vars[][2], int num_vars,
VectorAttribute * context, VectorAttribute * nic)
{
string nic_id = nic->vector_value("NIC_ID");
for (int i=0; i < num_vars; i++)
{
ostringstream cvar;
string cval;
cvar << "ETH" << nic_id << "_" << vars[i][0];
cval = nic->vector_value(vars[i][1]); //Check the NIC
if (cval.empty()) //Will check the AR and VNET
{
ostringstream cval_ss;
cval_ss << "$NETWORK["<< vars[i][1] <<", NIC_ID=\""<< nic_id <<"\"]";
cval = cval_ss.str();
}
context->replace(cvar.str(), cval);
}
}
int VirtualMachine::generate_network_context(VectorAttribute* context,
string& error_str)
{
bool net_context;
context->vector_value("NETWORK", net_context);
if (!net_context)
{
return 0;
}
vector<VectorAttribute *> vatts;
int rc;
string parsed;
string* str;
VectorAttribute tmp_context("TMP_CONTEXT");
int num_vatts = obj_template->get("NIC", vatts);
if ( num_vatts == 0 )
{
return 0;
}
for(int i=0; i<num_vatts; i++)
{
parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
&tmp_context, vatts[i]);
parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
&tmp_context, vatts[i]);
}
str = tmp_context.marshall();
if (str == 0)
{
error_str = "Internal error generating network context";
return -1;
}
rc = parse_template_attribute(*str, parsed, error_str);
delete str;
if (rc != 0)
{
return -1;
}
tmp_context.clear();
tmp_context.unmarshall(parsed);
context->merge(&tmp_context, true);
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void parse_pci_context_network(const char* vars[][2], int num_vars,
VectorAttribute * context, VectorAttribute * nic)
{
string pci_id = nic->vector_value("PCI_ID");
for (int i=0; i < num_vars; i++)
{
ostringstream cvar;
cvar << "PCI" << pci_id << "_" << vars[i][0];
string cval = nic->vector_value(vars[i][1]);
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
}
}
/**
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
* is also adds basic network attributes for pass-through NICs
* @param context attribute of the VM
* @return true if the net context was generated.
*/
bool VirtualMachine::generate_pci_context(VectorAttribute * context)
{
bool net_context;
vector<VectorAttribute *> vatts;
context->vector_value("NETWORK", net_context);
int num_vatts = obj_template->get("PCI", vatts);
for(int i=0; i<num_vatts; i++)
{
if ( net_context && vatts[i]->vector_value("TYPE") == "NIC" )
{
parse_pci_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
context, vatts[i]);
parse_pci_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
context, vatts[i]);
}
ostringstream cvar;
cvar << "PCI" << vatts[i]->vector_value("PCI_ID") << "_ADDRESS";
string cval = vatts[i]->vector_value("VM_ADDRESS");
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
}
return net_context;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::generate_token_context(VectorAttribute * context, string& e)
{
bool token;
string ep;
context->vector_value("TOKEN", token);
if ( token == false )
{
return 0;
}
Nebula::instance().get_configuration_attribute("ONEGATE_ENDPOINT", ep);
if ( ep.empty() )
{
e = "TOKEN set, but onegate endpoint was not defined in oned.conf.";
return -1;
}
context->replace("ONEGATE_ENDPOINT", ep);
context->replace("VMID", oid);
// Store the original owner to compute token_password in case of a chown
replace_template_attribute("CREATED_BY", uid);
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_context(string& error_str)
{
VectorAttribute * context = obj_template->get("CONTEXT");
if ( context == 0 )
{
return 0;
}
string files_ds = context->vector_value("FILES_DS");
context->remove("FILES_DS");
// -------------------------------------------------------------------------
// Add network context and parse variables
// -------------------------------------------------------------------------
if (parse_context_variables(&context, error_str) == -1 ||
generate_network_context(context, error_str) == -1 )
{
return -1;
}
generate_pci_context(context);
// -------------------------------------------------------------------------
// Parse FILE_DS variables
// -------------------------------------------------------------------------
if (!files_ds.empty())
{
string files_ds_parsed;
string st;
ostringstream oss_parsed;
vector<int> img_ids;
if ( parse_file_attribute(files_ds, img_ids, error_str) != 0 )
{
return -1;
}
if ( img_ids.size() > 0 )
{
vector<int>::iterator it;
Nebula& nd = Nebula::instance();
ImagePool * ipool = nd.get_ipool();
Image * img = 0;
Image::ImageType type;
Image::ImageState state;
for ( it=img_ids.begin() ; it < img_ids.end(); it++ )
{
img = ipool->get(*it, true);
if ( img != 0 )
{
oss_parsed << img->get_source() << ":'"
<< img->get_name() << "' ";
type = img->get_type();
state = img->get_state();
img->unlock();
if (type != Image::CONTEXT)
{
error_str = "Only images of type CONTEXT can be used in"
" FILE_DS attribute.";
return -1;
}
if ( state != Image::READY )
{
ostringstream oss;
oss << Image::type_to_str(type)
<< " Image '" << *it << "' not in READY state.";
error_str = oss.str();
return -1;
}
}
}
}
files_ds_parsed = oss_parsed.str();
if ( !files_ds_parsed.empty() )
{
context->replace("FILES_DS", files_ds_parsed);
}
}
// -------------------------------------------------------------------------
// OneGate URL
// -------------------------------------------------------------------------
if ( generate_token_context(context, error_str) != 0 )
{
return -1;
}
// -------------------------------------------------------------------------
// Virtual Router attributes
// -------------------------------------------------------------------------
string st;
for (int i = 0; i < NUM_VROUTER_ATTRIBUTES; i++)
{
obj_template->get(VROUTER_ATTRIBUTES[i], st);
if (!st.empty())
{
context->replace(VROUTER_ATTRIBUTES[i], st);
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_context_variables(VectorAttribute ** context,
string& error_str)
{
int rc;
string parsed;
string * str = (*context)->marshall();
if (str == 0)
{
return -1;
}
rc = parse_template_attribute(*str, parsed, error_str);
delete str;
if (rc != 0)
{
return -1;
}
*context = new VectorAttribute("CONTEXT");
(*context)->unmarshall(parsed);
obj_template->erase("CONTEXT");
obj_template->set(*context);
return 0;
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

View File

@ -368,7 +368,7 @@ long long VirtualMachineDisks::system_ds_size()
long long VirtualMachineDisks::system_ds_size(Template * ds_tmpl)
{
VirtualMachineDisks disks(ds_tmpl);
VirtualMachineDisks disks(ds_tmpl, false);
return disks.system_ds_size();
}
@ -386,7 +386,7 @@ void VirtualMachineDisks::extended_info(int uid)
void VirtualMachineDisks::extended_info(int uid, Template * tmpl)
{
VirtualMachineDisks disks(tmpl);
VirtualMachineDisks disks(tmpl, false);
return disks.extended_info(uid);
}
@ -415,8 +415,6 @@ bool VirtualMachineDisks::volatile_info(int ds_id)
return found;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -477,140 +475,6 @@ void VirtualMachineDisks::assign_disk_targets(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid,
int cluster_id, VectorAttribute * vdisk, VectorAttribute * vcontext,
string& error)
{
set<string> used_targets;
int max_disk_id = -1;
// -------------------------------------------------------------------------
// Get the list of used targets and max_disk_id
// -------------------------------------------------------------------------
for ( disk_iterator disk = begin() ; disk != end() ; ++disk )
{
string target = (*disk)->vector_value("TARGET");
if ( !target.empty() )
{
used_targets.insert(target);
}
int disk_id = (*disk)->get_disk_id();
if ( disk_id > max_disk_id )
{
max_disk_id = disk_id;
}
}
if ( vcontext != 0 )
{
string target = vcontext->vector_value("TARGET");
if ( !target.empty() )
{
used_targets.insert(target);
}
int disk_id;
vcontext->vector_value("DISK_ID", disk_id);
if ( disk_id > max_disk_id )
{
max_disk_id = disk_id;
}
}
// -------------------------------------------------------------------------
// Acquire the new disk image
// -------------------------------------------------------------------------
Nebula& nd = Nebula::instance();
ImagePool * ipool = nd.get_ipool();
ImageManager* imagem = nd.get_imagem();
Snapshots * snap = 0;
string dev_prefix;
Image::ImageType img_type;
int image_id;
VirtualMachineDisk * disk = new VirtualMachineDisk(vdisk, max_disk_id + 1);
int rc = ipool->acquire_disk(vmid, disk, max_disk_id + 1, img_type,
dev_prefix, uid, image_id, &snap, error);
if ( rc != 0 )
{
return 0;
}
disk->set_snapshots(snap);
string target = disk->vector_value("TARGET");
if ( !target.empty() )
{
if ( used_targets.insert(target).second == false )
{
error = "Target " + target + " is already in use.";
imagem->release_image(vmid, image_id, false);
delete disk;
return 0;
}
}
else
{
queue<pair <string, VirtualMachineDisk *> > disks_queue;
disks_queue.push(make_pair(dev_prefix, disk));
assign_disk_targets(disks_queue, used_targets);
}
// -------------------------------------------------------------------------
// Check that we don't have a cluster incompatibility.
// -------------------------------------------------------------------------
string disk_cluster_ids = disk->vector_value("CLUSTER_ID");
if ( !disk_cluster_ids.empty() )
{
set<int> cluster_ids;
one_util::split_unique(disk_cluster_ids, ',', cluster_ids);
if (cluster_ids.count(cluster_id) == 0)
{
ostringstream oss;
oss << "Image [" << image_id << "] is not part of cluster ["
<< cluster_id << "]";
error = oss.str();
imagem->release_image(vmid, image_id, false);
delete disk;
return 0;
}
}
// -------------------------------------------------------------------------
// Add disk to the set
// -------------------------------------------------------------------------
disk->set_attach();
add_attribute(disk, disk->get_disk_id());
return disk;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::get_images(int vm_id, int uid,
vector<Attribute *> disks, VectorAttribute * vcontext,
std::string& error_str)
@ -875,6 +739,140 @@ int VirtualMachineDisks::set_attach(int id)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid,
int cluster_id, VectorAttribute * vdisk, VectorAttribute * vcontext,
string& error)
{
set<string> used_targets;
int max_disk_id = -1;
// -------------------------------------------------------------------------
// Get the list of used targets and max_disk_id
// -------------------------------------------------------------------------
for ( disk_iterator disk = begin() ; disk != end() ; ++disk )
{
string target = (*disk)->vector_value("TARGET");
if ( !target.empty() )
{
used_targets.insert(target);
}
int disk_id = (*disk)->get_disk_id();
if ( disk_id > max_disk_id )
{
max_disk_id = disk_id;
}
}
if ( vcontext != 0 )
{
string target = vcontext->vector_value("TARGET");
if ( !target.empty() )
{
used_targets.insert(target);
}
int disk_id;
vcontext->vector_value("DISK_ID", disk_id);
if ( disk_id > max_disk_id )
{
max_disk_id = disk_id;
}
}
// -------------------------------------------------------------------------
// Acquire the new disk image
// -------------------------------------------------------------------------
Nebula& nd = Nebula::instance();
ImagePool * ipool = nd.get_ipool();
ImageManager* imagem = nd.get_imagem();
Snapshots * snap = 0;
string dev_prefix;
Image::ImageType img_type;
int image_id;
VirtualMachineDisk * disk = new VirtualMachineDisk(vdisk, max_disk_id + 1);
int rc = ipool->acquire_disk(vmid, disk, max_disk_id + 1, img_type,
dev_prefix, uid, image_id, &snap, error);
if ( rc != 0 )
{
return 0;
}
disk->set_snapshots(snap);
string target = disk->vector_value("TARGET");
if ( !target.empty() )
{
if ( used_targets.insert(target).second == false )
{
error = "Target " + target + " is already in use.";
imagem->release_image(vmid, image_id, false);
delete disk;
return 0;
}
}
else
{
queue<pair <string, VirtualMachineDisk *> > disks_queue;
disks_queue.push(make_pair(dev_prefix, disk));
assign_disk_targets(disks_queue, used_targets);
}
// -------------------------------------------------------------------------
// Check that we don't have a cluster incompatibility.
// -------------------------------------------------------------------------
string disk_cluster_ids = disk->vector_value("CLUSTER_ID");
if ( !disk_cluster_ids.empty() )
{
set<int> cluster_ids;
one_util::split_unique(disk_cluster_ids, ',', cluster_ids);
if (cluster_ids.count(cluster_id) == 0)
{
ostringstream oss;
oss << "Image [" << image_id << "] is not part of cluster ["
<< cluster_id << "]";
error = oss.str();
imagem->release_image(vmid, image_id, false);
delete disk;
return 0;
}
}
// -------------------------------------------------------------------------
// Add disk to the set
// -------------------------------------------------------------------------
disk->set_attach();
add_attribute(disk, disk->get_disk_id());
return disk;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* RESIZE DISK INTERFACE */
@ -895,6 +893,8 @@ int VirtualMachineDisks::set_resize(int id)
return 0;
}
/* -------------------------------------------------------------------------- */
void VirtualMachineDisks::clear_resize(bool restore)
{
string size, size_prev;
@ -914,6 +914,40 @@ void VirtualMachineDisks::clear_resize(bool restore)
disk->clear_resize();
}
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::set_up_resize(int disk_id, long size, string& err)
{
VirtualMachineDisk * disk = get_disk(disk_id);
long size_prev;
if ( disk == 0 )
{
err = "Disk not found";
return -1;
}
if ( disk->vector_value("SIZE", size_prev) != 0 )
{
err = "Wrong format for disk SIZE";
return -1;
}
if ( size <= size_prev )
{
err = "New size has to be bigger than current one";
return -1;
}
disk->replace("SIZE_PREV", size_prev);
disk->replace("SIZE", size);
disk->set_resize();
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* SNAPSHOT INTERFACE */
@ -951,15 +985,12 @@ int VirtualMachineDisks::set_active_snapshot(int id, int snap_id)
void VirtualMachineDisks::clear_active_snapshot()
{
for ( disk_iterator disk = begin() ; disk != end() ; ++disk )
{
if ( (*disk)->is_active_snapshot() )
{
(*disk)->clear_active_snapshot();
(*disk)->remove("DISK_SNAPSHOT_ID");
VirtualMachineDisk * disk = get_active_snapshot();
break;
}
if ( disk != 0 )
{
disk->clear_active_snapshot();
disk->remove("DISK_SNAPSHOT_ID");
}
}
@ -1081,7 +1112,7 @@ void VirtualMachineDisks::delete_snapshot(int disk_id, int snap_id,
void VirtualMachineDisks::delete_non_persistent_snapshots(Template **vm_quotas,
map<int, Template *>& ds_quotas)
{
long long system_disk;
long long system_disk = 0;
for ( disk_iterator disk = begin() ; disk != end() ; ++disk )
{
@ -1131,3 +1162,115 @@ void VirtualMachineDisks::delete_non_persistent_snapshots(Template **vm_quotas,
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::set_saveas(int disk_id, int snap_id, int &iid,
long long &size, string& err_str)
{
iid = -1;
VirtualMachineDisk * disk =
static_cast<VirtualMachineDisk *>(get_attribute(disk_id));
if (disk == 0)
{
err_str = "DISK does not exist.";
return -1;
}
if (disk->vector_value("IMAGE_ID", iid) != 0)
{
iid = -1;
err_str = "DISK does not have a valid IMAGE_ID.";
return -1;
}
const Snapshots * snaps = disk->get_snapshots();
if (snap_id != -1)
{
if (snaps == 0 || !snaps->exists(snap_id))
{
err_str = "Snapshot does not exist.";
return -1;
}
}
disk->set_saveas();
disk->replace("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id);
size = 0;
disk->vector_value("SIZE", size);
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::set_saveas(int disk_id, const string& source, int iid)
{
VirtualMachineDisk * disk = get_saveas();
if ( disk == 0 )
{
return -1;
}
disk->replace("HOTPLUG_SAVE_AS", iid);
disk->replace("HOTPLUG_SAVE_AS_SOURCE", source);
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::clear_saveas()
{
VirtualMachineDisk * disk = get_saveas();
if ( disk == 0 )
{
return -1;
}
int image_id;
disk->clear_saveas();
disk->vector_value("HOTPLUG_SAVE_AS", image_id);
disk->remove("HOTPLUG_SAVE_AS");
disk->remove("HOTPLUG_SAVE_AS_SOURCE");
disk->remove("HOTPLUG_SAVE_AS_SNAPSHOT_ID");
return image_id;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachineDisks::get_saveas_info(int& disk_id, string& source,
int& image_id, string& snap_id, string& tm_mad, string& ds_id)
{
int rc;
VirtualMachineDisk * disk = get_saveas();
if ( disk == 0 )
{
return -1;
}
rc = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE", source);
rc += disk->vector_value("HOTPLUG_SAVE_AS", image_id);
rc += disk->vector_value("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id);
rc += disk->vector_value("DISK_ID", disk_id);
rc += disk->vector_value("DATASTORE_ID", ds_id);
rc += disk->vector_value("TM_MAD", tm_mad);
return rc;
}

View File

@ -0,0 +1,683 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2016, 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 <limits.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <regex.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <queue>
#include "VirtualMachine.h"
#include "VirtualNetworkPool.h"
#include "ImagePool.h"
#include "NebulaLog.h"
#include "NebulaUtil.h"
#include "Snapshots.h"
#include "Nebula.h"
#include "vm_file_var_syntax.h"
#include "vm_var_syntax.h"
/* -------------------------------------------------------------------------- */
/* Parser constanta */
/* -------------------------------------------------------------------------- */
const char * VirtualMachine::NO_NIC_DEFAULTS[] = {"NETWORK_ID", "NETWORK",
"NETWORK_UID", "NETWORK_UNAME"};
const int VirtualMachine::NUM_NO_NIC_DEFAULTS = 4;
const char* VirtualMachine::VROUTER_ATTRIBUTES[] = {
"VROUTER_ID",
"VROUTER_KEEPALIVED_ID",
"VROUTER_KEEPALIVED_PASSWORD"};
const int VirtualMachine::NUM_VROUTER_ATTRIBUTES = 3;
pthread_mutex_t VirtualMachine::lex_mutex = PTHREAD_MUTEX_INITIALIZER;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* Generates image attributes (DS_ID, TM_MAD, SOURCE...) for KERNEL and
* INITRD files.
* @param os attribute of the VM template
* @param base_name of the attribute "KERNEL", or "INITRD"
* @param base_type of the image attribute KERNEL, RAMDISK
* @param error_str Returns the error reason, if any
* @return 0 on succes
*/
int VirtualMachine::set_os_file(VectorAttribute* os, const string& base_name,
Image::ImageType base_type, string& error_str)
{
vector<int> img_ids;
Nebula& nd = Nebula::instance();
ImagePool * ipool = nd.get_ipool();
Image * img = 0;
int img_id;
Image::ImageType type;
Image::ImageState state;
DatastorePool * ds_pool = nd.get_dspool();
Datastore * ds;
int ds_id;
string attr;
string base_name_ds = base_name + "_DS";
string base_name_id = base_name + "_DS_ID";
string base_name_source = base_name + "_DS_SOURCE";
string base_name_ds_id = base_name + "_DS_DSID";
string base_name_tm = base_name + "_DS_TM";
string base_name_cluster= base_name + "_DS_CLUSTER_ID";
string type_str;
attr = os->vector_value(base_name_ds.c_str());
if ( attr.empty() )
{
return 0;
}
if ( parse_file_attribute(attr, img_ids, error_str) != 0 )
{
return -1;
}
if ( img_ids.size() != 1 )
{
error_str = "Only one FILE variable can be used in: " + attr;
return -1;
}
img_id = img_ids.back();
img = ipool->get(img_id, true);
if ( img == 0 )
{
error_str = "Image no longer exists in attribute: " + attr;
return -1;
}
state = img->get_state();
ds_id = img->get_ds_id();
type = img->get_type();
os->remove(base_name);
os->replace(base_name_id, img->get_oid());
os->replace(base_name_source, img->get_source());
os->replace(base_name_ds_id, img->get_ds_id());
img->unlock();
type_str = Image::type_to_str(type);
if ( type != base_type )
{
ostringstream oss;
oss << base_name << " needs an image of type "
<< Image::type_to_str(base_type) << " and not "
<< type_str;
error_str = oss.str();
return -1;
}
if ( state != Image::READY )
{
ostringstream oss;
oss << type_str << " Image '" << img_id << " 'not in READY state.";
error_str = oss.str();
return -1;
}
ds = ds_pool->get(ds_id, true);
if ( ds == 0 )
{
error_str = "Associated datastore for image does not exist";
return -1;
}
os->replace(base_name_tm, ds->get_tm_mad());
set<int> cluster_ids = ds->get_cluster_ids();
if (!cluster_ids.empty())
{
os->replace(base_name_cluster, one_util::join(cluster_ids, ','));
}
ds->unlock();
return 0;
}
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_os(string& error_str)
{
int num;
int rc;
vector<Attribute *> os_attr;
VectorAttribute * os;
vector<Attribute *>::iterator it;
num = user_obj_template->remove("OS", os_attr);
for (it=os_attr.begin(); it != os_attr.end(); it++)
{
obj_template->set(*it);
}
if ( num == 0 )
{
return 0;
}
else if ( num > 1 )
{
error_str = "Only one OS attribute can be defined.";
return -1;
}
os = dynamic_cast<VectorAttribute *>(os_attr[0]);
if ( os == 0 )
{
error_str = "Internal error parsing OS attribute.";
return -1;
}
rc = set_os_file(os, "KERNEL", Image::KERNEL, error_str);
if ( rc != 0 )
{
return -1;
}
rc = set_os_file(os, "INITRD", Image::RAMDISK, error_str);
if ( rc != 0 )
{
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_defaults(string& error_str)
{
int num;
vector<Attribute *> attr;
VectorAttribute* vatt = 0;
num = user_obj_template->remove("NIC_DEFAULT", attr);
if ( num == 0 )
{
return 0;
}
if ( num > 1 )
{
error_str = "Only one NIC_DEFAULT attribute can be defined.";
goto error_cleanup;
}
vatt = dynamic_cast<VectorAttribute *>(attr[0]);
if ( vatt == 0 )
{
error_str = "Wrong format for NIC_DEFAULT attribute.";
goto error_cleanup;
}
for (int i=0; i < NUM_NO_NIC_DEFAULTS; i++)
{
if(vatt->vector_value(NO_NIC_DEFAULTS[i]) != "")
{
ostringstream oss;
oss << "Attribute " << NO_NIC_DEFAULTS[i]
<< " is not allowed inside NIC_DEFAULT.";
error_str = oss.str();
return -1;
}
}
obj_template->set(vatt);
return 0;
error_cleanup:
for (int i = 0; i < num ; i++)
{
delete attr[i];
}
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_vrouter(string& error_str)
{
string st;
for (int i = 0; i < NUM_VROUTER_ATTRIBUTES; i++)
{
user_obj_template->get(VROUTER_ATTRIBUTES[i], st);
if (!st.empty())
{
obj_template->replace(VROUTER_ATTRIBUTES[i], st);
}
user_obj_template->erase(VROUTER_ATTRIBUTES[i]);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int check_pci_attributes(VectorAttribute * pci, const string& default_bus,
string& error_str)
{
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
static int num_attrs = 3;
string bus;
bool found = false;
for (int i = 0; i < num_attrs; i++)
{
unsigned int val;
int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
if (rc == -1)
{
error_str = "Wrong Hex value for PCI attribute " + attrs[i];
return -1;
}
else if ( rc != 0 )
{
found = true;
}
}
if (!found)
{
error_str = "DEVICE, VENDOR or CLASS must be defined for PCI.";
return -1;
}
if ( HostSharePCI::set_pci_address(pci, default_bus) != 0 )
{
error_str = "Wrong BUS in PCI attribute";
return -1;
}
return 0;
}
int VirtualMachine::parse_pci(string& error_str)
{
vector<VectorAttribute *> array_pci;
vector<VectorAttribute *>::iterator it;
int pci_id = 0;
user_obj_template->remove("PCI", array_pci);
for (it = array_pci.begin(); it !=array_pci.end(); ++it, ++pci_id)
{
(*it)->replace("PCI_ID", pci_id);
obj_template->set(*it);
}
Nebula& nd = Nebula::instance();
string default_bus;
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", default_bus);
for (it = array_pci.begin(); it !=array_pci.end(); ++it)
{
if ( check_pci_attributes(*it, default_bus, error_str) != 0 )
{
return -1;
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_graphics(string& error_str)
{
VectorAttribute * user_graphics = user_obj_template->get("GRAPHICS");
if ( user_graphics == 0 )
{
return 0;
}
VectorAttribute * graphics = new VectorAttribute(user_graphics);
user_obj_template->erase("GRAPHICS");
obj_template->set(graphics);
if ( !graphics->vector_value("PORT").empty() )
{
unsigned int port;
int rc = graphics->vector_value("PORT", port);
if (rc == -1 || port > 65535 )
{
error_str = "Wrong PORT number in GRAPHICS attribute";
return -1;
}
}
string random_passwd = graphics->vector_value("RANDOM_PASSWD");
if ( !random_passwd.empty() )
{
graphics->replace("PASSWD", one_util::random_password());
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_requirements(string& error_str)
{
int rc, num;
vector<Attribute *> array_reqs;
SingleAttribute * reqs;
string parsed;
num = user_obj_template->remove("SCHED_REQUIREMENTS", array_reqs);
if ( num == 0 ) // Compatibility with old REQUIREMENTS attribute
{
num = user_obj_template->remove("REQUIREMENTS", array_reqs);
}
else
{
user_obj_template->erase("REQUIREMENTS");
}
if ( num == 0 )
{
return 0;
}
else if ( num > 1 )
{
error_str = "Only one SCHED_REQUIREMENTS attribute can be defined.";
goto error_cleanup;
}
reqs = dynamic_cast<SingleAttribute *>(array_reqs[0]);
if ( reqs == 0 )
{
error_str = "Wrong format for SCHED_REQUIREMENTS attribute.";
goto error_cleanup;
}
rc = parse_template_attribute(reqs->value(), parsed, error_str);
if ( rc == 0 )
{
SingleAttribute * reqs_parsed;
reqs_parsed = new SingleAttribute("SCHED_REQUIREMENTS",parsed);
user_obj_template->set(reqs_parsed);
}
/* --- Delete old requirements attribute --- */
delete array_reqs[0];
return rc;
error_cleanup:
for (int i = 0; i < num ; i++)
{
delete array_reqs[i];
}
return -1;
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void VirtualMachine::parse_well_known_attributes()
{
/*
* List of meaningful attributes, used in other places and expected in
* obj_template:
*
* DISK
* NIC
* VCPU
* MEMORY
* CPU
* CONTEXT
* OS
* GRAPHICS
*
* INPUT
* FEATURES
* RAW
* CLONING_TEMPLATE_ID
*/
vector<Attribute *> v_attr;
vector<Attribute *>::iterator it;
string names[] = {"INPUT", "FEATURES", "RAW", "CLONING_TEMPLATE_ID"};
for (int i=0; i<4; i++)
{
v_attr.clear();
user_obj_template->remove(names[i], v_attr);
for (it=v_attr.begin(); it != v_attr.end(); it++)
{
obj_template->set(*it);
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* VirtualMachine Lex & YACC parser functions */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
extern "C"
{
typedef struct yy_buffer_state * YY_BUFFER_STATE;
int vm_var_parse (VirtualMachine * vm,
ostringstream * parsed,
char ** errmsg);
int vm_file_var_parse (VirtualMachine * vm,
vector<int> * img_ids,
char ** errmsg);
int vm_var_lex_destroy();
YY_BUFFER_STATE vm_var__scan_string(const char * str);
void vm_var__delete_buffer(YY_BUFFER_STATE);
}
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_template_attribute(const string& attribute,
string& parsed,
string& error_str)
{
YY_BUFFER_STATE str_buffer = 0;
const char * str;
int rc;
ostringstream oss_parsed;
char * error_msg = 0;
pthread_mutex_lock(&lex_mutex);
str = attribute.c_str();
str_buffer = vm_var__scan_string(str);
if (str_buffer == 0)
{
goto error_yy;
}
rc = vm_var_parse(this, &oss_parsed, &error_msg);
vm_var__delete_buffer(str_buffer);
vm_var_lex_destroy();
pthread_mutex_unlock(&lex_mutex);
if ( rc != 0 && error_msg != 0 )
{
ostringstream oss;
oss << "Error parsing: " << attribute << ". " << error_msg;
log("VM", Log::ERROR, oss);
error_str = oss.str();
free(error_msg);
}
parsed = oss_parsed.str();
return rc;
error_yy:
log("VM",Log::ERROR,"Error setting scan buffer");
pthread_mutex_unlock(&lex_mutex);
return -1;
}
/* -------------------------------------------------------------------------- */
int VirtualMachine::parse_file_attribute(string attribute,
vector<int>& img_ids,
string& error)
{
YY_BUFFER_STATE str_buffer = 0;
const char * str;
int rc;
ostringstream oss_parsed;
char * error_msg = 0;
size_t non_blank_pos;
//Removes leading blanks from attribute, these are not managed
//by the parser as it is common to the other VM varibales
non_blank_pos = attribute.find_first_not_of(" \t\n\v\f\r");
if ( non_blank_pos != string::npos )
{
attribute.erase(0, non_blank_pos);
}
pthread_mutex_lock(&lex_mutex);
str = attribute.c_str();
str_buffer = vm_var__scan_string(str);
if (str_buffer == 0)
{
goto error_yy;
}
rc = vm_file_var_parse(this, &img_ids, &error_msg);
vm_var__delete_buffer(str_buffer);
vm_var_lex_destroy();
pthread_mutex_unlock(&lex_mutex);
if ( rc != 0 )
{
ostringstream oss;
if ( error_msg != 0 )
{
oss << "Error parsing: " << attribute << ". " << error_msg;
free(error_msg);
}
else
{
oss << "Unknown error parsing: " << attribute << ".";
}
error = oss.str();
}
return rc;
error_yy:
log("VM",Log::ERROR,"Error setting scan buffer");
pthread_mutex_unlock(&lex_mutex);
return -1;
}