diff --git a/include/Attribute.h b/include/Attribute.h index 2b88e00cfa..7a12c7c24b 100644 --- a/include/Attribute.h +++ b/include/Attribute.h @@ -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_value * - * 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) + << ""; - *xml = "<" + name() + ">" + one_util::escape_xml(attribute_value) + - ""; + } - 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: diff --git a/include/ExtendedAttribute.h b/include/ExtendedAttribute.h index 31d96caf6f..447e54bdf9 100644 --- a/include/ExtendedAttribute.h +++ b/include/ExtendedAttribute.h @@ -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) diff --git a/include/History.h b/include/History.h index 7c6f03fac3..3e45417d50 100644 --- a/include/History.h +++ b/include/History.h @@ -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 diff --git a/include/Nebula.h b/include/Nebula.h index 508f9cd31a..5635b9ebfd 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -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 diff --git a/include/NebulaUtil.h b/include/NebulaUtil.h index b02fcd48b3..e350812b50 100644 --- a/include/NebulaUtil.h +++ b/include/NebulaUtil.h @@ -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 - std::set set_intersection(const std::set &first, const std::set &second) + std::set set_intersection(const std::set &first, const std::set + &second) { std::set 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 vmutex; - }; + static std::vector vmutex; + }; }; #endif /* _NEBULA_UTIL_H_ */ diff --git a/include/PoolSQL.h b/include/PoolSQL.h index a641b2adef..172b5e7a33 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -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: /** diff --git a/include/RequestManagerPoolInfoFilter.h b/include/RequestManagerPoolInfoFilter.h index 247643cd6b..1e30a9eb90 100644 --- a/include/RequestManagerPoolInfoFilter.h +++ b/include/RequestManagerPoolInfoFilter.h @@ -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(); diff --git a/include/Template.h b/include/Template.h index dac30fd7e7..aa086d671b 100644 --- a/include/Template.h +++ b/include/Template.h @@ -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 diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 42f21dfebe..75859aeae2 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -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 // ------------------------------------------------------------------------- diff --git a/install.sh b/install.sh index a058ae33c5..db90ad3df0 100755 --- a/install.sh +++ b/install.sh @@ -1000,6 +1000,7 @@ IM_PROBES_LXD_PROBES_FILES="src/im_mad/remotes/lxd-probes.d/lxd.rb \ src/im_mad/remotes/lxd-probes.d/pci.rb \ src/im_mad/remotes/lxd-probes.d/monitor_ds.sh \ src/im_mad/remotes/lxd-probes.d/version.sh \ + src/im_mad/remotes/lxd-probes.d/profiles.sh \ src/im_mad/remotes/lxd-probes.d/collectd-client-shepherd.sh" IM_PROBES_LXD_FILES="src/im_mad/remotes/lxd.d/collectd-client_control.sh \ @@ -1458,8 +1459,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 \ diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index 625fc25cc9..e66fcf7c37 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -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 diff --git a/src/cli/onevm b/src/cli/onevm index a49cb8cc9c..fba0696d7f 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -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 diff --git a/src/cli/onevntemplate b/src/cli/onevntemplate index 2d2a6faf79..647320d78e 100755 --- a/src/cli/onevntemplate +++ b/src/cli/onevntemplate @@ -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` [] []' diff --git a/src/common/Attribute.cc b/src/common/Attribute.cc index 6b6790a7be..bcc2d3f38b 100644 --- a/src/common/Attribute.cc +++ b/src/common/Attribute.cc @@ -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::const_iterator it; + map::const_iterator it; oss << "<" << name() << ">"; @@ -102,6 +86,60 @@ void VectorAttribute::to_xml(ostringstream &oss) const oss << ""; } +void VectorAttribute::to_json(std::ostringstream& s) const +{ + if ( attribute_value.empty() ) + { + s << "{}"; + return; + } + + map::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::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; + } +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/common/NebulaUtil.cc b/src/common/NebulaUtil.cc index f572b0595f..39ad93fdf7 100644 --- a/src/common/NebulaUtil.cc +++ b/src/common/NebulaUtil.cc @@ -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<> diff --git a/src/im_mad/remotes/lxd-probes.d/profiles.sh b/src/im_mad/remotes/lxd-probes.d/profiles.sh new file mode 100755 index 0000000000..2c27b6d1ed --- /dev/null +++ b/src/im_mad/remotes/lxd-probes.d/profiles.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +cmd='lxc profile list' + +profiles=$($cmd | grep -v -- -+- | grep -v NAME | grep -v default | awk '{print $2}') + +if [ "$?" -ne "0" ]; then + profiles=$(sudo $cmd | grep -v -- -+- | grep -v NAME | grep -v default | awk '{print $2}') +fi + +tmpfile=$(mktemp /tmp/lxd_probe.XXXXXX) + +echo "$profiles" > "$tmpfile" +out=$(tr '\n' ',' < "$tmpfile") +out=${out::-1} + +echo -e LXD_PROFILES=\""$out"\" + +rm "$tmpfile" \ No newline at end of file diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 9478b94bcd..291d42a52f 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -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"); } diff --git a/src/oca/java/src/org/opennebula/client/vm/VirtualMachinePool.java b/src/oca/java/src/org/opennebula/client/vm/VirtualMachinePool.java index 3ceeacce6d..a0491ebbde 100644 --- a/src/oca/java/src/org/opennebula/client/vm/VirtualMachinePool.java +++ b/src/oca/java/src/org/opennebula/client/vm/VirtualMachinePool.java @@ -177,6 +177,36 @@ public class VirtualMachinePool extends Pool implements Iterable 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: + *
    + *
  • {@link Pool#ALL}: All Virtual Machines
  • + *
  • {@link Pool#MINE}: Connected user's Virtual Machines
  • + *
  • {@link Pool#MINE_GROUP}: Connected user's Virtual Machines, and the ones in + * his group
  • + *
  • {@link Pool#GROUP}: User's primary group Virtual Machines
  • + *
  • >= 0 UID User's Virtual Machines
  • + *
+ * @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. diff --git a/src/oca/ruby/opennebula/virtual_machine_pool.rb b/src/oca/ruby/opennebula/virtual_machine_pool.rb index c3f54635b6..aba1228e4f 100644 --- a/src/oca/ruby/opennebula/virtual_machine_pool.rb +++ b/src/oca/ruby/opennebula/virtual_machine_pool.rb @@ -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 diff --git a/src/onedb/database_schema.rb b/src/onedb/database_schema.rb index a106263571..2c9f8649a3 100644 --- a/src/onedb/database_schema.rb +++ b/src/onedb/database_schema.rb @@ -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" diff --git a/src/onedb/fsck.rb b/src/onedb/fsck.rb index de579d63c3..d366be2e11 100644 --- a/src/onedb/fsck.rb +++ b/src/onedb/fsck.rb @@ -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 diff --git a/src/onedb/local/5.6.0_to_5.7.80.rb b/src/onedb/local/5.6.0_to_5.7.80.rb index 64ad8ebd92..7d4490e3d8 100644 --- a/src/onedb/local/5.6.0_to_5.7.80.rb +++ b/src/onedb/local/5.6.0_to_5.7.80.rb @@ -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{ diff --git a/src/rm/RequestManagerPoolInfoFilter.cc b/src/rm/RequestManagerPoolInfoFilter.cc index 3228a4eac8..7b3be48b64 100644 --- a/src/rm/RequestManagerPoolInfoFilter.cc +++ b/src/rm/RequestManagerPoolInfoFilter.cc @@ -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, diff --git a/src/template/Template.cc b/src/template/Template.cc index e824e3fdae..b14995a817 100644 --- a/src/template/Template.cc +++ b/src/template/Template.cc @@ -386,19 +386,14 @@ bool Template::get(const string& name, bool& value) const string& Template::to_xml(string& xml) const { - multimap::const_iterator it; - ostringstream oss; - string * s; + multimap::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 << ""; @@ -407,6 +402,81 @@ string& Template::to_xml(string& xml) const return xml; } + +string& Template::to_json(string& json) const +{ + multimap::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::const_iterator it; + + for ( it = attributes.begin(); it!=attributes.end(); it++) + { + it->second->to_token(os); + } + + str = os.str(); + return str; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/vm/History.cc b/src/vm/History.cc index 0975ce90c4..0668094436 100644 --- a/src/vm/History.cc +++ b/src/vm/History.cc @@ -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; diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index f93717c55c..fca914df51 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -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 << "" << "" << oid << "" @@ -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; diff --git a/src/vmm_mad/exec/vmm_exec_vcenter.conf b/src/vmm_mad/exec/vmm_exec_vcenter.conf index 3cc83a2e78..484f0b3af1 100644 --- a/src/vmm_mad/exec/vmm_exec_vcenter.conf +++ b/src/vmm_mad/exec/vmm_exec_vcenter.conf @@ -16,8 +16,8 @@ # Default configuration attributes for the vCenter driver # (all domains will use these values as defaults) -# Valid atributes: +# Valid attributes: # - nic[model] -NIC=[MODEL="VirtualE1000"] - +# WARNING: Do not use!! +# Not honored due to https://github.com/OpenNebula/one/issues/2855 diff --git a/src/vmm_mad/remotes/lib/lxd/client.rb b/src/vmm_mad/remotes/lib/lxd/client.rb index c26cccad24..0f500d15d0 100644 --- a/src/vmm_mad/remotes/lib/lxd/client.rb +++ b/src/vmm_mad/remotes/lib/lxd/client.rb @@ -135,10 +135,15 @@ end # Error used for raising LXDClient exception when response is error return value class LXDError < StandardError - attr_reader :body + + attr_reader :body, :error, :error_code, :type def initialize(msg = 'LXD API error') @body = msg + @error = @body['error'] + @error_code = @body['error_code'] + @type = @body['type'] super end + end diff --git a/src/vmm_mad/remotes/lib/lxd/opennebula_vm.rb b/src/vmm_mad/remotes/lib/lxd/opennebula_vm.rb index 97d7d7da39..df6d08cccb 100644 --- a/src/vmm_mad/remotes/lib/lxd/opennebula_vm.rb +++ b/src/vmm_mad/remotes/lib/lxd/opennebula_vm.rb @@ -340,7 +340,19 @@ class OpenNebulaVM def profile(hash) profile = @xml['//USER_TEMPLATE/LXD_PROFILE'] - profile = 'default' if profile.empty? + + if profile.empty? + profile = 'default' + else + begin + LXDClient.new.get("profiles/#{profile}") + rescue LXDError => e + raise e unless e.error_code == 404 + + OpenNebula.log_error "Profile \"#{profile}\" not found\n#{e}" + profile = 'default' + end + end hash['profiles'] = [profile] end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 06ec99d1b0..4839ea5b0c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1163,8 +1163,8 @@ class VirtualMachine < VCenterDriver::Template return RbVmomi::VIM::VirtualVmxnet2 when 'virtualvmxnet3', 'vmxnet3' return RbVmomi::VIM::VirtualVmxnet3 - else # If none matches, use VirtualE1000 - return RbVmomi::VIM::VirtualE1000 + else # If none matches, use vmxnet3 + return RbVmomi::VIM::VirtualVmxnet3 end end @@ -1238,20 +1238,20 @@ class VirtualMachine < VCenterDriver::Template } unmanaged_nics.each do |unic| - vnic = select_net.call(unic['VCENTER_NET_REF']) - vcenter_nic_class = vnic.class - new_model = unic['MODEL'] && !unic['MODEL'].empty? && !unic['MODEL'].nil? - opennebula_nic_class = nic_model_class(unic['MODEL']) if new_model + vnic = select_net.call(unic['VCENTER_NET_REF']) + nic_class = vnic.class + new_model = nic_model_class(unic['MODEL']) if unic['MODEL'] - if new_model && opennebula_nic_class != vcenter_nic_class - # delete actual nic and update the new one. + # delete actual nic and update the new one. + if new_model && new_model != nic_class device_change << { :device => vnic, :operation => :remove } - device_change << calculate_add_nic_spec(unic) + device_change << calculate_add_nic_spec(unic, vnic.unitNumber) else vnic.macAddress = unic['MAC'] device_change << { :device => vnic, :operation => :edit } end end + end rescue Exception => e raise "There is a problem with your vm NICS, make sure that they are working properly. Error: #{e.message}" @@ -1370,14 +1370,21 @@ class VirtualMachine < VCenterDriver::Template device_change = [] if option == :all + dchange = [] + # detached? condition indicates that the nic exists in OpeNebula but not # in vCenter nics_each(:detached?) do |nic| - device_change << { + dchange << { :operation => :remove, :device => nic.vc_item } end + if !dchange.empty? + dspec_hash = { :deviceChange => dchange } + dspec = RbVmomi::VIM.VirtualMachineConfigSpec(dspec_hash) + @item.ReconfigVM_Task(:spec => dspec).wait_for_completion + end end # no_exits? condition indicates that the nic does not exist in vCenter @@ -1499,21 +1506,15 @@ class VirtualMachine < VCenterDriver::Template end # Returns an array of actions to be included in :deviceChange - def calculate_add_nic_spec(nic) + def calculate_add_nic_spec(nic, unumber = nil) mac = nic["MAC"] pg_name = nic["BRIDGE"] - model = '' + default = VCenterDriver::VIHelper.get_default('VM/TEMPLATE/NIC/MODEL') + tmodel = one_item['USER_TEMPLATE/NIC_DEFAULT/MODEL'] + + model = nic['MODEL'] || tmodel || default + raise 'nic model cannot be empty!' if model == '' - if !one_item.retrieve_xmlelements('TEMPLATE/NIC_DEFAULT/MODEL').nil? && - !one_item.retrieve_xmlelements('TEMPLATE/NIC_DEFAULT/MODEL').empty? - model = one_item['TEMPLATE/NIC_DEFAULT/MODEL'] - elsif (model.nil? || model.empty?) && - !nic['MODEL'].nil? && - !nic['MODEL'].empty? - model = nic['MODEL'] - else - model = VCenterDriver::VIHelper.get_default('VM/TEMPLATE/NIC/MODEL') - end vnet_ref = nic["VCENTER_NET_REF"] backing = nil @@ -1546,24 +1547,7 @@ class VirtualMachine < VCenterDriver::Template card_num += 1 if is_nic?(dv) end - nic_card = case model - when "virtuale1000", "e1000" - RbVmomi::VIM::VirtualE1000 - when "virtuale1000e", "e1000e" - RbVmomi::VIM::VirtualE1000e - when "virtualpcnet32", "pcnet32" - RbVmomi::VIM::VirtualPCNet32 - when "virtualsriovethernetcard", "sriovethernetcard" - RbVmomi::VIM::VirtualSriovEthernetCard - when "virtualvmxnetm", "vmxnetm" - RbVmomi::VIM::VirtualVmxnetm - when "virtualvmxnet2", "vmnet2" - RbVmomi::VIM::VirtualVmxnet2 - when "virtualvmxnet3", "vmxnet3" - RbVmomi::VIM::VirtualVmxnet3 - else # If none matches, use VirtualE1000 - RbVmomi::VIM::VirtualE1000 - end + nic_card = nic_model_class(model) if network.class == RbVmomi::VIM::Network backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( @@ -1580,7 +1564,13 @@ class VirtualMachine < VCenterDriver::Template end # grab the last unitNumber to ensure the nic to be added at the end - @unic = @unic || get_vcenter_nics.map{|d| d.unitNumber}.max || 0 + if !unumber + @unic = @unic || get_vcenter_nics.map{|d| d.unitNumber}.max || 0 + unumber = @unic += 1 + else + @unic = unumber + end + card_spec = { :key => 0, :deviceInfo => { @@ -1590,7 +1580,7 @@ class VirtualMachine < VCenterDriver::Template :backing => backing, :addressType => mac ? 'manual' : 'generated', :macAddress => mac, - :unitNumber => @unic+=1 + :unitNumber => unumber } if (limit || rsrv) && (limit > 0) @@ -1616,17 +1606,11 @@ class VirtualMachine < VCenterDriver::Template def calculate_add_nic_spec_autogenerate_mac(nic) pg_name = nic["BRIDGE"] model = '' + default = VCenterDriver::VIHelper.get_default('VM/TEMPLATE/NIC/MODEL') + tmodel = one_item['USER_TEMPLATE/NIC_DEFAULT/MODEL'] + + model = nic['MODEL'] || tmodel || default - if !one_item.retrieve_xmlelements('TEMPLATE/NIC_DEFAULT/MODEL').nil? && - !one_item.retrieve_xmlelements('TEMPLATE/NIC_DEFAULT/MODEL').empty? - model = one_item['TEMPLATE/NIC_DEFAULT/MODEL'] - elsif (model.nil? || model.empty?) && - !nic['MODEL'].nil? && - !nic['MODEL'].empty? - model = nic['MODEL'] - else - model = VCenterDriver::VIHelper.get_default('VM/TEMPLATE/NIC/MODEL') - end vnet_ref = nic["VCENTER_NET_REF"] backing = nil @@ -1658,24 +1642,7 @@ class VirtualMachine < VCenterDriver::Template card_num += 1 if is_nic?(dv) end - nic_card = case model - when "virtuale1000", "e1000" - RbVmomi::VIM::VirtualE1000 - when "virtuale1000e", "e1000e" - RbVmomi::VIM::VirtualE1000e - when "virtualpcnet32", "pcnet32" - RbVmomi::VIM::VirtualPCNet32 - when "virtualsriovethernetcard", "sriovethernetcard" - RbVmomi::VIM::VirtualSriovEthernetCard - when "virtualvmxnetm", "vmxnetm" - RbVmomi::VIM::VirtualVmxnetm - when "virtualvmxnet2", "vmnet2" - RbVmomi::VIM::VirtualVmxnet2 - when "virtualvmxnet3", "vmxnet3" - RbVmomi::VIM::VirtualVmxnet3 - else # If none matches, use VirtualE1000 - RbVmomi::VIM::VirtualE1000 - end + nic_card = nic_model_class(model) if network.class == RbVmomi::VIM::Network backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( diff --git a/src/vmm_mad/remotes/vcenter/vcenterrc b/src/vmm_mad/remotes/vcenter/vcenterrc index 1b5469bd81..ab04548245 100644 --- a/src/vmm_mad/remotes/vcenter/vcenterrc +++ b/src/vmm_mad/remotes/vcenter/vcenterrc @@ -14,10 +14,10 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -# No : VCENTER_IMPORTED attribute will be set on imported images +# no : VCENTER_IMPORTED attribute will be set on imported images # this attribute prevents the image to be deleted. -# Yes : You can delete the images using OpenNebula. -:delete_images: No +# yes : You can delete the images using OpenNebula. +:delete_images: no # Default timeout to complete deploy :vm_poweron_wait_default: 300 diff --git a/src/vnm/AddressRangeIPAM.cc b/src/vnm/AddressRangeIPAM.cc index 34a404eee9..a5b95c7c17 100644 --- a/src/vnm/AddressRangeIPAM.cc +++ b/src/vnm/AddressRangeIPAM.cc @@ -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);