diff --git a/include/Cluster.h b/include/Cluster.h index 822c2a28d0..52b4d46fd2 100644 --- a/include/Cluster.h +++ b/include/Cluster.h @@ -143,6 +143,30 @@ public: return rc; } + /** + * Returns a copy of the host IDs set + */ + set get_host_ids() + { + return hosts.get_collection_copy(); + } + + /** + * Returns a copy of the datastore IDs set + */ + set get_datastore_ids() + { + return datastores.get_collection_copy(); + } + + /** + * Returns a copy of the vnet IDs set + */ + set get_vnet_ids() + { + return vnets.get_collection_copy(); + } + // ************************************************************************* // DataBase implementation (Public) // ************************************************************************* diff --git a/include/Datastore.h b/include/Datastore.h index 2e7816f8e1..181dbdeba1 100644 --- a/include/Datastore.h +++ b/include/Datastore.h @@ -97,6 +97,14 @@ public: return del_collection_id(id); }; + /** + * Returns a copy of the Image IDs set + */ + set get_image_ids() + { + return get_collection_copy(); + } + /** * Retrieves TM mad name * @return string tm mad name diff --git a/include/Host.h b/include/Host.h index 801f32cc3c..aad9cef2e4 100644 --- a/include/Host.h +++ b/include/Host.h @@ -390,6 +390,14 @@ public: return host_share.test(cpu, mem, disk); } + /** + * Returns a copy of the VM IDs set + */ + set get_vm_ids() + { + return vm_collection.get_collection_copy(); + } + /** * Factory method for host templates */ diff --git a/include/Image.h b/include/Image.h index 500e26eb76..285bd18758 100644 --- a/include/Image.h +++ b/include/Image.h @@ -479,13 +479,21 @@ public: }; /** - * Returns the Datastore ID + * Returns the Datastore name */ const string& get_ds_name() const { return ds_name; }; + /** + * Updates the Datastore name + */ + void set_ds_name(const string& name) + { + ds_name = name; + }; + /** * Clones this image template including image specific attributes: NAME, * TYPE, PATH, FSTYPE, SIZE and PERSISTENT diff --git a/include/RequestManagerRename.h b/include/RequestManagerRename.h index 0034e5b62a..9e9dcf362a 100644 --- a/include/RequestManagerRename.h +++ b/include/RequestManagerRename.h @@ -34,6 +34,8 @@ protected: const string& params = "A:sis") :Request(method_name,params,help) { + pthread_mutex_init(&mutex, 0); + auth_op = AuthRequest::MANAGE; }; @@ -44,7 +46,60 @@ protected: void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); - virtual PoolObjectSQL * get(const string& name, int uid, bool lock) = 0; + /** + * Gets and object by name and owner. Default implementation returns no + * object + */ + virtual PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return 0; + } + + /** + * Batch rename of related objects. Default implementation does nothing + */ + virtual void batch_rename(int oid){}; + + /** + * Test if a rename is being perform on a given object. If not it set it. + * @return true if the rename can be performed (no ongoing rename) + */ + bool test_and_set_rename(int oid) + { + pair::iterator,bool> rc; + + pthread_mutex_lock(&mutex); + + rc = rename_ids.insert(oid); + + pthread_mutex_unlock(&mutex); + + return rc.second == true; + } + + /** + * Clear the rename. + */ + void clear_rename(int oid) + { + pthread_mutex_lock(&mutex); + + rename_ids.erase(oid); + + pthread_mutex_unlock(&mutex); + } + +private: + /** + * Mutex to control concurrent access to the ongoing rename operations + */ + pthread_mutex_t mutex; + + /** + * Set of IDs being renamed; + */ + set rename_ids; + }; /* ------------------------------------------------------------------------- */ @@ -62,11 +117,6 @@ public: }; ~VirtualMachineRename(){}; - - PoolObjectSQL * get(const string& name, int uid, bool lock) - { - return 0; - }; }; /* ------------------------------------------------------------------------- */ @@ -152,11 +202,78 @@ public: }; ~DocumentRename(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class ClusterRename: public RequestManagerRename +{ +public: + ClusterRename(): + RequestManagerRename("ClusterRename", "Renames a cluster") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_clpool(); + auth_object = PoolObjectSQL::CLUSTER; + }; + + ~ClusterRename(){}; PoolObjectSQL * get(const string& name, int uid, bool lock) { - return 0; + return static_cast(pool)->get(name, lock); }; + + void batch_rename(int oid); +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class DatastoreRename: public RequestManagerRename +{ +public: + DatastoreRename(): + RequestManagerRename("DatastoreRename", "Renames a datastore") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_dspool(); + auth_object = PoolObjectSQL::DATASTORE; + }; + + ~DatastoreRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, lock); + }; + + void batch_rename(int oid); +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class HostRename: public RequestManagerRename +{ +public: + HostRename(): + RequestManagerRename("HostRename", "Renames a host") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_hpool(); + auth_object = PoolObjectSQL::HOST; + }; + + ~HostRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, lock); + }; + + void batch_rename(int oid); }; /* -------------------------------------------------------------------------- */ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 38e943835a..645dc0b377 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -623,6 +623,16 @@ public: return history->hostname; }; + /** + * Updates the current hostname. The hasHistory() + * function MUST be called before this one. + * @param hostname New hostname + */ + void set_hostname(const string& hostname) + { + history->hostname = hostname; + }; + /** * Returns the hostname for the previous host. The hasPreviousHistory() * function MUST be called before this one. diff --git a/src/cli/onecluster b/src/cli/onecluster index 4e61e09e09..5624ec649b 100755 --- a/src/cli/onecluster +++ b/src/cli/onecluster @@ -197,4 +197,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do obj.update(str, options[:append]) end end + + rename_desc = <<-EOT.unindent + Renames the Cluster + EOT + + command :rename, rename_desc, :clusterid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end end diff --git a/src/cli/onedatastore b/src/cli/onedatastore index 77e4c4b2c2..7c09d0cb16 100755 --- a/src/cli/onedatastore +++ b/src/cli/onedatastore @@ -174,4 +174,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do obj.update(str, options[:append]) end end + + rename_desc = <<-EOT.unindent + Renames the Datastore + EOT + + command :rename, rename_desc, :datastoreid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end end diff --git a/src/cli/onehost b/src/cli/onehost index 9c9a4d9463..108db2d3fd 100755 --- a/src/cli/onehost +++ b/src/cli/onehost @@ -213,4 +213,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do host.flush end end + + rename_desc = <<-EOT.unindent + Renames the Host + EOT + + command :rename, rename_desc, :hostid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end end diff --git a/src/oca/java/src/org/opennebula/client/cluster/Cluster.java b/src/oca/java/src/org/opennebula/client/cluster/Cluster.java index 15ea8b3e31..094016ae1a 100644 --- a/src/oca/java/src/org/opennebula/client/cluster/Cluster.java +++ b/src/oca/java/src/org/opennebula/client/cluster/Cluster.java @@ -37,6 +37,7 @@ public class Cluster extends PoolElement{ private static final String DELDATASTORE = METHOD_PREFIX + "deldatastore"; private static final String ADDVNET = METHOD_PREFIX + "addvnet"; private static final String DELVNET = METHOD_PREFIX + "delvnet"; + private static final String RENAME = METHOD_PREFIX + "rename"; /** * Creates a new Cluster representation. @@ -199,6 +200,19 @@ public class Cluster extends PoolElement{ return client.call(DELVNET, id, vnetId); } + /** + * Renames this Cluster. + * + * @param client XML-RPC Client. + * @param id The image id of the target host we want to modify. + * @param name New name for the Cluster + * @return If successful the message contains the cluster id. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -315,6 +329,17 @@ public class Cluster extends PoolElement{ return delVnet(client, id, vnetId); } + /** + * Renames this Cluster + * + * @param name New name for the Cluster. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/datastore/Datastore.java b/src/oca/java/src/org/opennebula/client/datastore/Datastore.java index 26a03b8b60..f68b42303f 100644 --- a/src/oca/java/src/org/opennebula/client/datastore/Datastore.java +++ b/src/oca/java/src/org/opennebula/client/datastore/Datastore.java @@ -35,6 +35,7 @@ public class Datastore extends PoolElement private static final String UPDATE = METHOD_PREFIX + "update"; private static final String CHOWN = METHOD_PREFIX + "chown"; private static final String CHMOD = METHOD_PREFIX + "chmod"; + private static final String RENAME = METHOD_PREFIX + "rename"; private static final String[] DATASTORE_TYPES = {"IMAGE", "SYSTEM", "FILE"}; @@ -212,6 +213,19 @@ public class Datastore extends PoolElement return chmod(client, CHMOD, id, octet); } + /** + * Renames this Datastore. + * + * @param client XML-RPC Client. + * @param id The image id of the target host we want to modify. + * @param name New name for the Datastore + * @return If successful the message contains the datastore id. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -373,6 +387,17 @@ public class Datastore extends PoolElement return chmod(client, id, octet); } + /** + * Renames this Datastore + * + * @param name New name for the Datastore. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/host/Host.java b/src/oca/java/src/org/opennebula/client/host/Host.java index df36d87eae..f9aba9eb8f 100644 --- a/src/oca/java/src/org/opennebula/client/host/Host.java +++ b/src/oca/java/src/org/opennebula/client/host/Host.java @@ -34,6 +34,7 @@ public class Host extends PoolElement{ private static final String ENABLE = METHOD_PREFIX + "enable"; private static final String UPDATE = METHOD_PREFIX + "update"; private static final String MONITORING = METHOD_PREFIX + "monitoring"; + private static final String RENAME = METHOD_PREFIX + "rename"; private static final String[] HOST_STATES = {"INIT", "MONITORING_MONITORED", "MONITORED", "ERROR", "DISABLED", @@ -189,6 +190,19 @@ public class Host extends PoolElement{ return client.call(MONITORING, id); } + /** + * Renames this Host. + * + * @param client XML-RPC Client. + * @param id The image id of the target host we want to modify. + * @param name New name for the Host + * @return If successful the message contains the host id. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -280,6 +294,17 @@ public class Host extends PoolElement{ return monitoring(client, id); } + /** + * Renames this Host. + * + * @param name New name for the Host + * @return If successful the message contains the host id. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/ruby/opennebula/cluster.rb b/src/oca/ruby/opennebula/cluster.rb index 9f0997d96c..25c9d758f8 100644 --- a/src/oca/ruby/opennebula/cluster.rb +++ b/src/oca/ruby/opennebula/cluster.rb @@ -34,6 +34,7 @@ module OpenNebula :addvnet => "cluster.addvnet", :delvnet => "cluster.delvnet", :update => "cluster.update", + :rename => "cluster.rename" } # Creates a Cluster description with just its identifier @@ -171,6 +172,16 @@ module OpenNebula super(CLUSTER_METHODS[:update], new_template, append ? 1 : 0) end + # Renames this Cluster + # + # @param name [String] New name for the Cluster. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(CLUSTER_METHODS[:rename], @pe_id, name) + end + # --------------------------------------------------------------------- # Helpers to get information # --------------------------------------------------------------------- diff --git a/src/oca/ruby/opennebula/datastore.rb b/src/oca/ruby/opennebula/datastore.rb index 6bf2a9abca..fe702abfaa 100644 --- a/src/oca/ruby/opennebula/datastore.rb +++ b/src/oca/ruby/opennebula/datastore.rb @@ -29,7 +29,8 @@ module OpenNebula :delete => "datastore.delete", :update => "datastore.update", :chown => "datastore.chown", - :chmod => "datastore.chmod" + :chmod => "datastore.chmod", + :rename => "datastore.rename" } DATASTORE_TYPES=%w{IMAGE SYSTEM FILE} @@ -146,6 +147,16 @@ module OpenNebula group_m, group_a, other_u, other_m, other_a) end + # Renames this datastore + # + # @param name [String] New name for the datastore + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(DATASTORE_METHODS[:rename], @pe_id, name) + end + # --------------------------------------------------------------------- # Helpers to get information # --------------------------------------------------------------------- diff --git a/src/oca/ruby/opennebula/host.rb b/src/oca/ruby/opennebula/host.rb index 94ab6f6323..7476e01c9e 100644 --- a/src/oca/ruby/opennebula/host.rb +++ b/src/oca/ruby/opennebula/host.rb @@ -30,7 +30,8 @@ module OpenNebula :delete => "host.delete", :enable => "host.enable", :update => "host.update", - :monitoring => "host.monitoring" + :monitoring => "host.monitoring", + :rename => "host.rename" } HOST_STATES=%w{INIT MONITORING_MONITORED MONITORED ERROR DISABLED MONITORING_ERROR MONITORING_INIT MONITORING_DISABLED} @@ -176,6 +177,16 @@ module OpenNebula return @client.call(HOST_METHODS[:monitoring], @pe_id) end + # Renames this Host + # + # @param name [String] New name for the Host. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(HOST_METHODS[:rename], @pe_id, name) + end + ####################################################################### # Helpers to get Host information ####################################################################### diff --git a/src/onedb/fsck.rb b/src/onedb/fsck.rb index 649643234b..1d29fd41fd 100644 --- a/src/onedb/fsck.rb +++ b/src/onedb/fsck.rb @@ -308,9 +308,11 @@ module OneDBFsck cluster = {} - @db.fetch("SELECT oid FROM cluster_pool") do |row| + @db.fetch("SELECT oid, name FROM cluster_pool") do |row| cluster[row[:oid]] = {} + cluster[row[:oid]][:name] = row[:name] + cluster[row[:oid]][:hosts] = [] cluster[row[:oid]][:datastores] = [] cluster[row[:oid]][:vnets] = [] @@ -322,13 +324,21 @@ module OneDBFsck datastores_fix = {} vnets_fix = {} - @db.fetch("SELECT oid,body FROM host_pool") do |row| + @db.fetch("SELECT oid,body,cid FROM host_pool") do |row| doc = Document.new(row[:body]) cluster_id = doc.root.get_text('CLUSTER_ID').to_s.to_i + cluster_name = doc.root.get_text('CLUSTER') + + if cluster_id != row[:cid] + log_error("Host #{row[:oid]} is in cluster #{cluster_id}, but cid column has cluster #{row[:cid]}") + hosts_fix[row[:oid]] = {:body => row[:body], :cid => cluster_id} + end if cluster_id != -1 - if cluster[cluster_id].nil? + cluster_entry = cluster[cluster_id] + + if cluster_entry.nil? log_error("Host #{row[:oid]} is in cluster #{cluster_id}, but it does not exist") doc.root.each_element('CLUSTER_ID') do |e| @@ -339,25 +349,43 @@ module OneDBFsck e.text = "" end - hosts_fix[row[:oid]] = doc.to_s + hosts_fix[row[:oid]] = {:body => doc.to_s, :cid => -1} else - cluster[cluster_id][:hosts] << row[:oid] + if cluster_name != cluster_entry[:name] + log_error("Host #{row[:oid]} has a wrong name for cluster #{cluster_id}, #{cluster_name}. It will be changed to #{cluster_entry[:name]}") + + doc.root.each_element('CLUSTER') do |e| + e.text = cluster_entry[:name] + end + + hosts_fix[row[:oid]] = {:body => doc.to_s, :cid => cluster_id} + end + + cluster_entry[:hosts] << row[:oid] end end end - hosts_fix.each do |id, body| - @db[:host_pool].where(:oid => id).update(:body => body, :cid => -1) + hosts_fix.each do |id, entry| + @db[:host_pool].where(:oid => id).update(:body => entry[:body], :cid => entry[:cid]) end - @db.fetch("SELECT oid,body FROM datastore_pool") do |row| + @db.fetch("SELECT oid,body,cid FROM datastore_pool") do |row| doc = Document.new(row[:body]) cluster_id = doc.root.get_text('CLUSTER_ID').to_s.to_i + cluster_name = doc.root.get_text('CLUSTER') + + if cluster_id != row[:cid] + log_error("Datastore #{row[:oid]} is in cluster #{cluster_id}, but cid column has cluster #{row[:cid]}") + hosts_fix[row[:oid]] = {:body => row[:body], :cid => cluster_id} + end if cluster_id != -1 - if cluster[cluster_id].nil? + cluster_entry = cluster[cluster_id] + + if cluster_entry.nil? log_error("Datastore #{row[:oid]} is in cluster #{cluster_id}, but it does not exist") doc.root.each_element('CLUSTER_ID') do |e| @@ -368,16 +396,16 @@ module OneDBFsck e.text = "" end - datastores_fix[row[:oid]] = doc.to_s + datastores_fix[row[:oid]] = {:body => doc.to_s, :cid => -1} else if doc.root.get_text('TYPE').to_s != "1" - cluster[cluster_id][:datastores] << row[:oid] + cluster_entry[:datastores] << row[:oid] else - if cluster[cluster_id][:system_ds] == 0 - cluster[cluster_id][:datastores] << row[:oid] - cluster[cluster_id][:system_ds] = row[:oid] + if cluster_entry[:system_ds] == 0 + cluster_entry[:datastores] << row[:oid] + cluster_entry[:system_ds] = row[:oid] else - log_error("System Datastore #{row[:oid]} is in Cluster #{cluster_id}, but it already contains System Datastore #{cluster[cluster_id][:system_ds]}") + log_error("System Datastore #{row[:oid]} is in Cluster #{cluster_id}, but it already contains System Datastore #{cluster_entry[:system_ds]}") doc.root.each_element('CLUSTER_ID') do |e| e.text = "-1" @@ -387,25 +415,45 @@ module OneDBFsck e.text = "" end - datastores_fix[row[:oid]] = doc.to_s + datastores_fix[row[:oid]] = {:body => doc.to_s, :cid => -1} + + next end end + + if cluster_name != cluster_entry[:name] + log_error("Datastore #{row[:oid]} has a wrong name for cluster #{cluster_id}, #{cluster_name}. It will be changed to #{cluster_entry[:name]}") + + doc.root.each_element('CLUSTER') do |e| + e.text = cluster_entry[:name] + end + + datastores_fix[row[:oid]] = {:body => doc.to_s, :cid => cluster_id} + end end end end - datastores_fix.each do |id, body| - @db[:datastore_pool].where(:oid => id).update(:body => body, :cid => -1) + datastores_fix.each do |id, entry| + @db[:datastore_pool].where(:oid => id).update(:body => entry[:body], :cid => entry[:cid]) end - @db.fetch("SELECT oid,body FROM network_pool") do |row| + @db.fetch("SELECT oid,body,cid FROM network_pool") do |row| doc = Document.new(row[:body]) cluster_id = doc.root.get_text('CLUSTER_ID').to_s.to_i + cluster_name = doc.root.get_text('CLUSTER') + + if cluster_id != row[:cid] + log_error("VNet #{row[:oid]} is in cluster #{cluster_id}, but cid column has cluster #{row[:cid]}") + hosts_fix[row[:oid]] = {:body => row[:body], :cid => cluster_id} + end if cluster_id != -1 - if cluster[cluster_id].nil? + cluster_entry = cluster[cluster_id] + + if cluster_entry.nil? log_error("VNet #{row[:oid]} is in cluster #{cluster_id}, but it does not exist") doc.root.each_element('CLUSTER_ID') do |e| @@ -416,15 +464,25 @@ module OneDBFsck e.text = "" end - vnets_fix[row[:oid]] = doc.to_s + vnets_fix[row[:oid]] = {:body => doc.to_s, :cid => -1} else - cluster[cluster_id][:vnets] << row[:oid] + if cluster_name != cluster_entry[:name] + log_error("VNet #{row[:oid]} has a wrong name for cluster #{cluster_id}, #{cluster_name}. It will be changed to #{cluster_entry[:name]}") + + doc.root.each_element('CLUSTER') do |e| + e.text = cluster_entry[:name] + end + + vnets_fix[row[:oid]] = {:body => doc.to_s, :cid => -1} + end + + cluster_entry[:vnets] << row[:oid] end end end - vnets_fix.each do |id, body| - @db[:network_pool].where(:oid => id).update(:body => body, :cid => -1) + vnets_fix.each do |id, entry| + @db[:network_pool].where(:oid => id).update(:body => entry[:body], :cid => entry[:cid]) end @@ -528,35 +586,49 @@ module OneDBFsck datastore = {} - @db.fetch("SELECT oid FROM datastore_pool") do |row| - datastore[row[:oid]] = [] + @db.fetch("SELECT oid, name FROM datastore_pool") do |row| + datastore[row[:oid]] = {:name => row[:name], :images => []} end - images_fix = {} + ds_1_name = datastore[1][:name] + images_fix = {} @db.fetch("SELECT oid,body FROM image_pool") do |row| doc = Document.new(row[:body]) ds_id = doc.root.get_text('DATASTORE_ID').to_s.to_i + ds_name = doc.root.get_text('DATASTORE') if ds_id != -1 - if datastore[ds_id].nil? - log_error("Image #{row[:oid]} has datastore #{ds_id}, but it does not exist. It will be moved to the Datastore default (1), but it is probably unusable anymore") + ds_entry = datastore[ds_id] + + if ds_entry.nil? + log_error("Image #{row[:oid]} has datastore #{ds_id}, but it does not exist. It will be moved to the Datastore #{ds_1_name} (1), but it is probably unusable anymore") doc.root.each_element('DATASTORE_ID') do |e| e.text = "1" end doc.root.each_element('DATASTORE') do |e| - e.text = "default" + e.text = ds_1_name end images_fix[row[:oid]] = doc.to_s - datastore[1] << row[:oid] + datastore[1][:images] << row[:oid] else - datastore[ds_id] << row[:oid] + if ds_name != ds_entry[:name] + log_error("Image #{row[:oid]} has a wrong name for datastore #{ds_id}, #{ds_name}. It will be changed to #{ds_entry[:name]}") + + doc.root.each_element('DATASTORE') do |e| + e.text = ds_entry[:name] + end + + images_fix[row[:oid]] = doc.to_s + end + + ds_entry[:images] << row[:oid] end end end @@ -576,7 +648,7 @@ module OneDBFsck images_new_elem = doc.root.add_element("IMAGES") - datastore[ds_id].each do |id| + datastore[ds_id][:images].each do |id| id_elem = images_elem.elements.delete("ID[.=#{id}]") if id_elem.nil? @@ -611,8 +683,9 @@ module OneDBFsck counters[:vnet] = {} # Initialize all the host counters to 0 - @db.fetch("SELECT oid FROM host_pool") do |row| + @db.fetch("SELECT oid, name FROM host_pool") do |row| counters[:host][row[:oid]] = { + :name => row[:name], :memory => 0, :cpu => 0, :rvms => Set.new @@ -655,6 +728,8 @@ module OneDBFsck } end + vms_fix = {} + # Aggregate information of the RUNNING vms @db.fetch("SELECT oid,body FROM vm_pool WHERE state<>6") do |row| vm_doc = Document.new(row[:body]) @@ -713,21 +788,41 @@ module OneDBFsck cpu = e.text.to_f } - # Get hostid + # Get hostid, hostname hid = -1 vm_doc.root.each_element("HISTORY_RECORDS/HISTORY[last()]/HID") { |e| hid = e.text.to_i } - if counters[:host][hid].nil? + hostname = "" + vm_doc.root.each_element("HISTORY_RECORDS/HISTORY[last()]/HOSTNAME") { |e| + hostname = e.text + } + + counters_host = counters[:host][hid] + + if counters_host.nil? log_error("VM #{row[:oid]} is using Host #{hid}, but it does not exist") else - counters[:host][hid][:memory] += memory - counters[:host][hid][:cpu] += cpu - counters[:host][hid][:rvms].add(row[:oid]) + if counters_host[:name] != hostname + log_error("VM #{row[:oid]} has a wrong hostname for Host #{hid}, #{hostname}. It will be changed to #{counters_host[:name]}") + + vm_doc.root.each_element("HISTORY_RECORDS/HISTORY[last()]/HOSTNAME") { |e| + e.text = counters_host[:name] + } + + vms_fix[row[:oid]] = vm_doc.to_s + end + + counters_host[:memory] += memory + counters_host[:cpu] += cpu + counters_host[:rvms].add(row[:oid]) end end + vms_fix.each do |id, body| + @db[:vm_pool].where(:oid => id).update(:body => body) + end ######################################################################## @@ -752,9 +847,11 @@ module OneDBFsck hid = row[:oid] - rvms = counters[:host][hid][:rvms].size - cpu_usage = (counters[:host][hid][:cpu]*100).to_i - mem_usage = counters[:host][hid][:memory]*1024 + counters_host = counters[:host][hid] + + rvms = counters_host[:rvms].size + cpu_usage = (counters_host[:cpu]*100).to_i + mem_usage = counters_host[:memory]*1024 # rewrite running_vms host_doc.root.each_element("HOST_SHARE/RUNNING_VMS") {|e| @@ -770,7 +867,7 @@ module OneDBFsck vms_new_elem = host_doc.root.add_element("VMS") - counters[:host][hid][:rvms].each do |id| + counters_host[:rvms].each do |id| id_elem = vms_elem.elements.delete("ID[.=#{id}]") if id_elem.nil? diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 31dc020d6f..bdd4b5e3f9 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -407,6 +407,9 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr vn_rename(new VirtualNetworkRename()); xmlrpc_c::methodPtr image_rename(new ImageRename()); xmlrpc_c::methodPtr doc_rename(new DocumentRename()); + xmlrpc_c::methodPtr cluster_rename(new ClusterRename()); + xmlrpc_c::methodPtr datastore_rename(new DatastoreRename()); + xmlrpc_c::methodPtr host_rename(new HostRename()); /* VM related methods */ RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy); @@ -454,6 +457,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.host.delete", host_delete); RequestManagerRegistry.addMethod("one.host.info", host_info); RequestManagerRegistry.addMethod("one.host.monitoring", host_monitoring); + RequestManagerRegistry.addMethod("one.host.rename", host_rename); RequestManagerRegistry.addMethod("one.hostpool.info", hostpool_info); RequestManagerRegistry.addMethod("one.hostpool.monitoring", host_pool_monitoring); @@ -528,6 +532,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.datastore.update", datastore_update); RequestManagerRegistry.addMethod("one.datastore.chown", datastore_chown); RequestManagerRegistry.addMethod("one.datastore.chmod", datastore_chmod); + RequestManagerRegistry.addMethod("one.datastore.rename", datastore_rename); RequestManagerRegistry.addMethod("one.datastorepool.info",datastorepool_info); @@ -536,6 +541,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.cluster.delete", cluster_delete); RequestManagerRegistry.addMethod("one.cluster.info", cluster_info); RequestManagerRegistry.addMethod("one.cluster.update", cluster_update); + RequestManagerRegistry.addMethod("one.cluster.rename", cluster_rename); RequestManagerRegistry.addMethod("one.cluster.addhost", cluster_addhost); RequestManagerRegistry.addMethod("one.cluster.delhost", cluster_delhost); diff --git a/src/rm/RequestManagerRename.cc b/src/rm/RequestManagerRename.cc index c5c899adcf..0685f3fa75 100644 --- a/src/rm/RequestManagerRename.cc +++ b/src/rm/RequestManagerRename.cc @@ -36,16 +36,27 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, PoolObjectAuth operms; PoolObjectSQL * object; + if (test_and_set_rename(oid) == false) + { + failure_response(INTERNAL, + request_error("Object is being renamed", ""), att); + + return; + } + rc = get_info(pool, oid, auth_object, att, operms, old_name); if ( rc == -1 ) { + clear_rename(oid); return; } if (old_name == new_name) { success_response(oid, att); + + clear_rename(oid); return; } @@ -62,12 +73,12 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, failure_response(AUTHORIZATION, authorization_error(ar.message, att), att); - + clear_rename(oid); return; } } - // --------------- Check name uniqueness ----------------------------------- + // ----------------------- Check name uniqueness --------------------------- object = get(new_name, operms.uid, true); @@ -85,10 +96,12 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, << id; failure_response(ACTION, request_error(oss.str(), ""), att); + + clear_rename(oid); return; } - // --------------- Update the object --------------------------------------- + // -------------------------- Update the object ---------------------------- object = pool->get(oid, true); @@ -97,6 +110,9 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, failure_response(NO_EXISTS, get_error(object_name(auth_object), oid), att); + + clear_rename(oid); + return; } if ( object->set_name(new_name, error_str) != 0 ) @@ -104,6 +120,8 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, object->unlock(); failure_response(ACTION, request_error(error_str, ""), att); + + clear_rename(oid); return; } @@ -113,8 +131,174 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, pool->update_cache_index(old_name, operms.uid, new_name, operms.uid); + batch_rename(oid); + success_response(oid, att); + clear_rename(oid); + return; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void ClusterRename::batch_rename(int oid) +{ + Cluster * cluster = static_cast(pool)->get(oid, true); + + if (cluster == 0) + { + return; + } + + const set & hosts = cluster->get_host_ids(); + const set & datastores = cluster->get_datastore_ids(); + const set & vnets = cluster->get_vnet_ids(); + + set::iterator it; + + string cluster_name = cluster->get_name(); + + cluster->unlock(); + + Host * host; + HostPool* hpool = Nebula::instance().get_hpool(); + + Datastore * ds; + DatastorePool* dspool = Nebula::instance().get_dspool(); + + VirtualNetwork* vnet; + VirtualNetworkPool* vnpool = Nebula::instance().get_vnpool(); + + for (it = hosts.begin(); it != hosts.end(); it++) + { + host = hpool->get(*it, true); + + if (host != 0) + { + if (host->get_cluster_id() == oid) + { + host->set_cluster(oid, cluster_name); + hpool->update(host); + } + + host->unlock(); + } + } + + for (it = datastores.begin(); it != datastores.end(); it++) + { + ds = dspool->get(*it, true); + + if (ds != 0) + { + if (ds->get_cluster_id() == oid) + { + ds->set_cluster(oid, cluster_name); + dspool->update(ds); + } + + ds->unlock(); + } + } + + for (it = vnets.begin(); it != vnets.end(); it++) + { + vnet = vnpool->get(*it, true); + + if (vnet != 0) + { + if (vnet->get_cluster_id() == oid) + { + vnet->set_cluster(oid, cluster_name); + vnpool->update(vnet); + } + + vnet->unlock(); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void DatastoreRename::batch_rename(int oid) +{ + Datastore * datastore = static_cast(pool)->get(oid, true); + + if (datastore == 0) + { + return; + } + + const set & images = datastore->get_image_ids(); + + set::iterator it; + + string image_name = datastore->get_name(); + + datastore->unlock(); + + Image * image; + ImagePool * ipool = Nebula::instance().get_ipool(); + + for (it = images.begin(); it != images.end(); it++) + { + image = ipool->get(*it, true); + + if (image != 0) + { + if (image->get_ds_id() == oid) + { + image->set_ds_name(image_name); + ipool->update(image); + } + + image->unlock(); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void HostRename::batch_rename(int oid) +{ + Host * host = static_cast(pool)->get(oid, true); + + if (host == 0) + { + return; + } + + const set & vms = host->get_vm_ids(); + + set::iterator it; + + string host_name = host->get_name(); + + host->unlock(); + + VirtualMachine * vm; + VirtualMachinePool * vmpool = Nebula::instance().get_vmpool(); + + for (it = vms.begin(); it != vms.end(); it++) + { + vm = vmpool->get(*it, true); + + if (vm != 0) + { + if (vm->hasHistory() && vm->get_hid() == oid) + { + vm->set_hostname(host_name); + vmpool->update(vm); + } + + vm->unlock(); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb b/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb index c2d8a09c12..8713d15574 100644 --- a/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb @@ -43,6 +43,7 @@ module OpenNebulaJSON when "addvnet" then self.addvnet(action_hash['params']) when "delvnet" then self.delvnet(action_hash['params']) when "update" then self.update(action_hash['params']) + when "rename" then self.rename(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << @@ -78,5 +79,9 @@ module OpenNebulaJSON def update(params=Hash.new) super(params['template_raw']) end + + def rename(params=Hash.new) + super(params['name']) + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb b/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb index e7ff02b4ea..a17ad80f7e 100644 --- a/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb @@ -50,6 +50,7 @@ module OpenNebulaJSON when "update" then self.update(action_hash['params']) when "chown" then self.chown(action_hash['params']) when "chmod" then self.chmod_octet(action_hash['params']) + when "rename" then self.rename(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -68,5 +69,9 @@ module OpenNebulaJSON def chmod_octet(params=Hash.new) super(params['octet']) end + + def rename(params=Hash.new) + super(params['name']) + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/HostJSON.rb b/src/sunstone/models/OpenNebulaJSON/HostJSON.rb index 196010d609..57adb5df10 100644 --- a/src/sunstone/models/OpenNebulaJSON/HostJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/HostJSON.rb @@ -51,6 +51,7 @@ module OpenNebulaJSON when "enable" then self.enable when "disable" then self.disable when "update" then self.update(action_hash['params']) + when "rename" then self.rename(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -62,5 +63,8 @@ module OpenNebulaJSON super(params['template_raw']) end + def rename(params=Hash.new) + super(params['name']) + end end end diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 878e005170..4fcf8542a1 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -531,6 +531,13 @@ var OpenNebula = { }, "pool_monitor" : function(params){ OpenNebula.Action.monitor(params,OpenNebula.Host.resource,true); + }, + "rename" : function(params){ + var action_obj = params.data.extra_param; + OpenNebula.Action.simple_action(params, + OpenNebula.Host.resource, + "rename", + action_obj); } }, @@ -1152,6 +1159,13 @@ var OpenNebula = { OpenNebula.Cluster.resource, "update", action_obj); + }, + "rename" : function(params){ + var action_obj = params.data.extra_param; + OpenNebula.Action.simple_action(params, + OpenNebula.Cluster.resource, + "rename", + action_obj); } }, "Datastore" : { @@ -1191,6 +1205,13 @@ var OpenNebula = { }, "fetch_template" : function(params){ OpenNebula.Action.show(params,OpenNebula.Datastore.resource,"template"); + }, + "rename" : function(params){ + var action_obj = params.data.extra_param; + OpenNebula.Action.simple_action(params, + OpenNebula.Datastore.resource, + "rename", + action_obj); } }, diff --git a/src/sunstone/public/js/plugins/clusters-tab.js b/src/sunstone/public/js/plugins/clusters-tab.js index 53f372bf6b..245c255590 100644 --- a/src/sunstone/public/js/plugins/clusters-tab.js +++ b/src/sunstone/public/js/plugins/clusters-tab.js @@ -1070,6 +1070,18 @@ var cluster_actions = { type: "single", call: popUpUpdateClusterDialog }, + + "Cluster.rename" : { + type: "single", + call: OpenNebula.Cluster.rename, + callback: function(request) { + notifyMessage(tr("Cluster renamed correctly")); + Sunstone.runAction('Cluster.showinfo',request.request.data[0]); + Sunstone.runAction('Cluster.list'); + }, + error: onError, + notify: true + } }; var cluster_buttons = { @@ -1233,18 +1245,22 @@ function updateClusterInfo(request,cluster){
\ \ \ - \ \ \ \ \ - \ + \ \ \ - \ - \ + \ + \ + \ \ \
' + +
' + tr("Cluster") + ' - '+cluster_info.NAME+'
' + tr("id") + ''+cluster_info.ID+''+cluster_info.ID+'
' + tr("Name") + ''+cluster_info.NAME+''+tr("Name")+''+cluster_info.NAME+'
\ + \ +
\ +
\ @@ -1291,6 +1307,25 @@ function updateClusterInfo(request,cluster){
' } + $("#div_edit_rename_link").die(); + $(".input_edit_value_rename").die(); + + // Listener for edit link for rename + $("#div_edit_rename_link").live("click", function() { + var value_str = $(".value_td_rename").text(); + $(".value_td_rename").html(''); + }); + + $(".input_edit_value_rename").live("change", function() { + var value_str = $(".input_edit_value_rename").val(); + if(value_str!="") + { + // Let OpenNebula know + var name_template = {"name": value_str}; + Sunstone.runAction("Cluster.rename",cluster_info.ID,name_template); + } + }); + //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_info_tab",info_tab); Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_host_tab",cluster_host_tab); diff --git a/src/sunstone/public/js/plugins/datastores-tab.js b/src/sunstone/public/js/plugins/datastores-tab.js index 9913f3d759..35729778be 100644 --- a/src/sunstone/public/js/plugins/datastores-tab.js +++ b/src/sunstone/public/js/plugins/datastores-tab.js @@ -524,6 +524,18 @@ var datastore_actions = { hideDialog(); $('div#datastores_tab div.legend_div').slideToggle(); } + }, + + "Datastore.rename" : { + type: "single", + call: OpenNebula.Datastore.rename, + callback: function(request) { + notifyMessage(tr("Datastore renamed correctly")); + Sunstone.runAction('Datastore.showinfo',request.request.data[0]); + Sunstone.runAction('Datastore.list'); + }, + error: onError, + notify: true } }; @@ -733,9 +745,12 @@ function updateDatastoreInfo(request,ds){ \ \ \ - '+tr("Name")+'\ - '+info.NAME+'\ - \ + '+tr("Name")+'\ + '+info.NAME+'\ +
\ + \ +
\ + \ \ '+ cluster_str + @@ -787,6 +802,24 @@ function updateDatastoreInfo(request,ds){ content : '
' + datastore_image_table_tmpl + '
' } + $("#div_edit_rename_link").die(); + $(".input_edit_value_rename").die(); + + // Listener for edit link for rename + $("#div_edit_rename_link").live("click", function() { + var value_str = $(".value_td_rename").text(); + $(".value_td_rename").html(''); + }); + + $(".input_edit_value_rename").live("change", function() { + var value_str = $(".input_edit_value_rename").val(); + if(value_str!="") + { + // Let OpenNebula know + var name_template = {"name": value_str}; + Sunstone.runAction("Datastore.rename",info.ID,name_template); + } + }); // Add tabs Sunstone.updateInfoPanelTab("datastore_info_panel","datastore_info_tab",info_tab); diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 2ef52deb31..956724045a 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -384,8 +384,19 @@ var host_actions = { hideDialog(); $('div#hosts_tab div.legend_div').slideToggle(); } - } + }, + "Host.rename" : { + type: "single", + call: OpenNebula.Host.rename, + callback: function(request) { + notifyMessage(tr("Host renamed correctly")); + Sunstone.runAction('Host.showinfo',request.request.data[0]); + Sunstone.runAction('Host.list'); + }, + error: onError, + notify: true + } }; var host_buttons = { @@ -732,8 +743,12 @@ function updateHostInfo(request,host){ '+host_info.ID+'\ \ \ - ' + tr("Name") + '\ - '+host_info.NAME+'\ + '+tr("Name")+'\ + '+host_info.NAME+'\ +
\ + \ +
\ + \ \ ' + insert_cluster_dropdown("Host",host_info.ID,host_info.CLUSTER,host_info.CLUSTER_ID) + @@ -828,6 +843,25 @@ function updateHostInfo(request,host){ ' } + $("#div_edit_rename_link").die(); + $(".input_edit_value_rename").die(); + + // Listener for edit link for rename + $("#div_edit_rename_link").live("click", function() { + var value_str = $(".value_td_rename").text(); + $(".value_td_rename").html(''); + }); + + $(".input_edit_value_rename").live("change", function() { + var value_str = $(".input_edit_value_rename").val(); + if(value_str!="") + { + // Let OpenNebula know + var name_template = {"name": value_str}; + Sunstone.runAction("Host.rename",host_info.ID,name_template); + } + }); + //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); Sunstone.updateInfoPanelTab("host_info_panel","host_info_tab",info_tab); Sunstone.updateInfoPanelTab("host_info_panel","host_monitoring_tab",monitor_tab);