1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

F #2671: Add oned search functionality. Add an index column to perform FTS searches server-side. New parameter has been added to the one.vmpool.info call, and --search option to CLI onevm list. This commits adds support for JAVA and migrator.

Co-authored-by: Christian González <cgonzalez@opennebula.systems>
This commit is contained in:
Ruben S. Montero 2019-01-30 00:10:18 +01:00
parent f3995775cc
commit 5f7fb402aa
26 changed files with 689 additions and 104 deletions

View File

@ -83,7 +83,11 @@ public:
* by the calling function.
* @return a string (allocated in the heap) holding the attribute value.
*/
virtual string * to_xml() const = 0;
virtual void to_xml(std::ostringstream& s) const = 0;
virtual void to_json(std::ostringstream& s) const = 0;
virtual void to_token(std::ostringstream& s) const = 0;
/**
* Builds a new attribute from a string.
@ -158,17 +162,31 @@ public:
*
* <attribute_name>attribute_value</attribute_name>
*
* The string MUST be freed by the calling function.
* @return a string (allocated in the heap) holding the attribute value.
* @paran s the stream to write the attribute.
*/
string * to_xml() const
void to_xml(std::ostringstream& s) const
{
string * xml = new string;
s << "<" << attribute_name << ">" << one_util::escape_xml(attribute_value)
<< "</"<< attribute_name << ">";
*xml = "<" + name() + ">" + one_util::escape_xml(attribute_value) +
"</"+ name() + ">";
}
return xml;
void to_json(std::ostringstream& s) const
{
one_util::escape_json(attribute_value, s);
}
void to_token(std::ostringstream& s) const
{
if (attribute_name.empty() || attribute_value.empty())
{
return;
}
one_util::escape_token(attribute_name, s);
s << "=";
one_util::escape_token(attribute_value, s);
s << std::endl;
}
/**
@ -350,12 +368,11 @@ public:
* The string MUST be freed by the calling function.
* @return a string (allocated in the heap) holding the attribute value.
*/
string * to_xml() const;
void to_xml(std::ostringstream& s) const;
/**
* Same as above but the attribute is written in an string stream;
*/
void to_xml(ostringstream &oss) const;
void to_json(std::ostringstream& s) const;
void to_token(std::ostringstream& s) const;
/**
* Builds a new attribute from a string of the form:

View File

@ -92,9 +92,19 @@ protected:
return va->marshall(_sep);
};
string * to_xml() const
void to_xml(std::ostringstream& s) const
{
return va->to_xml();
return va->to_xml(s);
};
void to_json(std::ostringstream& s) const
{
return va->to_json(s);
};
void to_token(std::ostringstream& s) const
{
return va->to_token(s);
};
void unmarshall(const std::string& sattr, const char * _sep = 0)

View File

@ -258,6 +258,10 @@ private:
*/
string& to_xml(string& xml, bool database) const;
string& to_json(string& json) const;
string& to_token(string& text) const;
/**
* Rebuilds the object from an xml node
* @param node The xml node pointer

View File

@ -371,7 +371,7 @@ public:
*/
static string shared_db_version()
{
return "5.7.80";
return "5.6.0";
}
/**
@ -578,6 +578,15 @@ public:
return nebula_configuration->to_xml(xml);
};
/**
* Gets the database backend type
* @return database backend type
*/
string get_db_backend() const
{
return db_backend_type;
}
// -----------------------------------------------------------------------
// Default Quotas
// -----------------------------------------------------------------------
@ -695,7 +704,7 @@ private:
"/DEFAULT_GROUP_QUOTAS/NETWORK_QUOTA",
"/DEFAULT_GROUP_QUOTAS/IMAGE_QUOTA",
"/DEFAULT_GROUP_QUOTAS/VM_QUOTA"),
system_db(0), logdb(0), fed_logdb(0),
system_db(0), db_backend_type("sqlite"), logdb(0), fed_logdb(0),
vmpool(0), hpool(0), vnpool(0), upool(0), ipool(0), gpool(0), tpool(0),
dspool(0), clpool(0), docpool(0), zonepool(0), secgrouppool(0),
vdcpool(0), vrouterpool(0), marketpool(0), apppool(0), vmgrouppool(0),
@ -819,6 +828,7 @@ private:
// ---------------------------------------------------------------
SystemDB * system_db;
string db_backend_type;
// ---------------------------------------------------------------
// Nebula Pools

View File

@ -208,6 +208,11 @@ namespace one_util
{
return escape(v, "'", "'");
}
void escape_json(const std::string& str, std::ostringstream& s);
void escape_token(const std::string& str, std::ostringstream& s);
/**
* Checks if a strings matches a regular expression
*
@ -236,7 +241,8 @@ namespace one_util
const std::string& replacement);
template <class T>
std::set<T> set_intersection(const std::set<T> &first, const std::set<T> &second)
std::set<T> set_intersection(const std::set<T> &first, const std::set<T>
&second)
{
std::set<T> output;
@ -247,48 +253,48 @@ namespace one_util
return output;
}
/**
/**
* Compress the input string unsing zlib
* @param in input string
* @param bool64 true to base64 encode output
* @return pointer to the compressed sting (must be freed) or 0 in case
* of error
*/
std::string * zlib_compress(const std::string& in, bool base64);
std::string * zlib_compress(const std::string& in, bool base64);
/**
/**
* Decompress the input string unsing zlib
* @param in input string
* @param base64 true if the input is base64 encoded
* @return pointer to the decompressed sting (must be freed) or 0 in case
* of error
*/
std::string * zlib_decompress(const std::string& in, bool base64);
std::string * zlib_decompress(const std::string& in, bool base64);
extern "C" void sslmutex_lock_callback(int mode, int type, char *file,
int line);
extern "C" void sslmutex_lock_callback(int mode, int type, char *file,
int line);
extern "C" unsigned long sslmutex_id_callback();
extern "C" unsigned long sslmutex_id_callback();
class SSLMutex
{
public:
static void initialize();
class SSLMutex
{
public:
static void initialize();
static void finalize();
static void finalize();
private:
friend void sslmutex_lock_callback(int mode, int type, char *file,
int line);
private:
friend void sslmutex_lock_callback(int mode, int type, char *file,
int line);
SSLMutex();
SSLMutex();
~SSLMutex();
~SSLMutex();
static SSLMutex * ssl_mutex;
static SSLMutex * ssl_mutex;
static std::vector<pthread_mutex_t *> vmutex;
};
static std::vector<pthread_mutex_t *> vmutex;
};
};
#endif /* _NEBULA_UTIL_H_ */

View File

@ -251,6 +251,28 @@ public:
static void oid_filter(int start_id,
int end_id,
string& filter);
/**
* This function returns a legal SQL string that can be used in an SQL
* statement. The string is encoded to an escaped SQL string, taking into
* account the current character set of the connection.
* @param str the string to be escaped
* @return a valid SQL string or NULL in case of failure
*/
char * escape_str(const string& str)
{
return db->escape_str(str);
}
/**
* Frees a previously scaped string
* @param str pointer to the str
*/
void free_str(char * str)
{
db->free_str(str);
}
protected:
/**

View File

@ -113,7 +113,7 @@ public:
VirtualMachinePoolInfo():
RequestManagerPoolInfoFilter("one.vmpool.info",
"Returns the virtual machine instances pool",
"A:siiii")
"A:siiiis")
{
Nebula& nd = Nebula::instance();
pool = nd.get_vmpool();

View File

@ -170,6 +170,10 @@ public:
*/
string& to_xml(string& xml) const;
string& to_json(string& xml) const;
string& to_token(string& xml) const;
/**
* Writes the template in a plain text string
* @param str string that hold the template representation

View File

@ -1884,6 +1884,10 @@ private:
*/
string& to_xml_extended(string& xml, int n_history) const;
string& to_json(string& json) const;
string& to_token(string& text) const;
// -------------------------------------------------------------------------
// Attribute Parser
// -------------------------------------------------------------------------

View File

@ -1458,8 +1458,7 @@ ONEDB_SHARED_MIGRATOR_FILES="src/onedb/shared/2.0_to_2.9.80.rb \
src/onedb/shared/5.3.80_to_5.4.0.rb \
src/onedb/shared/5.4.0_to_5.4.1.rb \
src/onedb/shared/5.4.1_to_5.5.80.rb \
src/onedb/shared/5.5.80_to_5.6.0.rb \
src/onedb/shared/5.6.0_to_5.7.80.rb"
src/onedb/shared/5.5.80_to_5.6.0.rb"
ONEDB_LOCAL_MIGRATOR_FILES="src/onedb/local/4.5.80_to_4.7.80.rb \
src/onedb/local/4.7.80_to_4.9.80.rb \

View File

@ -198,6 +198,13 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
:format => String
}
SEARCH = {
:name => "search",
:large => "--search search",
:description=> "query in KEY=VALUE format",
:format => String
}
def self.rname
"VM"
end

View File

@ -1047,8 +1047,28 @@ CommandParser::CmdParser.new(ARGV) do
command :list, list_desc, [:filterflag, nil],
:options => CLIHelper::OPTIONS + OpenNebulaHelper::OPTIONS +
[OpenNebulaHelper::DESCRIBE] do
helper.list_pool(options, false, args[0])
[OpenNebulaHelper::DESCRIBE] + [OneVMHelper::SEARCH] do
if !options[:search]
helper.list_pool(options, false, args[0])
else
table = helper.format_pool(options)
pool = OpenNebula::VirtualMachinePool.new(OneVMHelper.get_client)
rc = pool.info_search(:query => options[:search])
if rc != nil
puts rc.message
exit -1
end
if options[:xml]
puts pool.to_xml
else
table.show(pool.to_hash, options)
end
return 0
end
end
show_desc = <<-EOT.unindent

View File

@ -30,7 +30,6 @@ $LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
require 'command_parser'
require 'one_helper/onevntemplate_helper'
require 'one_helper/onevnet_helper'
require 'pry'
CommandParser::CmdParser.new(ARGV) do
usage '`onevntemplate` <command> [<args>] [<options>]'

View File

@ -65,25 +65,9 @@ string * VectorAttribute::marshall(const char * _sep) const
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string * VectorAttribute::to_xml() const
{
ostringstream oss;
to_xml(oss);
string * xml = new string;
*xml = oss.str();
return xml;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VectorAttribute::to_xml(ostringstream &oss) const
{
map<string,string>::const_iterator it;
map<string,string>::const_iterator it;
oss << "<" << name() << ">";
@ -102,6 +86,60 @@ void VectorAttribute::to_xml(ostringstream &oss) const
oss << "</"<< name() << ">";
}
void VectorAttribute::to_json(std::ostringstream& s) const
{
if ( attribute_value.empty() )
{
s << "{}";
return;
}
map<string,string>::const_iterator it = attribute_value.begin();
bool is_first = true;
s << "{";
for (++it; it!=attribute_value.end(); it++)
{
if ( it->first.empty() )
{
continue;
}
if ( !is_first )
{
s << ",";
}
else
{
is_first = false;
}
s << "\"" << it->first << "\": ";
one_util::escape_json(it->second, s);
}
s << "}";
}
void VectorAttribute::to_token(std::ostringstream& s) const
{
map<string,string>::const_iterator it;
for (it=attribute_value.begin(); it!=attribute_value.end(); it++)
{
if (it->first.empty() || it->second.empty())
{
continue;
}
one_util::escape_token(it->first, s);
s << "=";
one_util::escape_token(it->second, s);
s << std::endl;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -380,6 +380,57 @@ std::string one_util::gsub(const std::string& st, const std::string& sfind,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void one_util::escape_json(const std::string& str, std::ostringstream& s)
{
std::string::const_iterator it;
s << "\"";
for (it = str.begin(); it != str.end(); ++it)
{
switch (*it)
{
case '\\': s << "\\\\"; break;
case '"' : s << "\\\""; break;
case '/' : s << "\\/"; break;
case '\b': s << "\\b"; break;
case '\f': s << "\\f"; break;
case '\n': s << "\\n"; break;
case '\r': s << "\\r"; break;
case '\t': s << "\\t"; break;
default : s << *it;
}
}
s << "\"";
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void one_util::escape_token(const std::string& str, std::ostringstream& s)
{
std::string::const_iterator it;
for (it = str.begin(); it != str.end(); ++it)
{
switch (*it)
{
case '-':
case '_':
case '.':
case ':':
s << '_';
break;
default :
s << *it;
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
namespace one_util
{
template<>

View File

@ -252,8 +252,6 @@ void Nebula::start(bool bootstrap_only)
// -----------------------------------------------------------
try
{
bool db_is_sqlite = true;
string server;
int port;
string user;
@ -265,12 +263,7 @@ void Nebula::start(bool bootstrap_only)
if ( _db != 0 )
{
string value = _db->vector_value("BACKEND");
if (value == "mysql")
{
db_is_sqlite = false;
}
db_backend_type = _db->vector_value("BACKEND");
if (_db->vector_value("SERVER", server) == -1)
{
@ -303,7 +296,7 @@ void Nebula::start(bool bootstrap_only)
}
}
if ( db_is_sqlite )
if ( db_backend_type == "sqlite" )
{
db_backend = new SqliteDB(var_location + "one.db");
}

View File

@ -177,6 +177,36 @@ public class VirtualMachinePool extends Pool implements Iterable<VirtualMachine>
return client.call(INFO_METHOD, filter, startId, endId, state);
}
/**
* Retrieves all or part of the Virtual Machines in the pool. The
* Virtual Machines to retrieve can be also filtered by Id, specifying the
* first and last Id to include; and by state.
*
* @param client XML-RPC Client.
* @param filter Filter flag to use. Possible values:
* <ul>
* <li>{@link Pool#ALL}: All Virtual Machines</li>
* <li>{@link Pool#MINE}: Connected user's Virtual Machines</li>
* <li>{@link Pool#MINE_GROUP}: Connected user's Virtual Machines, and the ones in
* his group</li>
* <li>{@link Pool#GROUP}: User's primary group Virtual Machines</li>
* <li>&gt;= 0 UID User's Virtual Machines</li>
* </ul>
* @param startId Lowest Id to retrieve
* @param endId Biggest Id to retrieve
* @param state Numeric state of the Virtual Machines wanted, or one
* of {@link VirtualMachinePool#ALL_VM} or
* {@link VirtualMachinePool#NOT_DONE}
* @param query query for FTS
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse info_search(Client client, int filter,
int startId, int endId, int state, String query)
{
return client.call(INFO_METHOD, filter, startId, endId, state, query);
}
/**
* Retrieves the monitoring data for all or part of the Virtual
* Machines in the pool.

View File

@ -115,6 +115,23 @@ module OpenNebula
INFO_NOT_DONE)
end
def info_search(args = {})
default_args = {
:who => INFO_ALL,
:start_id => -1,
:end_id => -1,
:state => INFO_NOT_DONE,
:query => ""
}.merge!(args)
return info_filter(VM_POOL_METHODS[:info],
default_args[:who],
default_args[:start_id],
default_args[:end_id],
default_args[:state],
default_args[:query])
end
alias_method :info!, :info
alias_method :info_all!, :info_all
alias_method :info_mine!, :info_mine
@ -458,8 +475,8 @@ module OpenNebula
data_hash
end
def info_filter(xml_method, who, start_id, end_id, state)
return xmlrpc_info(xml_method, who, start_id, end_id, state)
def info_filter(xml_method, who, start_id, end_id, state, query="")
return xmlrpc_info(xml_method, who, start_id, end_id, state, query)
end
end
end

View File

@ -91,8 +91,15 @@ class OneDBBacKEnd
vm_pool: "oid INTEGER PRIMARY KEY, name VARCHAR(128), " <<
"body MEDIUMTEXT, uid INTEGER, gid INTEGER, " <<
"last_poll INTEGER, state INTEGER, lcm_state INTEGER, " <<
"owner_u INTEGER, group_u INTEGER, other_u INTEGER, short_body MEDIUMTEXT",
"owner_u INTEGER, group_u INTEGER, other_u INTEGER, short_body MEDIUMTEXT, " <<
"search_token MEDIUMTEXT, FULLTEXT ftidx(search_token)",
vm_pool_sqlite: "oid INTEGER PRIMARY KEY, name VARCHAR(128), " <<
"body MEDIUMTEXT, uid INTEGER, gid INTEGER, " <<
"last_poll INTEGER, state INTEGER, lcm_state INTEGER, " <<
"owner_u INTEGER, group_u INTEGER, other_u INTEGER, short_body MEDIUMTEXT, " <<
"search_token MEDIUMTEXT",
vn_template_pool: "oid INTEGER PRIMARY KEY, name VARCHAR(128), " <<
"body MEDIUMTEXT, uid INTEGER, gid INTEGER," <<
"owner_u INTEGER, group_u INTEGER, other_u INTEGER"

View File

@ -52,7 +52,7 @@ require 'fsck/template'
require 'fsck/quotas'
module OneDBFsck
VERSION = "5.7.80"
VERSION = "5.6.0"
LOCAL_VERSION = "5.7.80"
def db_version

View File

@ -38,7 +38,7 @@ module Migrator
def up
bug_2687 # MUST be run before 2489, which generates short body
feature_2253
feature_2489
feature_2489_2671
feature_826
true
end
@ -104,10 +104,15 @@ module Migrator
@db.run 'DROP TABLE old_vm_pool;'
end
def feature_2489
def feature_2489_2671
@db.run 'DROP TABLE IF EXISTS old_vm_pool;'
@db.run 'ALTER TABLE vm_pool RENAME TO old_vm_pool;'
create_table(:vm_pool, nil, db_version)
if @backend.class == BackEndSQLite
create_table(:vm_pool_sqlite, nil, db_version)
elsif
create_table(:vm_pool, nil, db_version)
end
@db.transaction do
@db.fetch('SELECT * FROM old_vm_pool') do |row|
@ -116,6 +121,7 @@ module Migrator
end
row[:short_body] = gen_short_body(doc)
row[:search_token] = gen_search_body(doc)
@db[:vm_pool].insert(row)
end
@ -135,6 +141,67 @@ module Migrator
end
end
def gen_search_body(body)
search_body = "UNAME=" + escape_token(body.root.xpath('UNAME').text) + "\n" +
"GNAME=" + escape_token(body.root.xpath('GNAME').text) + "\n" +
"NAME=" + escape_token(body.root.xpath('NAME').text) + "\n" +
"LAST_POLL=" + escape_token(body.root.xpath('LAST_POLL').text) + "\n" +
"PREV_STATE=" + escape_token(body.root.xpath('PREV_STATE').text) + "\n" +
"PREV_LCM_STATE=" + escape_token(body.root.xpath('PREV_LCM_STATE').text) + "\n" +
"RESCHED=" + escape_token(body.root.xpath('RESCHED').text) + "\n" +
"STIME=" + escape_token(body.root.xpath('STIME').text) + "\n" +
"ETIME=" + escape_token(body.root.xpath('ETIME').text) + "\n" +
"DEPLOY_ID=" + escape_token(body.root.xpath('DEPLOY_ID').text) + "\n"
body.root.xpath("//TEMPLATE/*").each do |node|
search_body += to_token(node)
end
node = Nokogiri::XML(body.root.xpath("//HISTORY_RECORDS/HISTORY[last()]").to_s)
if !node.root.nil?
search_body += history_to_token(node)
end
return search_body
end
def to_token(node)
search_body = ""
if node.children.size > 1
node.children.each do |child|
search_body += to_token(child)
end
elsif
search_body += node.name + "=" + escape_token(node.children.text) + "\n"
end
return search_body
end
def history_to_token(hr)
hr_token = "HOSTNAME=" + escape_token(hr.xpath("//HOSTNAME").text) + "\n" +
"HID=" + hr.xpath("//HID").text + "\n" +
"CID=" + hr.xpath("//CID").text + "\n" +
"DS_ID=" + hr.xpath("//DS_ID").text + "\n"
end
def escape_token(str)
str_scaped = ""
str.split("").each do |c|
case c
when '-', '_', '.', ':'
str_scaped += '_'
else
str_scaped += c
end
end
return str_scaped
end
def gen_short_body(body)
short_body = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.VM{

View File

@ -96,12 +96,30 @@ void VirtualMachinePoolInfo::request_execute(
int end_id = xmlrpc_c::value_int(paramList.getInt(3));
int state = xmlrpc_c::value_int(paramList.getInt(4));
ostringstream state_filter;
std::string fts_query;
if (paramList.size() > 5)
{
fts_query = xmlrpc_c::value_string(paramList.getString(5));
std::string backend = Nebula::instance().get_db_backend();
if (!fts_query.empty() && backend == "sqlite")
{
att.resp_msg = "Full text search is not allowed with sqlite backend";
failure_response(INTERNAL, att);
return;
}
}
ostringstream and_filter;
if (( state < VirtualMachinePoolInfo::ALL_VM ) ||
( state > VirtualMachine::CLONING_FAILURE ))
{
att.resp_msg = "Incorrect filter_flag, state";
failure_response(XML_RPC_API, att);
return;
}
@ -112,15 +130,39 @@ void VirtualMachinePoolInfo::request_execute(
break;
case VirtualMachinePoolInfo::NOT_DONE:
state_filter << "state <> " << VirtualMachine::DONE;
and_filter << "state <> " << VirtualMachine::DONE;
break;
default:
state_filter << "state = " << state;
and_filter << "state = " << state;
break;
}
dump(att, filter_flag, start_id, end_id, state_filter.str(), "");
if (!fts_query.empty())
{
char * _fts_query = pool->escape_str(fts_query);
if ( _fts_query == 0 )
{
att.resp_msg = "Error building search query";
failure_response(INTERNAL, att);
return;
}
if (!and_filter.str().empty())
{
and_filter << " AND ";
}
and_filter << "MATCH(search_token) AGAINST ('+\"";
one_util::escape_token(_fts_query, and_filter);
and_filter << "\"' in boolean mode)";
pool->free_str(_fts_query);
}
dump(att, filter_flag, start_id, end_id, and_filter.str(), "");
}
/* ------------------------------------------------------------------------- */
@ -471,7 +513,7 @@ void RequestManagerPoolInfoFilter::dump(
limit_clause = oss.str();
}
Nebula::instance().get_configuration_attribute(att.uid, att.gid,
Nebula::instance().get_configuration_attribute(att.uid, att.gid,
"API_LIST_ORDER", desc);
rc = pool->dump(str, where_string, limit_clause,

View File

@ -386,19 +386,14 @@ bool Template::get(const string& name, bool& value) const
string& Template::to_xml(string& xml) const
{
multimap<string,Attribute *>::const_iterator it;
ostringstream oss;
string * s;
multimap<string,Attribute *>::const_iterator it;
ostringstream oss;
oss << "<" << xml_root << ">";
for ( it = attributes.begin(); it!=attributes.end(); it++)
{
s = it->second->to_xml();
oss << *s;
delete s;
it->second->to_xml(oss);
}
oss << "</" << xml_root << ">";
@ -407,6 +402,81 @@ string& Template::to_xml(string& xml) const
return xml;
}
string& Template::to_json(string& json) const
{
multimap<string, Attribute *>::const_iterator it;
ostringstream oss;
bool is_first = true;
oss << "\"" << xml_root << "\": {";
for ( it = attributes.begin(); it!=attributes.end(); )
{
if (!is_first)
{
oss << ",";
}
else
{
is_first = false;
}
oss << "\"" << it->first << "\": ";
if ( attributes.count(it->first) == 1 )
{
it->second->to_json(oss);
++it;
}
else
{
std::string jelem = it->first;
bool is_array_first = true;
oss << "[ ";
for ( ; it->first == jelem && it != attributes.end() ; ++it )
{
if ( !is_array_first )
{
oss << ",";
}
else
{
is_array_first = false;
}
it->second->to_json(oss);
}
oss << "]";
}
}
oss << "}";
json = oss.str();
return json;
}
string& Template::to_token(string& str) const
{
ostringstream os;
multimap<string,Attribute *>::const_iterator it;
for ( it = attributes.begin(); it!=attributes.end(); it++)
{
it->second->to_token(os);
}
str = os.str();
return str;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -341,6 +341,62 @@ string& History::to_xml(string& xml, bool database) const
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& History::to_json(string& json) const
{
ostringstream oss;
oss << "\"HISTORY\": {" <<
"\"OID\": \"" << oid << "\"," <<
"\"SEQ\": \"" << seq << "\"," <<
"\"HOSTNAME\": \"" << hostname << "\"," <<
"\"HID\": \"" << hid << "\"," <<
"\"CID\": \"" << cid << "\"," <<
"\"STIME\": \"" << stime << "\"," <<
"\"ETIME\": \"" << etime << "\"," <<
"\"VM_MAD\": \"" << vmm_mad_name << "\"," <<
"\"TM_MAD\": \"" << tm_mad_name << "\"," <<
"\"DS_ID\": \"" << ds_id << "\"," <<
"\"PSTIME\": \"" << prolog_stime << "\"," <<
"\"PETIME\": \"" << prolog_etime << "\"," <<
"\"RSTIME\": \"" << running_stime << "\"," <<
"\"RETIME\": \"" << running_etime << "\"," <<
"\"ESTIME\": \"" << epilog_stime << "\"," <<
"\"EETIME\": \"" << epilog_etime << "\"," <<
"\"ACTION\": \"" << action << "\"," <<
"\"UID\": \"" << uid << "\"," <<
"\"GID\": \"" << gid << "\"," <<
"\"REQUEST_ID\": \"" << req_id << "\",";
oss << "}";
json = oss.str();
return json;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& History::to_token(string& text) const
{
ostringstream oss;
oss << "HOSTNAME=";
one_util::escape_token(hostname, oss);
oss << "\n";
oss << "HID=" << hid << "\n" <<
"CID=" << cid << "\n" <<
"DS_ID=" << ds_id << "\n";
text = oss.str();
return text;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& History::to_xml_short(string& xml) const
{
ostringstream oss;

View File

@ -457,13 +457,13 @@ const char * VirtualMachine::table = "vm_pool";
const char * VirtualMachine::db_names =
"oid, name, body, uid, gid, last_poll, state, lcm_state, "
"owner_u, group_u, other_u, short_body";
"owner_u, group_u, other_u, short_body, search_token";
const char * VirtualMachine::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
"vm_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
"gid INTEGER, last_poll INTEGER, state INTEGER, lcm_state INTEGER, "
"owner_u INTEGER, group_u INTEGER, other_u INTEGER, short_body MEDIUMTEXT)";
"vm_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, "
"uid INTEGER, gid INTEGER, last_poll INTEGER, state INTEGER, "
"lcm_state INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, "
"short_body MEDIUMTEXT, search_token MEDIUMTEXT";
const char * VirtualMachine::monit_table = "vm_monitoring";
@ -489,7 +489,21 @@ int VirtualMachine::bootstrap(SqlDB * db)
{
int rc;
ostringstream oss_vm(VirtualMachine::db_bootstrap);
string backend = Nebula::instance().get_db_backend();
ostringstream oss_vm;
oss_vm << VirtualMachine::db_bootstrap;
if (backend == "mysql")
{
oss_vm << ", FULLTEXT ftidx(search_token))";
}
else
{
oss_vm << ")";
}
ostringstream oss_monit(VirtualMachine::monit_db_bootstrap);
ostringstream oss_hist(History::db_bootstrap);
ostringstream oss_showback(VirtualMachine::showback_db_bootstrap);
@ -1662,10 +1676,12 @@ int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
ostringstream oss;
int rc;
string xml_body, short_xml_body;
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.c_str());
@ -1698,6 +1714,13 @@ int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
goto error_xml_short;
}
sql_text = db->escape_str(to_token(text).c_str());
if ( sql_text == 0 )
{
goto error_text;
}
if(replace)
{
oss << "REPLACE";
@ -1719,17 +1742,21 @@ int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
<< owner_u << ","
<< group_u << ","
<< other_u << ","
<< "'" << sql_short_xml << "'"
<< "'" << 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:
@ -2145,7 +2172,7 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
string snap_xml;
string lock_str;
ostringstream oss;
ostringstream oss;
oss << "<VM>"
<< "<ID>" << oid << "</ID>"
@ -2215,6 +2242,91 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
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\": \""<< last_poll << "\","
<< "\"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";
oss << "NAME=";
one_util::escape_token(name, oss);
oss << "\n";
oss << "LAST_POLL="<< last_poll << "\n"
<< "PREV_STATE="<< prev_state << "\n"
<< "PREV_LCM_STATE="<< prev_lcm_state << "\n"
<< "RESCHED="<< resched << "\n"
<< "STIME="<< stime << "\n"
<< "ETIME="<< etime << "\n"
<< "DEPLOY_ID="<< deploy_id << "\n"
<< obj_template->to_token(template_text) << "\n"
<< user_obj_template->to_token(user_template_text);
if ( hasHistory() )
{
oss << "\n" << history->to_token(history_text);
}
text = oss.str();
return text;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& VirtualMachine::to_xml_short(string& xml)
{
string disks_xml, monitoring_xml, user_template_xml, history_xml, nics_xml;

View File

@ -26,13 +26,13 @@
int AddressRangeIPAM::from_vattr(VectorAttribute * attr, std::string& error_msg)
{
std::ostringstream oss;
IPAMManager * ipamm = Nebula::instance().get_ipamm();
std::string * ar_xml = attr->to_xml();
attr->to_xml(oss);
IPAMRequest ir(*ar_xml);
free(ar_xml);
IPAMRequest ir(oss.str());
ipamm->trigger(IPMAction::REGISTER_ADDRESS_RANGE, &ir);