class Bosh::Director::DeploymentPlan::DatabaseIpRepo
Public Class Methods
new(logger)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 7 def initialize(logger) @logger = Bosh::Director::TaggedLogger.new(logger, 'network-configuration') end
Public Instance Methods
add(reservation)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 24 def add(reservation) cidr_ip = CIDRIP.new(reservation.ip) reservation_type = reservation.network.ip_type(cidr_ip) reserve_with_instance_validation( reservation.instance_model, cidr_ip, reservation, reservation_type.eql?(:static) ) reservation.resolve_type(reservation_type) reservation.mark_reserved @logger.debug("Reserved ip '#{cidr_ip}' for #{reservation.network.name} as #{reservation_type}") end
allocate_dynamic_ip(reservation, subnet)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 41 def allocate_dynamic_ip(reservation, subnet) begin ip_address = try_to_allocate_dynamic_ip(reservation, subnet) rescue NoMoreIPsAvailableAndStopRetrying @logger.debug('Failed to allocate dynamic ip: no more available') return nil rescue IpFoundInDatabaseAndCanBeRetried @logger.debug('Retrying to allocate dynamic ip: probably a race condition with another deployment') # IP can be taken by other deployment that runs in parallel # retry until succeeds or out of range retry end @logger.debug("Allocated dynamic IP '#{ip_address.ip}' for #{reservation.network.name}") ip_address.to_i end
delete(ip, _)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 11 def delete(ip, _) cidr_ip = CIDRIP.new(ip) ip_address = Bosh::Director::Models::IpAddress.first(address: cidr_ip.to_i) if ip_address @logger.debug("Releasing ip '#{cidr_ip}'") ip_address.destroy else @logger.debug("Skipping releasing ip '#{cidr_ip}': not reserved") end end
Private Instance Methods
all_ip_addresses()
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 87 def all_ip_addresses Bosh::Director::Models::IpAddress.select(:address).all.map { |a| a.address } end
reserve_with_instance_validation(instance_model, ip, reservation, is_static)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 91 def reserve_with_instance_validation(instance_model, ip, reservation, is_static) # try to save IP first before validating its instance to prevent race conditions save_ip(ip, reservation, is_static) rescue IpFoundInDatabaseAndCanBeRetried ip_address = Bosh::Director::Models::IpAddress.first(address: ip.to_i) retry unless ip_address validate_instance_and_update_reservation_type(instance_model, ip, ip_address, reservation.network.name, is_static) end
save_ip(ip, reservation, is_static)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 120 def save_ip(ip, reservation, is_static) reservation.instance_model.add_ip_address( address: ip.to_i, network_name: reservation.network.name, task_id: Bosh::Director::Config.current_job.task_id, static: is_static ) rescue Sequel::ValidationFailed, Sequel::DatabaseError => e error_message = e.message.downcase if error_message.include?('unique') || error_message.include?('duplicate') raise IpFoundInDatabaseAndCanBeRetried else raise e end end
try_to_allocate_dynamic_ip(reservation, subnet)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 60 def try_to_allocate_dynamic_ip(reservation, subnet) addresses_in_use = Set.new(all_ip_addresses) first_range_address = subnet.range.first(Objectify: true).to_i - 1 addresses_we_cant_allocate = addresses_in_use addresses_we_cant_allocate << first_range_address addresses_we_cant_allocate.merge(subnet.restricted_ips.to_a) unless subnet.restricted_ips.empty? addresses_we_cant_allocate.merge(subnet.static_ips.to_a) unless subnet.static_ips.empty? # find first in-use address whose subsequent address is not in use # the subsequent address must be free addr = addresses_we_cant_allocate .to_a .reject {|a| a < first_range_address } .sort .find { |a| !addresses_we_cant_allocate.include?(a+1) } ip_address = NetAddr::CIDRv4.new(addr+1) unless subnet.range == ip_address || subnet.range.contains?(ip_address) raise NoMoreIPsAvailableAndStopRetrying end save_ip(ip_address, reservation, false) ip_address end
validate_instance_and_update_reservation_type(instance_model, ip, ip_address, network_name, is_static)
click to toggle source
# File lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb, line 102 def validate_instance_and_update_reservation_type(instance_model, ip, ip_address, network_name, is_static) reserved_instance = ip_address.instance if reserved_instance == instance_model if ip_address.static != is_static || ip_address.network_name != network_name reservation_type = is_static ? 'static' : 'dynamic' @logger.debug("Updating reservation for ip '#{ip}' with type '#{reservation_type}' and network '#{network_name}'") ip_address.update(static: is_static, network_name: network_name) end return ip_address else raise Bosh::Director::NetworkReservationAlreadyInUse, "Failed to reserve IP '#{ip}' for instance '#{instance_model}': " + "already reserved by instance '#{reserved_instance.job}/#{reserved_instance.index}' " + "from deployment '#{reserved_instance.deployment.name}'" end end