diff --git a/src/onedb/3.6.1_fsck.rb b/src/onedb/3.6.1_fsck.rb deleted file mode 100644 index 7f71eeac02..0000000000 --- a/src/onedb/3.6.1_fsck.rb +++ /dev/null @@ -1,163 +0,0 @@ -# -------------------------------------------------------------------------- # -# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -#--------------------------------------------------------------------------- # - -require "rexml/document" -include REXML - -module OneDBFsck - VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED} - - LCM_STATE=%w{LCM_INIT PROLOG BOOT RUNNING MIGRATE SAVE_STOP SAVE_SUSPEND - SAVE_MIGRATE PROLOG_MIGRATE PROLOG_RESUME EPILOG_STOP EPILOG - SHUTDOWN CANCEL FAILURE CLEANUP UNKNOWN HOTPLUG} - - SHORT_VM_STATES={ - "INIT" => "init", - "PENDING" => "pend", - "HOLD" => "hold", - "ACTIVE" => "actv", - "STOPPED" => "stop", - "SUSPENDED" => "susp", - "DONE" => "done", - "FAILED" => "fail" - } - - SHORT_LCM_STATES={ - "PROLOG" => "prol", - "BOOT" => "boot", - "RUNNING" => "runn", - "MIGRATE" => "migr", - "SAVE_STOP" => "save", - "SAVE_SUSPEND" => "save", - "SAVE_MIGRATE" => "save", - "PROLOG_MIGRATE"=> "migr", - "PROLOG_RESUME" => "prol", - "EPILOG_STOP" => "epil", - "EPILOG" => "epil", - "SHUTDOWN" => "shut", - "CANCEL" => "shut", - "FAILURE" => "fail", - "CLEANUP" => "clea", - "UNKNOWN" => "unkn", - "HOTPLUG" => "hotp" - } - - MIGRATE_REASON=%w{NONE ERROR STOP_RESUME USER CANCEL} - - SHORT_MIGRATE_REASON={ - "NONE" => "none", - "ERROR" => "erro", - "STOP_RESUME" => "stop", - "USER" => "user", - "CANCEL" => "canc" - } - - def db_version - "3.6.1" - end - - def one_version - "OpenNebula 3.6.1" - end - - def fsck - counters = {:host => {}} - - # Initialize all the hosts to 0 - @db[:host_pool].each do |row| - hid = row[:oid] - counters[:host][hid] = { - :memory => 0, - :cpu => 0, - :rvms => 0 - } - end - - # Aggregate information of the RUNNING vms - @db[:vm_pool].where(:state => 3).each do |row| - vm_doc = Document.new(row[:body]) - - state = vm_doc.root.get_text('STATE').to_s.to_i - lcm_state = vm_doc.root.get_text('LCM_STATE').to_s.to_i - - # Take only into account ACTIVE and SUSPENDED vms - # the rest don't eat up resources. - next if !%w(ACTIVE SUSPENDED).include?(VM_STATE[state]) - - # Get memory (integer) - memory = 0 - vm_doc.root.each_element("TEMPLATE/MEMORY") { |e| - memory = e.text.to_i - } - - # Get CPU (float) - cpu = 0 - vm_doc.root.each_element("TEMPLATE/CPU") { |e| - cpu = e.text.to_f - } - - # Get hostid - hid = -1 - vm_doc.root.each_element("HISTORY_RECORDS/HISTORY[last()]/HID") { |e| - hid = e.text.to_i - } - - counters[:host][hid][:memory] += memory - counters[:host][hid][:cpu] += cpu - counters[:host][hid][:rvms] += 1 - end - - # Create a new empty table where we will store the new calculated values - @db.run "CREATE TABLE host_pool_new (oid INTEGER PRIMARY KEY, " << - "name VARCHAR(128), body TEXT, state INTEGER, " << - "last_mon_time INTEGER, uid INTEGER, gid INTEGER, " << - "owner_u INTEGER, group_u INTEGER, other_u INTEGER, " << - "UNIQUE(name));" - - # Calculate the host's xml and write them to host_pool_new - @db[:host_pool].each do |row| - host_doc = Document.new(row[:body]) - - hid = row[:oid] - - # rewrite running_vms - host_doc.root.each_element("HOST_SHARE/RUNNING_VMS") {|e| - e.text = counters[:host][hid][:rvms] - } - - # rewrite cpu - host_doc.root.each_element("HOST_SHARE/CPU_USAGE") {|e| - e.text = (counters[:host][hid][:cpu]*100).to_i - } - - # rewrite memory - host_doc.root.each_element("HOST_SHARE/MEM_USAGE") {|e| - e.text = counters[:host][hid][:memory]*1024 - } - - row[:body] = host_doc.to_s - - # commit - @db[:host_pool_new].insert(row) - end - - # Rename table - @db.run("DROP TABLE host_pool") - @db.run("ALTER TABLE host_pool_new RENAME TO host_pool") - - return true - end -end diff --git a/src/onedb/3.8.0_fsck.rb b/src/onedb/3.8.0_fsck.rb new file mode 100644 index 0000000000..e1c7106170 --- /dev/null +++ b/src/onedb/3.8.0_fsck.rb @@ -0,0 +1,780 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require "rexml/document" +include REXML +require 'ipaddr' + +module OneDBFsck + def db_version + "3.8.0" + end + + def one_version + "OpenNebula 3.8.0" + end + + def fsck + + ######################################################################## + # Acl + ######################################################################## + + ######################################################################## + # pool_control + ######################################################################## + + ######################################################################## + # Clusters + # + # CLUSTERS/HOSTS/ID + # CLUSTERS/DATASTORES/ID + # CLUSTERS/VNETS/ID + ######################################################################## + + ######################################################################## + # Groups + # + # GROUP/USERS/ID + ######################################################################## + + ######################################################################## + # Users + # + # USER/GID + # USER/GNAME + ######################################################################## + + ######################################################################## + # Datastore + # + # DATASTORE/UID + # DATASTORE/UNAME + # DATASTORE/GID + # DATASTORE/GNAME + # DATASTORE/SYSTEM ?? + # DATASTORE/CLUSTER_ID + # DATASTORE/CLUSTER + # DATASTORE/IMAGES/ID + ######################################################################## + + ######################################################################## + # VM Template + # + # VMTEMPLATE/UID + # VMTEMPLATE/UNAME + # VMTEMPLATE/GID + # VMTEMPLATE/GNAME + ######################################################################## + + ######################################################################## + # Documents + # + # DOCUMENT/UID + # DOCUMENT/UNAME + # DOCUMENT/GID + # DOCUMENT/GNAME + ######################################################################## + + ######################################################################## + # VM + # + # VM/UID + # VM/UNAME + # VM/GID + # VM/GNAME + # + # VM/STATE <--- Check transitioning states? + # VM/LCM_STATE <---- Check consistency state/lcm_state ? + ######################################################################## + + ######################################################################## + # Image + # + # IMAGE/UID + # IMAGE/UNAME + # IMAGE/GID + # IMAGE/GNAME + # IMAGE/CLONING_OPS + # IMAGE/CLONING_ID + # IMAGE/DATASTORE_ID + # IMAGE/DATASTORE + ######################################################################## + + ######################################################################## + # VNet + # + # VNET/UID + # VNET/UNAME + # VNET/GID + # VNET/GNAME + # + # VNET/CLUSTER_ID + # VNET/CLUSTER + ######################################################################## + + ######################################################################## + # Hosts + # + # HOST/CLUSTER_ID + # HOST/CLUSTER + ######################################################################## + + + @errors = 0 + puts + + counters = {} + counters[:host] = {} + counters[:image] = {} + counters[:vnet] = {} + + # Initialize all the host counters to 0 + @db.fetch("SELECT oid FROM host_pool") do |row| + counters[:host][row[:oid]] = { + :memory => 0, + :cpu => 0, + :rvms => 0 + } + end + + # Init image counters + @db.fetch("SELECT oid FROM image_pool") do |row| + counters[:image][row[:oid]] = { + :rvms => 0 + } + end + + # Init vnet counters + @db.fetch("SELECT oid,body FROM network_pool") do |row| + doc = Document.new(row[:body]) + + counters[:vnet][row[:oid]] = { + :type => doc.root.get_text('TYPE').to_s.to_i, + :total_leases => 0, + :leases => {} + } + end + + # Aggregate information of the RUNNING vms + @db.fetch("SELECT body FROM vm_pool WHERE state<>6") do |row| + vm_doc = Document.new(row[:body]) + + state = vm_doc.root.get_text('STATE').to_s.to_i + lcm_state = vm_doc.root.get_text('LCM_STATE').to_s.to_i + + + # Images used by this VM + vm_doc.root.each_element("TEMPLATE/DISK/IMAGE_ID") do |e| + counters[:image][e.text.to_i][:rvms] += 1 + end + + # VNets used by this VM + vm_doc.root.each_element("TEMPLATE/NIC") do |e| + net_id = nil + e.each_element("NETWORK_ID") do |nid| + net_id = nid.text.to_i + end + + if !net_id.nil? + counters[:vnet][net_id][:leases][e.get_text('IP').to_s] = + [ + e.get_text('MAC').to_s, # MAC + "1", # USED + vm_doc.root.get_text('ID').to_s.to_i # VID + ] + end + end + + # Host resources + + # Only states that add to Host resources consumption are + # ACTIVE, SUSPENDED, POWEROFF + next if !([3,5,8].include? state) + + # Get memory (integer) + memory = 0 + vm_doc.root.each_element("TEMPLATE/MEMORY") { |e| + memory = e.text.to_i + } + + # Get CPU (float) + cpu = 0 + vm_doc.root.each_element("TEMPLATE/CPU") { |e| + cpu = e.text.to_f + } + + # Get hostid + hid = -1 + vm_doc.root.each_element("HISTORY_RECORDS/HISTORY[last()]/HID") { |e| + hid = e.text.to_i + } + + counters[:host][hid][:memory] += memory + counters[:host][hid][:cpu] += cpu + counters[:host][hid][:rvms] += 1 + end + + + + ######################################################################## + # Hosts + # + # HOST/HOST_SHARE/MEM_USAGE + # HOST/HOST_SHARE/CPU_USAGE + # HOST/HOST_SHARE/RUNNING_VMS + ######################################################################## + + # Create a new empty table where we will store the new calculated values + @db.run "CREATE TABLE host_pool_new (oid INTEGER PRIMARY KEY, " << + "name VARCHAR(128), body TEXT, state INTEGER, " << + "last_mon_time INTEGER, uid INTEGER, gid INTEGER, " << + "owner_u INTEGER, group_u INTEGER, other_u INTEGER, " << + "UNIQUE(name));" + + # Calculate the host's xml and write them to host_pool_new + @db[:host_pool].each do |row| + host_doc = Document.new(row[:body]) + + hid = row[:oid] + + rvms = counters[:host][hid][:rvms] + cpu_usage = (counters[:host][hid][:cpu]*100).to_i + mem_usage = counters[:host][hid][:memory]*1024 + + # rewrite running_vms + host_doc.root.each_element("HOST_SHARE/RUNNING_VMS") {|e| + if e.text != rvms.to_s + log_error("Host #{hid} RUNNING_VMS has #{e.text} \tis\t#{rvms}") + e.text = rvms + end + } + + # rewrite cpu + host_doc.root.each_element("HOST_SHARE/CPU_USAGE") {|e| + if e.text != cpu_usage.to_s + log_error("Host #{hid} CPU_USAGE has #{e.text} \tis\t#{cpu_usage}") + e.text = cpu_usage + end + } + + # rewrite memory + host_doc.root.each_element("HOST_SHARE/MEM_USAGE") {|e| + if e.text != mem_usage.to_s + log_error("Host #{hid} MEM_USAGE has #{e.text} \tis\t#{mem_usage}") + e.text = mem_usage + end + } + + row[:body] = host_doc.to_s + + # commit + @db[:host_pool_new].insert(row) + end + + # Rename table + @db.run("DROP TABLE host_pool") + @db.run("ALTER TABLE host_pool_new RENAME TO host_pool") + + + ######################################################################## + # Image + # + # IMAGE/RUNNING_VMS + ######################################################################## + + + # Create a new empty table where we will store the new calculated values + @db.run "CREATE TABLE image_pool_new (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid) );" + + # Calculate the host's xml and write them to host_pool_new + @db[:image_pool].each do |row| + doc = Document.new(row[:body]) + + oid = row[:oid] + + rvms = counters[:image][oid][:rvms] + + # rewrite running_vms + doc.root.each_element("RUNNING_VMS") {|e| + if e.text != rvms.to_s + log_error("Image #{oid} RUNNING_VMS has #{e.text} \tis\t#{rvms}") + e.text = rvms + end + } + + row[:body] = doc.to_s + + # commit + @db[:image_pool_new].insert(row) + end + + # Rename table + @db.run("DROP TABLE image_pool") + @db.run("ALTER TABLE image_pool_new RENAME TO image_pool") + + + ######################################################################## + # VNet + # + # LEASES + ######################################################################## + + @db.run "CREATE TABLE leases_new (oid INTEGER, ip BIGINT, body TEXT, PRIMARY KEY(oid,ip));" + + @db[:leases].each do |row| + doc = Document.new(row[:body]) + + used = (doc.root.get_text('USED') == "1") + vid = doc.root.get_text('VID').to_s.to_i + + ip_str = IPAddr.new(row[:ip], Socket::AF_INET).to_s + + vnet_structure = counters[:vnet][row[:oid]] + + ranged = vnet_structure[:type] == 0 + + counter_mac, counter_used, counter_vid = + vnet_structure[:leases][ip_str] + + vnet_structure[:leases].delete(ip_str) + + insert = true + + if used && (vid != -1) # Lease used by a VM + if counter_mac.nil? + log_error("VNet #{row[:oid]} has used lease #{ip_str} (VM #{vid}) \tbut it is free") + + if ranged + insert = false + end + + doc.root.each_element("USED") { |e| + e.text = "0" + } + + doc.root.each_element("VID") {|e| + e.text = "-1" + } + + row[:body] = doc.to_s + + elsif vid != counter_vid + log_error("VNet #{row[:oid]} has used lease #{ip_str} (VM #{vid}) \tbut it used by VM #{counter_vid}") + + doc.root.each_element("VID") {|e| + e.text = counter_vid.to_s + } + + row[:body] = doc.to_s + end + else # Lease is free or on hold (used=1, vid=-1) + if !counter_mac.nil? + if used + log_error("VNet #{row[:oid]} has lease on hold #{ip_str} \tbut it is used by VM #{counter_vid}") + else + log_error("VNet #{row[:oid]} has free lease #{ip_str} \tbut it is used by VM #{counter_vid}") + end + + doc.root.each_element("USED") { |e| + e.text = "1" + } + + doc.root.each_element("VID") {|e| + e.text = counter_vid.to_s + } + + row[:body] = doc.to_s + end + end + + if (doc.root.get_text('USED') == "1") + vnet_structure[:total_leases] += 1 + end + + # commit + @db[:leases_new].insert(row) if insert + end + + # Now insert all the leases left in the hash, i.e. used by a VM in + # vm_pool, but not in the leases table. This will only happen in + # ranged networks + + counters[:vnet].each do |net_id,vnet_structure| + vnet_structure[:leases].each do |ip,array| + mac,used,vid = array + + ip_i = IPAddr.new(ip, Socket::AF_INET).to_i + + # TODO: MAC_PREFIX is now hardcoded to "02:00" + body = "#{ip_i}512#{ip_i}#{used}#{vid}" + + log_error("VNet #{net_id} has free lease #{ip} \tbut it is used by VM #{vid}") + + vnet_structure[:total_leases] += 1 + + @db[:leases_new].insert( + :oid => net_id, + :ip => ip_i, + :body => body) + end + end + + + # Rename table + @db.run("DROP TABLE leases") + @db.run("ALTER TABLE leases_new RENAME TO leases") + + + ######################################################################## + # VNet + # + # VNET/TOTAL_LEASES + ######################################################################## + + # Create a new empty table where we will store the new calculated values + @db.run "CREATE TABLE network_pool_new (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid));" + + @db[:network_pool].each do |row| + doc = Document.new(row[:body]) + + oid = row[:oid] + + total_leases = counters[:vnet][oid][:total_leases] + + # rewrite running_vms + doc.root.each_element("TOTAL_LEASES") {|e| + if e.text != total_leases.to_s + log_error("VNet #{oid} TOTAL_LEASES has #{e.text} \tis\t#{total_leases}") + e.text = total_leases + end + } + + row[:body] = doc.to_s + + # commit + @db[:network_pool_new].insert(row) + end + + # Rename table + @db.run("DROP TABLE network_pool") + @db.run("ALTER TABLE network_pool_new RENAME TO network_pool") + + + ######################################################################## + # Users + # + # USER QUOTAS + ######################################################################## + + @db.run "ALTER TABLE user_pool RENAME TO old_user_pool;" + @db.run "CREATE TABLE user_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name));" + + # oneadmin does not have quotas + @db.fetch("SELECT * FROM old_user_pool WHERE oid=0") do |row| + @db[:user_pool].insert(row) + end + + @db.fetch("SELECT * FROM old_user_pool WHERE oid>0") do |row| + doc = Document.new(row[:body]) + + calculate_quotas(doc, "uid=#{row[:oid]}", "User") + + @db[:user_pool].insert( + :oid => row[:oid], + :name => row[:name], + :body => doc.root.to_s, + :uid => row[:oid], + :gid => row[:gid], + :owner_u => row[:owner_u], + :group_u => row[:group_u], + :other_u => row[:other_u]) + end + + @db.run "DROP TABLE old_user_pool;" + + + ######################################################################## + # Groups + # + # GROUP QUOTAS + ######################################################################## + + @db.run "ALTER TABLE group_pool RENAME TO old_group_pool;" + @db.run "CREATE TABLE group_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name));" + + # oneadmin group does not have quotas + @db.fetch("SELECT * FROM old_group_pool WHERE oid=0") do |row| + @db[:group_pool].insert(row) + end + + @db.fetch("SELECT * FROM old_group_pool WHERE oid>0") do |row| + doc = Document.new(row[:body]) + + calculate_quotas(doc, "gid=#{row[:oid]}", "Group") + + @db[:group_pool].insert( + :oid => row[:oid], + :name => row[:name], + :body => doc.root.to_s, + :uid => row[:oid], + :gid => row[:gid], + :owner_u => row[:owner_u], + :group_u => row[:group_u], + :other_u => row[:other_u]) + end + + @db.run "DROP TABLE old_group_pool;" + + log_total_errors() + + return true + end + + def log_error(message) + @errors += 1 + puts message + end + + def log_total_errors() + puts + puts "Total errors found: #{@errors}" + end + + + + def calculate_quotas(doc, where_filter, resource) + + oid = doc.root.get_text("ID").to_s.to_i + + # VM quotas + cpu_used = 0.0 + mem_used = 0 + vms_used = 0 + + # VNet quotas + vnet_usage = {} + + # Image quotas + img_usage = {} + + @db.fetch("SELECT body FROM vm_pool WHERE #{where_filter} AND state<>6") do |vm_row| + vmdoc = Document.new(vm_row[:body]) + + # VM quotas + vmdoc.root.each_element("TEMPLATE/CPU") { |e| + # truncate to 2 decimals + cpu = (e.text.to_f * 100).to_i / 100.0 + cpu_used += cpu + } + + vmdoc.root.each_element("TEMPLATE/MEMORY") { |e| + mem_used += e.text.to_i + } + + vms_used += 1 + + # VNet quotas + vmdoc.root.each_element("TEMPLATE/NIC/NETWORK_ID") { |e| + vnet_usage[e.text] = 0 if vnet_usage[e.text].nil? + vnet_usage[e.text] += 1 + } + + # Image quotas + vmdoc.root.each_element("TEMPLATE/DISK/IMAGE_ID") { |e| + img_usage[e.text] = 0 if img_usage[e.text].nil? + img_usage[e.text] += 1 + } + end + + + # VM quotas + + vm_elem = nil + doc.root.each_element("VM_QUOTA/VM") { |e| vm_elem = e } + + if vm_elem.nil? + vm_quota = doc.root.add_element("VM_QUOTA") + vm_elem = vm_quota.add_element("VM") + + vm_elem.add_element("CPU").text = "0" + vm_elem.add_element("CPU_USED").text = "0" + + vm_elem.add_element("MEMORY").text = "0" + vm_elem.add_element("MEMORY_USED").text = "0" + + vm_elem.add_element("VMS").text = "0" + vm_elem.add_element("VMS_USED").text = "0" + end + + + vm_elem.each_element("CPU_USED") { |e| + if e.text.to_f != cpu_used + log_error("#{resource} #{oid} CPU_USED has #{e.text} \tis\t#{cpu_used}") + e.text = cpu_used.to_s + end + } + + vm_elem.each_element("MEMORY_USED") { |e| + if e.text.to_i != mem_used + log_error("#{resource} #{oid} MEMORY_USED has #{e.text} \tis\t#{mem_used}") + e.text = mem_used.to_s + end + } + + vm_elem.each_element("VMS_USED") { |e| + if e.text.to_i != vms_used + log_error("#{resource} #{oid} VMS_USED has #{e.text} \tis\t#{vms_used}") + e.text = vms_used.to_s + end + } + + + # VNet quotas + + net_quota = nil + doc.root.each_element("NETWORK_QUOTA") { |e| net_quota = e } + + if net_quota.nil? + net_quota = doc.root.add_element("NETWORK_QUOTA") + end + + net_quota.each_element("NETWORK") { |net_elem| + vnet_id = net_elem.get_text("ID").to_s + + leases_used = vnet_usage.delete(vnet_id) + + leases_used = 0 if leases_used.nil? + + net_elem.each_element("LEASES_USED") { |e| + if e.text.to_i != leases_used + log_error("#{resource} #{oid} VNet #{vnet_id}\tLEASES_USED has #{e.text.to_i} \tis\t#{leases_used}") + e.text = leases_used.to_s + end + } + } + + vnet_usage.each { |vnet_id, leases_used| + log_error("#{resource} #{oid} VNet #{vnet_id}\tLEASES_USED has 0 \tis\t#{leases_used}") + + new_elem = net_quota.add_element("NETWORK") + + new_elem.add_element("ID").text = vnet_id + new_elem.add_element("LEASES").text = "0" + new_elem.add_element("LEASES_USED").text = leases_used.to_s + } + + + # Image quotas + + img_quota = nil + doc.root.each_element("IMAGE_QUOTA") { |e| img_quota = e } + + if img_quota.nil? + img_quota = doc.root.add_element("IMAGE_QUOTA") + end + + img_quota.each_element("IMAGE") { |img_elem| + img_id = img_elem.get_text("ID").to_s + + rvms = img_usage.delete(img_id) + + rvms = 0 if rvms.nil? + + img_elem.each_element("RVMS_USED") { |e| + if e.text.to_i != rvms + log_error("#{resource} #{oid} Image #{img_id}\tRVMS has #{e.text.to_i} \tis\t#{rvms}") + e.text = rvms.to_s + end + } + } + + img_usage.each { |img_id, rvms| + log_error("#{resource} #{oid} Image #{img_id}\tRVMS has 0 \tis\t#{rvms}") + + new_elem = img_quota.add_element("IMAGE") + + new_elem.add_element("ID").text = img_id + new_elem.add_element("RVMS").text = "0" + new_elem.add_element("RVMS_USED").text = rvms.to_s + } + + + # Datastore quotas + + ds_usage = {} + + @db.fetch("SELECT body FROM image_pool WHERE #{where_filter}") do |img_row| + img_doc = Document.new(img_row[:body]) + + img_doc.root.each_element("DATASTORE_ID") { |e| + ds_usage[e.text] = [0,0] if ds_usage[e.text].nil? + ds_usage[e.text][0] += 1 + + img_doc.root.each_element("SIZE") { |size| + ds_usage[e.text][1] += size.text.to_i + } + } + end + + ds_quota = nil + doc.root.each_element("DATASTORE_QUOTA") { |e| ds_quota = e } + + if ds_quota.nil? + ds_quota = doc.root.add_element("DATASTORE_QUOTA") + end + + ds_quota.each_element("DATASTORE") { |ds_elem| + ds_id = ds_elem.get_text("ID").to_s + + images_used,size_used = ds_usage.delete(ds_id) + + images_used = 0 if images_used.nil? + size_used = 0 if size_used.nil? + + ds_elem.each_element("IMAGES_USED") { |e| + if e.text.to_i != images_used + log_error("#{resource} #{oid} Datastore #{ds_id}\tIMAGES_USED has #{e.text.to_i} \tis\t#{images_used}") + e.text = images_used.to_s + end + } + + ds_elem.each_element("SIZE_USED") { |e| + if e.text.to_i != size_used + log_error("#{resource} #{oid} Datastore #{ds_id}\tSIZE_USED has #{e.text.to_i} \tis\t#{size_used}") + e.text = size_used.to_s + end + } + } + + ds_usage.each { |ds_id, array| + images_used,size_used = array + + log_error("#{resource} #{oid} Datastore #{ds_id}\tIMAGES_USED has 0 \tis\t#{images_used}") + log_error("#{resource} #{oid} Datastore #{ds_id}\tSIZE_USED has 0 \tis\t#{size_used}") + + new_elem = ds_quota.add_element("DATASTORE") + + new_elem.add_element("ID").text = ds_id + + new_elem.add_element("IMAGES").text = "0" + new_elem.add_element("IMAGES_USED").text = images_used.to_s + + new_elem.add_element("SIZE").text = "0" + new_elem.add_element("SIZE_USED").text = size_used.to_s + } + end +end