diff --git a/share/linters/.rubocop.yml b/share/linters/.rubocop.yml index d80f6d3dc81..3d23a268d37 100644 --- a/share/linters/.rubocop.yml +++ b/share/linters/.rubocop.yml @@ -502,7 +502,6 @@ AllCops: - src/onedb/fsck/vrouter.rb - src/onedb/fsck/pool_control.rb - src/onedb/fsck/marketplace.rb - - src/onedb/fsck/network.rb - src/onedb/fsck/template.rb - src/onedb/fsck/group.rb - src/onedb/fsck/cluster.rb diff --git a/src/onedb/fsck/network.rb b/src/onedb/fsck/network.rb index 346c1bf56ae..c98685074d1 100644 --- a/src/onedb/fsck/network.rb +++ b/src/onedb/fsck/network.rb @@ -1,43 +1,24 @@ - +# Network module module OneDBFsck - # Init vnet counters - def init_network_counters - @db.fetch("SELECT oid,body FROM network_pool") do |row| - doc = nokogiri_doc(row[:body]) - - ar_leases = {} - - doc.root.xpath("AR_POOL/AR/AR_ID").each do |ar_id| - ar_leases[ar_id.text.to_i] = {} - end - - counters[:vnet][row[:oid]] = { - :ar_leases => ar_leases, - :no_ar_leases => {} - } - end - end - + # Check that network cluster really exists def check_network_cluster cluster = @data_cluster + @fixes_host_cluster = {} - @db.fetch("SELECT oid,body FROM network_pool") do |row| + @db.fetch('SELECT oid,body FROM network_pool') do |row| doc = nokogiri_doc(row[:body]) - doc.root.xpath("CLUSTERS/ID").each do |e| - cluster_id = e.text.to_i - + doc.root.xpath('CLUSTERS/ID').each do |e| + cluster_id = e.text.to_i cluster_entry = cluster[cluster_id] if cluster_entry.nil? - log_error("VNet #{row[:oid]} is in cluster " << + log_error("VNet #{row[:oid]} is in cluster " \ "#{cluster_id}, but it does not exist") - e.remove - - @fixes_host_cluster[row[:oid]] = { body: doc.root.to_s } + @fixes_host_cluster[row[:oid]] = { :body => doc.root.to_s } else cluster_entry[:vnets] << row[:oid] end @@ -45,440 +26,513 @@ def check_network_cluster end end + # Check network information + def check_network + @fixes_network = {} + + @db[:network_pool].each do |row| + doc = nokogiri_doc(row[:body]) + oid = row[:oid] + + used_leases = doc.root.at_xpath('USED_LEASES').text.to_i + counter_no_ar = counters[:vnet][row[:oid]][:no_ar_leases] + ar_leases = counters[:vnet][row[:oid]][:ar_leases] + + error, new_used_leases = check_ar_leases(oid, + doc, + ar_leases, + counter_no_ar) + + if new_used_leases != used_leases + log_error("VNet #{oid} has #{used_leases} used leases, " \ + "but it is actually #{new_used_leases}") + + error = true + + doc.root.at_xpath('USED_LEASES').content = new_used_leases.to_s + end + + counter_no_ar.each do |_, counter_lease| + log_error("VM #{counter_lease[:vm]} has a lease from " \ + "VNet #{oid}, but it could not be matched " \ + 'to any AR', false) + end + + error = check_vn_mad(doc, oid, error) + + @fixes_network[oid] = doc.root.to_s if error + end + end + + # Fix network cluster def fix_network_cluster @db.transaction do @fixes_host_cluster.each do |id, entry| - @db[:host_pool].where(oid: id).update(body: entry[:body]) + @db.fetch('SELECT cid FROM cluster_network_relation where ' \ + "oid=#{id}") do |row| + doc = nokogiri_doc(entry[:body]) + + doc.root.at_xpath('CLUSTERS/ID').content = row[:cid] + + @data_cluster[row[:cid]][:vnets] << id + + body = doc.root.to_s + + @db[:network_pool].where(:oid => id).update(:body => body) + end end end end + # Fix network errors + def fix_network + @db.transaction do + @fixes_network.each do |id, body| + @db[:network_pool].where(:oid => id).update(:body => body) + end + end + end + + # Init vnet counters + def init_network_counters + @db.fetch('SELECT oid,body FROM network_pool') do |row| + doc = nokogiri_doc(row[:body]) + + ar_leases = {} + + doc.root.xpath('AR_POOL/AR/AR_ID').each do |ar_id| + ar_leases[ar_id.text.to_i] = {} + end + + counters[:vnet][row[:oid]] = { + :ar_leases => ar_leases, + :no_ar_leases => {} + } + end + end + + # Init network leases counters def init_network_lease_counters - @db.fetch("SELECT oid,body,pid FROM network_pool WHERE pid<>-1") do |row| + query = 'SELECT oid,body,pid FROM network_pool WHERE pid<>-1' + + @db.fetch(query) do |row| doc = nokogiri_doc(row[:body]) - parent_vnet = doc.root.at_xpath("PARENT_NETWORK_ID").text.to_i + parent_vnet = doc.root.at_xpath('PARENT_NETWORK_ID').text.to_i - if (row[:pid] != parent_vnet) + if row[:pid] != parent_vnet # TODO end - doc.root.xpath("AR_POOL/AR").each do |ar| - parent_ar_e = ar.at_xpath("PARENT_NETWORK_AR_ID") - if !(parent_ar_e.nil? || parent_ar_e.text == "") + doc.root.xpath('AR_POOL/AR').each do |ar| + parent_ar_e = ar.at_xpath('PARENT_NETWORK_AR_ID') - parent_ar = parent_ar_e.text.to_i + next if parent_ar_e.nil? || parent_ar_e.text.empty? - if counters[:vnet][parent_vnet][:ar_leases][parent_ar].nil? - log_error( - "VNet #{row[:oid]} is using parent "<< - "VNet #{parent_vnet}, AR #{parent_ar}, "<< - "but the AR does not exist", false) - end + parent_ar = parent_ar_e.text.to_i - # MAC - first_mac = mac_s_to_i(ar.at_xpath("MAC").text) + if counters[:vnet][parent_vnet][:ar_leases][parent_ar].nil? + log_error("VNet #{row[:oid]} is using parent " \ + "VNet #{parent_vnet}, AR #{parent_ar}, " \ + 'but the AR does not exist', false) + end - # IP - first_ip = nil - if (!ar.at_xpath("IP").nil?) - first_ip = IPAddr.new(ar.at_xpath("IP").text.strip, Socket::AF_INET) - end + # MAC + first_mac = mac_s_to_i(ar.at_xpath('MAC').text) - # IP6 - global_prefix = nil - if !ar.at_xpath("GLOBAL_PREFIX").nil? - global_prefix = ip6_prefix_s_to_i( - ar.at_xpath("GLOBAL_PREFIX").text) - end + # IP + unless ar.at_xpath('IP').nil? + first_ip = IPAddr.new(ar.at_xpath('IP').text.strip, + Socket::AF_INET) + end - ula_prefix = nil - if !ar.at_xpath("ULA_PREFIX").nil? - ula_prefix = ip6_prefix_s_to_i( - ar.at_xpath("ULA_PREFIX").text) - end + # IP6 + ipv6 = get_ipv6(ar) - link_prefix = nil - type = ar.at_xpath("TYPE").text - if ( type == "IP6" || type == "IP4_6" ) - link_prefix = 0xfe80000000000000 - end + addrs = { :mac => first_mac, :ip => first_ip, :ipv6 => ipv6 } - # Parent vnet has a lease for each address of this reservation - ar.at_xpath("SIZE").text.to_i.times do |index| - - lease = { - :ip => nil, - :ip6_global => nil, - :ip6_link => nil, - :ip6_ula => nil, - :mac => nil, - :vm => nil, - :vnet => row[:oid], - :vrouter => nil - } - - #MAC - mac = (first_mac & 0xFFFF00000000) + - (((first_mac & 0xFFFFFFFF) + index) % 0x100000000) - lease[:mac] = mac_i_to_s(mac) - - # IP - if (!first_ip.nil?) - lease[:ip] = IPAddr.new(first_ip.to_i + index, - Socket::AF_INET).to_s - end - - # IP6 - ip6_suffix = mac_to_ip6_suffix(mac) - - if (!global_prefix.nil?) - lease[:ip6_global] = IPAddr.new( - (global_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end - - if (!ula_prefix.nil?) - lease[:ip6_ula] = IPAddr.new( - (ula_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end - - if (!link_prefix.nil?) - lease[:ip6_link] = IPAddr.new( - (link_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end - - counters[:vnet][parent_vnet][ - :ar_leases][parent_ar][mac] = lease - end - end + # Parent vnet has a lease for each address of this reservation + calculate_leases(ar, row[:oid], addrs. parent_vnet, parent_ar) end end end - def check_network - @fixes_network = {} + # Get lease information + # + # @param oid [Integer] VNet ID + # @param mac [String] VNet mac address + # @param ip [String] VNet IPv4 address + # @param ipv6 [Object] VNet IPv6 object with all information about v6 + # @param index [Integer] Index of the lease to calculate the mac and IP + # + # @return [Object] Object with lease information + def get_lease(oid, mac, ip, ipv6, index) + lease = { + :ip => nil, + :ip6_global => nil, + :ip6_link => nil, + :ip6_ula => nil, + :mac => nil, + :mac_index => nil, + :vm => nil, + :vnet => oid, + :vrouter => nil + } + + # MAC + mac = (mac & 0xFFFF00000000) + + (((mac & 0xFFFFFFFF) + index) % + 0x100000000) + + lease[:mac] = mac_i_to_s(mac) + lease[:mac_index] = mac + + # IP + unless ip.nil? + lease[:ip] = IPAddr.new(ip.to_i + index, Socket::AF_INET).to_s + end - @db[:network_pool].each do |row| - doc = nokogiri_doc(row[:body]) - oid = row[:oid] + # IP6 + ip6_suffix = mac_to_ip6_suffix(mac) - used_leases = doc.root.at_xpath("USED_LEASES").text.to_i - new_used_leases = 0 + g_pref = ipv6[:global_prefix] + u_pref = ipv6[:ula_prefix] + l_pref = ipv6[:linked_prefix] - counter_no_ar = counters[:vnet][row[:oid]][:no_ar_leases] + unless g_pref.nil? + pref = (g_pref << 64) | ip6_suffix + lease[:ip6_global] = IPAddr.new(pref, Socket::AF_INET6).to_s + end - error = false - counters[:vnet][row[:oid]][:ar_leases].each do |ar_id, counter_ar| - net_ar = doc.root.at_xpath("AR_POOL/AR[AR_ID=#{ar_id}]") + unless u_pref.nil? + pref = (u_pref << 64) | ip6_suffix + lease[:ip6_ula] = IPAddr.new(pref, Socket::AF_INET6).to_s + end - if (net_ar.nil?) - # TODO shouldn't happen? - end + unless l_pref.nil? + pref = (l_pref << 64) | ip6_suffix + lease[:ip6_link] = IPAddr.new(pref, Socket::AF_INET6).to_s + end - # MAC - first_mac = mac_s_to_i(net_ar.at_xpath("MAC").text) + lease + end - # IP - first_ip = nil - if !net_ar.at_xpath("IP").nil? - first_ip_st = net_ar.at_xpath("IP").text + # Calculate ar leases + # + # @param ar [XML] Address range information + # @param oid [Interger] VNet ID + # @param addrs [Object] Object with mac, IP and IPv6 addresses + # @param p_vnet [String] Parent VNet + # @param p_ar [String] Parent address range + def calculate_leases(address_range, oid, addrs, p_vnet, p_ar) + address_range.at_xpath('SIZE').text.to_i.times do |index| + lease = get_lease(oid, addrs[:mac], addrs[:ip], addrs[:ipv6], index) + + counters[:vnet][p_vnet][:ar_leases][p_ar][mac] = lease + end + end - if (first_ip_st != first_ip_st.strip) - log_error("VNet #{oid} AR #{ar_id} "<< - "IP \"#{first_ip_st}\" contains whitespaces") - error = true + # Get IPv6 information + # + # @param address_range [XML element] Address range information + # + # @return [Object] Object with IPv6 information + def get_ipv6(address_range) + ipv6 = { :global_prefix => nil, + :ula_prefix => nil, + :link_prefix => nil } + + unless address_range.at_xpath('GLOBAL_PREFIX').nil? + g_prefix = address_range.at_xpath('GLOBAL_PREFIX').text + ipv6[:global_prefix] = ip6_prefix_s_to_i(g_prefix) + end - first_ip_st.strip! + unless address_range.at_xpath('ULA_PREFIX').nil? + u_prefix = address_range.at_xpath('ULA_PREFIX').text + ipv6[:ula_prefix] = ip6_prefix_s_to_i(u_prefix) + end - net_ar.at_xpath("IP").content = first_ip_st - end + type = address_range.at_xpath('TYPE').text - first_ip = IPAddr.new(first_ip_st, Socket::AF_INET) - end + if %w[IP6 IP4_6].include? type + ipv6[:link_prefix] = 0xfe80000000000000 + end - # IP6 - global_prefix = nil - if !net_ar.at_xpath("GLOBAL_PREFIX").nil? - global_prefix = ip6_prefix_s_to_i( - net_ar.at_xpath("GLOBAL_PREFIX").text) - end + ipv6 + end - ula_prefix = nil - if !net_ar.at_xpath("ULA_PREFIX").nil? - ula_prefix = ip6_prefix_s_to_i( - net_ar.at_xpath("ULA_PREFIX").text) - end + # Check that the IP address is valid + # + # @param oid [Integer] VNet ID + # @param ar_id [Integer] Address range ID + # @param ip [String] IP address + # @param net_ar [XML element] Address range information + # @param error [Boolean] True if there was an error, false if not + # + # @return [Boolean/IP] The current value of error and the fixed IP + def check_ip(oid, ar_id, ip, net_ar, error) + if ip != ip.strip + log_error("VNet #{oid} AR #{ar_id} " \ + "IP \"#{ip}\" contains whitespaces") + + error = true + + ip.strip! + + net_ar.at_xpath('IP').content = ip + end - link_prefix = nil - type = net_ar.at_xpath("TYPE").text - if ( type == "IP6" || type == "IP4_6" ) - link_prefix = 0xfe80000000000000 - end + [error, IPAddr.new(ip, Socket::AF_INET)] + end - # Allocated leases - allocated_e = net_ar.at_xpath("ALLOCATED") + # Check VNet VN_MAD + # + # @param doc [XML element] XML document with all the information + # @param oid [Integer] VNet ID + # @param error [Boolean] True if there was an error, false if not + # + # @return [Booleam] The current value of error + def check_vn_mad(doc, oid, error) + vn_mad_e = doc.root.at_xpath('VN_MAD') + + if vn_mad_e.nil? + log_error("VNet #{oid} VN_MAD element is missing", false) + else + vn_mad = vn_mad_e.text + vn_mad_tmpl_e = doc.root.at_xpath('TEMPLATE/VN_MAD') + + if vn_mad_tmpl_e.nil? || vn_mad_tmpl_e.text != vn_mad + log_error("VNet #{oid} VN_MAD element is missing " \ + 'from the TEMPLATE') - allocated = allocated_e.nil? ? "" : allocated_e.text + error = true - leases = allocated.scan(/(\d+) (\d+)/) + doc.root.at_xpath('TEMPLATE') + .add_child(doc.create_element('VN_MAD')).content = vn_mad + end + end - size = net_ar.at_xpath("SIZE").text.to_i + error + end - if leases.length > size - log_error("VNet #{oid} AR #{ar_id} allocated leases "\ - "(#{leases.length}) is greater than the AR size (#{size}"\ - "). SIZE can be increased with onevnet updatear"\ - " #{oid} #{ar_id}") + # Check ar leases + # + # @param oid [Integer] VNet ID + # @param doc [XML element] XML document with all the information + # @param ar_leasses [Array] Address range leases to check + # @param counter_no_ar [Array] Counters for no address range info + # + # @return [Boolean/Interger] error if any, number leases used + def check_ar_leases(oid, doc, ar_leases, counter_no_ar) + new_used_leases = 0 + error = false + + ar_leases.each do |ar_id, counter_ar| + net_ar = doc.root.at_xpath("AR_POOL/AR[AR_ID=#{ar_id}]") + + if net_ar.nil? + # TODO: shouldn't happen? + end - error = true - net_ar.at_xpath("SIZE").content = leases.length.to_s - end + # MAC + first_mac = mac_s_to_i(net_ar.at_xpath('MAC').text) - new_leases = [] - - leases.each do |lease_str| - index = lease_str[0].to_i - binary_magic = lease_str[1].to_i - - lease = { - :ip => nil, - :ip6_global => nil, - :ip6_link => nil, - :ip6_ula => nil, - :mac => nil, - :vm => nil, - :vnet => nil, - :vrouter => nil - } - - # MAC - mac = (first_mac & 0xFFFF00000000) + - (((first_mac & 0xFFFFFFFF) + index) % 0x100000000) - - lease[:mac] = mac_i_to_s(mac) - - # IP - if (!first_ip.nil?) - lease[:ip] = IPAddr.new(first_ip.to_i + index, - Socket::AF_INET).to_s - end + # IP + unless net_ar.at_xpath('IP').nil? + ip = net_ar.at_xpath('IP').text + error, first_ip = check_ip(oid, ar_id, ip, net_ar, error) + end - # IP6 - ip6_suffix = mac_to_ip6_suffix(mac) + # IP6 + ipv6 = get_ipv6(net_ar) - if (!global_prefix.nil?) - lease[:ip6_global] = IPAddr.new( - (global_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end + # Allocated leases + allocated_e = net_ar.at_xpath('ALLOCATED') - if (!ula_prefix.nil?) - lease[:ip6_ula] = IPAddr.new( - (ula_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end + allocated_e.nil? ? allocated = '' : allocated = allocated_e.text - if (!link_prefix.nil?) - lease[:ip6_link] = IPAddr.new( - (link_prefix << 64) | ip6_suffix, - Socket::AF_INET6 ).to_s - end + leases = allocated.scan(/(\d+) (\d+)/) - # OID - lease_oid = binary_magic & 0x00000000FFFFFFFF - lease_obj = "" - - if (binary_magic & VM_BIN != 0) - lease[:vm] = lease_oid - lease_obj = "VM" - elsif (binary_magic & NET_BIN != 0) - lease[:vnet] = lease_oid - lease_obj = "VNet" - else #(binary_magic & VROUTER_BIN != 0) - lease[:vrouter] = lease_oid - lease_obj = "VRouter" - end + size = net_ar.at_xpath('SIZE').text.to_i - counter_lease = counter_ar[mac] - counter_ar.delete(mac) + if leases.length > size + log_error("VNet #{oid} AR #{ar_id} allocated leases " \ + "(#{leases.length}) is greater than the " \ + "AR size (#{size}). SIZE can be increased " \ + "with onevnet updatear #{oid} #{ar_id}") - if counter_lease.nil? - counter_lease = counter_no_ar[mac] - counter_no_ar.delete(mac) - end - - if counter_lease.nil? - if(lease[:vm] != HOLD) - log_error( - "VNet #{oid} AR #{ar_id} has leased #{lease_to_s(lease)} "<< - "to #{lease_obj} #{lease_oid}, but it is actually free") + error = true - error = true - else - new_leases << lease_str - end - else - if counter_lease != lease - - # Things that can be fixed - if (counter_lease[:vm] != lease[:vm] || - counter_lease[:vnet] != lease[:vnet] || - counter_lease[:vrouter] != lease[:vrouter]) - - new_lease_obj = "" - new_lease_oid = 0 - new_binary_magic = 0 - - if !counter_lease[:vm].nil? - new_lease_obj = "VM" - new_lease_oid = counter_lease[:vm].to_i - - new_binary_magic = (VM_BIN | - (new_lease_oid & 0xFFFFFFFF)) - elsif !counter_lease[:vnet].nil? - new_lease_obj = "VNet" - new_lease_oid = counter_lease[:vnet].to_i - - new_binary_magic = (NET_BIN | - (new_lease_oid & 0xFFFFFFFF)) - else #if !counter_lease[:vrouter].nil? - new_lease_obj = "VRouter" - new_lease_oid = counter_lease[:vrouter].to_i - - new_binary_magic = (VROUTER_BIN | - (new_lease_oid & 0xFFFFFFFF)) - end - - if (lease[:vm] == HOLD) - log_error( - "VNet #{oid} AR #{ar_id} has lease "<< - "#{lease_to_s(lease)} on hold, but it is "<< - "actually used by "<< - "#{new_lease_obj} #{new_lease_oid}") - error = true - else - log_error( - "VNet #{oid} AR #{ar_id} has leased #{lease_to_s(lease)} "<< - "to #{lease_obj} #{lease_oid}, but it is "<< - "actually used by "<< - "#{new_lease_obj} #{new_lease_oid}") - error = true - end - - lease_str[1] = new_binary_magic.to_s - end - - # Things that can't be fixed - - [:ip, :ip6_global, :ip6_link, :ip6_ula].each do |key| - if (counter_lease[key] != lease[key]) - log_error( - "VNet #{oid} AR #{ar_id} has a wrong "<< - "lease for "<< - "#{lease_obj} #{lease_oid}. #{key.to_s.upcase} "<< - "does not match: "<< - "#{counter_lease[key]} != #{lease[key]}. "<< - "This can't be fixed", false) - end - end - end - - new_leases << lease_str - end - end + net_ar.at_xpath('SIZE').content = leases.length.to_s + end - counter_ar.each do |mac, counter_lease| - next if mac.nil? + ids = { :o => oid, :ar => ar_id } + addrs = { :mac => first_mac, :ip => first_ip, :ipv6 => ipv6 } + counters = { :ar => counter_ar, :no_ar => counter_no_ar } - index = ((mac & 0xFFFFFFFF) - (first_mac & 0xFFFFFFFF) ) % 0x100000000 + error, new_leases = calculate_new_leases(leases, + ids, + addrs, + counters, + error) - new_lease_obj = "" - new_lease_oid = 0 - new_binary_magic = 0 + counter_ar.each do |mac, counter_lease| + next if mac.nil? - if !counter_lease[:vm].nil? - new_lease_obj = "VM" - new_lease_oid = counter_lease[:vm].to_i + index = ((mac & 0xFFFFFFFF) - + (first_mac & 0xFFFFFFFF)) % + 0x100000000 - new_binary_magic = (VM_BIN | - (new_lease_oid & 0xFFFFFFFF)) - elsif !counter_lease[:vnet].nil? - new_lease_obj = "VNet" - new_lease_oid = counter_lease[:vnet].to_i + parameters = fix_parameters(counter_lease) - new_binary_magic = (NET_BIN | - (new_lease_oid & 0xFFFFFFFF)) - else #if !counter_lease[:vrouter].nil? - new_lease_obj = "VRouter" - new_lease_oid = counter_lease[:vrouter].to_i + log_error("VNet #{oid} AR #{ar_id} does not have a lease " \ + "for #{mac_i_to_s(mac)}, but it is in use by " \ + "#{parameters[:new_lease_obj]} " \ + "#{parameters[:new_lease_oid]}") - new_binary_magic = (VROUTER_BIN | - (new_lease_oid & 0xFFFFFFFF)) - end + error = true - log_error("VNet #{oid} AR #{ar_id} does not have a lease "<< - "for #{mac_i_to_s(mac)}, but it is in use by "<< - "#{new_lease_obj} #{new_lease_oid}") + new_leases << [index.to_s, parameters[:new_binary_magic].to_s] + end - error = true + new_used_leases += new_leases.size - new_leases << [index.to_s, new_binary_magic.to_s] - end + allocated_e.remove if allocated_e - new_used_leases += new_leases.size + unless new_leases.empty? + add_cdata(net_ar, 'ALLOCATED', " #{new_leases.join(' ')}") + end + end - allocated_e.remove if allocated_e + [error, new_used_leases] + end - if new_leases.size > 0 - add_cdata(net_ar, "ALLOCATED", " #{new_leases.join(" ")}") - end - end + # Fix paramters of the lease + # + # @param counter_lease [Object] Counters of the lease + # + # @return [Object] Object with new lease parameters + def fix_parameters(counter_lease) + params = { :new_lease_obj => '', + :new_lease_oid => 0, + :new_binary_magic => 0 } + + if !counter_lease[:vm].nil? + new_lease_obj = 'VM' + new_lease_oid = counter_lease[:vm].to_i + new_binary_magic = (VM_BIN | (new_lease_oid & 0xFFFFFFFF)) + elsif !counter_lease[:vnet].nil? + new_lease_obj = 'VNet' + new_lease_oid = counter_lease[:vnet].to_i + new_binary_magic = (NET_BIN | (new_lease_oid & 0xFFFFFFFF)) + else + new_lease_obj = 'VRouter' + new_lease_oid = counter_lease[:vrouter].to_i + new_binary_magic = (VROUTER_BIN | (new_lease_oid & 0xFFFFFFFF)) + end - if (new_used_leases != used_leases) - log_error("VNet #{oid} has #{used_leases} used leases, "<< - "but it is actually #{new_used_leases}") + params[:new_lease_obj] = new_lease_obj + params[:new_lease_oid] = new_lease_oid + params[:new_binary_magic] = new_binary_magic - error = true + params + end - doc.root.at_xpath("USED_LEASES").content = - new_used_leases.to_s + # Calculate new leases information + # + # @param leases [Array] Array with address range leases + # @param ids [Object] Object with VNet ID and AR ID + # @param addrs [Object] Object with mac, IP and IPv6 addresses + # @param counters [Object] Object with ar and no_ar counters + # @param error [Boolean] True if there was an error, false if not + # + # @return [Boolean/Leases] The current value of error and new leases + def calculate_new_leases(leases, ids, addrs, counters, error) + new_leases = [] + + leases.each do |lease_str| + index = lease_str[0].to_i + binary_magic = lease_str[1].to_i + + lease = get_lease(nil, addrs[:mac], addrs[:ip], addrs[:ipv6], index) + + # OID + lease_oid = binary_magic & 0x00000000FFFFFFFF + lease_obj = '' + + if binary_magic & VM_BIN != 0 + lease[:vm] = lease_oid + lease_obj = 'VM' + elsif binary_magic & NET_BIN != 0 + lease[:vnet] = lease_oid + lease_obj = 'VNet' + else + lease[:vrouter] = lease_oid + lease_obj = 'VRouter' end - counter_no_ar.each do |mac, counter_lease| - log_error("VM #{counter_lease[:vm]} has a lease from "<< - "VNet #{oid}, but it could not be matched to any AR", false) + counter_lease = counters[:ar][lease[:mac_index]] + counters[:ar].delete(lease[:mac_index]) + + if counter_lease.nil? + counter_lease = counters[:no_ar][lease[:mac_index]] + counters[:no_ar].delete(lease[:mac_index]) end - vn_mad_e = doc.root.at_xpath("VN_MAD") - if vn_mad_e.nil? - log_error("VNet #{oid} VN_MAD element is missing", false) + if counter_lease.nil? + if lease[:vm] != HOLD + log_error("VNet #{ids[:o]} AR #{ids[:ar]} has " \ + "leased #{lease_to_s(lease)} to #{lease_obj} " \ + "#{lease_oid}, but it is actually free") + + error = true + else + new_leases << lease_str + end else - vn_mad = vn_mad_e.text - vn_mad_tmpl_e = doc.root.at_xpath("TEMPLATE/VN_MAD") + new_leases << lease_str - if (vn_mad_tmpl_e.nil? || vn_mad_tmpl_e.text != vn_mad) - log_error("VNet #{oid} VN_MAD element is missing from the TEMPLATE") + next if counter_lease == lease - error = true + # Things that can be fixed + if counter_lease[:vm] != lease[:vm] || + counter_lease[:vnet] != lease[:vnet] || + counter_lease[:vrouter] != lease[:vrouter] - doc.root.at_xpath("TEMPLATE").add_child( - doc.create_element("VN_MAD")).content = vn_mad + parameters = fix_parameters(counter_lease) + + if lease[:vm] == HOLD + log_error("VNet #{ids[:o]} AR #{ids[:ar]} has lease " \ + "#{lease_to_s(lease)} on hold, but it is " \ + 'actually used by ' \ + "#{parameters[:new_lease_obj]} " \ + "#{parameters[:new_lease_oid]}") + else + log_error("VNet #{ids[:o]} AR #{ids[:ar]} has leased " \ + "#{lease_to_s(lease)} to #{lease_obj} " \ + "#{lease_oid}, but it is actually used by " \ + "#{parameters[:new_lease_obj]} " \ + "#{parameters[:new_lease_oid]}") + end + + error = true + lease_str[1] = parameters[:new_binary_magic].to_s end - end - @fixes_network[oid] = doc.root.to_s if error - end - end + # Things that can't be fixed + %i[ip ip6_global ip6_link ip6_ula].each do |key| + next if counter_lease[key] == lease[key] - def fix_network - @db.transaction do - @fixes_network.each do |id, body| - @db[:network_pool].where(oid: id).update(body: body) + log_error("VNet #{ids[:o]} AR #{ids[:ar]} has a wrong " \ + "lease for #{lease_obj} #{lease_oid}. " \ + "#{key.to_s.upcase} does not match: " \ + "#{counter_lease[key]} != #{lease[key]}. " \ + 'This can\'t be fixed', false) + end end + + return error, new_leases end end -end +end