Project

General

Profile

Download (5.83 KB) Statistics
| Branch: | Tag: | Revision:
90b83222 Ohad Levy
module Orchestration::DHCP
dc457681 Joseph Mitchell Magen
extend ActiveSupport::Concern
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
included do
90ff2a3a Dmitri Dolguikh
after_validation :dhcp_conflict_detected?, :queue_dhcp
dc457681 Joseph Mitchell Magen
before_destroy :queue_dhcp_destroy
validate :ip_belongs_to_subnet?
2fba6ad7 Ondrej Prazak
register_rebuild(:rebuild_dhcp, N_('DHCP'))
dc457681 Joseph Mitchell Magen
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def dhcp?
5440d482 Greg Sutcliffe
# host.managed? and managed? should always come first so that orchestration doesn't
# even get tested for such objects
93dbb7e7 Ori Rabin
(host.nil? || host.managed?) && managed? && hostname.present? && ip_available? && mac_available? &&
!subnet.nil? && subnet.dhcp? && SETTINGS[:unattended] && (!provision? || operatingsystem.present?)
dc457681 Joseph Mitchell Magen
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def dhcp_record
return unless dhcp? or @dhcp_record
e60f0799 Dominic Cleal
@dhcp_record ||= (provision? && jumpstart?) ? Net::DHCP::SparcRecord.new(dhcp_attrs) : Net::DHCP::Record.new(dhcp_attrs)
dc457681 Joseph Mitchell Magen
end
90b83222 Ohad Levy
2fba6ad7 Ondrej Prazak
def rebuild_dhcp
if dhcp?
del_dhcp_safe
begin
set_dhcp
rescue => e
Foreman::Logging.exception "Failed to rebuild DHCP record for #{name}, #{ip}", e, :level => :error
false
end
else
logger.info "DHCP not supported for #{name}, #{ip}, skipping orchestration rebuild"
true
end
end

dc457681 Joseph Mitchell Magen
protected
a6f4f5f7 Ohad Levy
2fba6ad7 Ondrej Prazak
def del_dhcp_safe
if dhcp_record
begin
del_dhcp
rescue => e
Foreman::Logging.exception "Proxy failed to delete DHCP record for #{name}, #{ip}", e, :level => :error
end
end
end

dc457681 Joseph Mitchell Magen
def set_dhcp
dhcp_record.create
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def set_dhcp_conflicts
dhcp_record.conflicts.each{|conflict| conflict.create}
end
30ae12bf Ohad Levy
dc457681 Joseph Mitchell Magen
def del_dhcp
dhcp_record.destroy
end
672f931d Paul Kelly
dc457681 Joseph Mitchell Magen
def del_dhcp_conflicts
dhcp_record.conflicts.each{|conflict| conflict.destroy}
end
30ae12bf Ohad Levy
dc457681 Joseph Mitchell Magen
# where are we booting from
def boot_server
# if we don't manage tftp at all, we dont create a next-server entry.
return unless tftp?

# first try to ask our TFTP server for its boot server
bs = tftp.bootServer
# if that failed, trying to guess out tftp next server based on the smart proxy hostname
bs ||= URI.parse(subnet.tftp.url).host
# now convert it into an ip address (see http://theforeman.org/issues/show/1381)
c83e29ac Lukas Zapletal
ip = to_ip_address(bs) if bs.present?
return ip unless ip.nil?
dc457681 Joseph Mitchell Magen
failure _("Unable to determine the host's boot server. The DHCP smart proxy failed to provide this information and this subnet is not provided with TFTP services.")
rescue => e
01e78260 Ivan Nečas
failure _("failed to detect boot server: %s") % e, e
dc457681 Joseph Mitchell Magen
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
private
8838eb42 Ohad Levy
dc457681 Joseph Mitchell Magen
# returns a hash of dhcp record settings
def dhcp_attrs
e60f0799 Dominic Cleal
raise ::Foreman::Exception.new(N_("DHCP not supported for this NIC")) unless dhcp?
dhcp_attr = {
:name => name,
:hostname => hostname,
:ip => ip,
:mac => mac,
:proxy => subnet.dhcp_proxy,
:network => subnet.network,
}

if provision?
dhcp_attr.merge!({:filename => operatingsystem.boot_filename(self), :nextServer => boot_server})
if jumpstart?
jumpstart_arguments = os.jumpstart_params self, model.vendor_class
dhcp_attr.merge! jumpstart_arguments unless jumpstart_arguments.empty?
end
8838eb42 Ohad Levy
end
e60f0799 Dominic Cleal
dc457681 Joseph Mitchell Magen
dhcp_attr
end
8838eb42 Ohad Levy
dc457681 Joseph Mitchell Magen
def queue_dhcp
return unless (dhcp? or (old and old.dhcp?)) and orchestration_errors?
90ff2a3a Dmitri Dolguikh
queue_remove_dhcp_conflicts
dc457681 Joseph Mitchell Magen
new_record? ? queue_dhcp_create : queue_dhcp_update
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def queue_dhcp_create
logger.debug "Scheduling new DHCP reservations for #{self}"
queue.create(:name => _("Create DHCP Settings for %s") % self, :priority => 10,
:action => [self, :set_dhcp]) if dhcp?
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def queue_dhcp_update
if dhcp_update_required?
logger.debug("Detected a changed required for DHCP record")
queue.create(:name => _("Remove DHCP Settings for %s") % old, :priority => 5,
:action => [old, :del_dhcp]) if old.dhcp?
queue.create(:name => _("Create DHCP Settings for %s") % self, :priority => 9,
:action => [self, :set_dhcp]) if dhcp?
a6f4f5f7 Ohad Levy
end
dc457681 Joseph Mitchell Magen
end
a6f4f5f7 Ohad Levy
dc457681 Joseph Mitchell Magen
# do we need to update our dhcp reservations
def dhcp_update_required?
87c6feb2 Baptiste AGASSE
# IP Address / name changed, or 'rebuild' action is triggered and DHCP record on the smart proxy is not present/identical.
return true if ((old.ip != ip) or (old.hostname != hostname) or (old.mac != mac) or (old.subnet != subnet) or
(!old.build? and build? and !dhcp_record.valid?))
dc457681 Joseph Mitchell Magen
# Handle jumpstart
#TODO, abstract this way once interfaces are fully used
cd032085 Daniel Lobato
if self.is_a?(Host::Base) and jumpstart?
dc457681 Joseph Mitchell Magen
if !old.build? or (old.medium != medium or old.arch != arch) or
(os and old.os and (old.os.name != os.name or old.os != os))
afe02d30 Daniel Lobato
return true
672f931d Paul Kelly
end
a6f4f5f7 Ohad Levy
end
dc457681 Joseph Mitchell Magen
false
end
a6f4f5f7 Ohad Levy
dc457681 Joseph Mitchell Magen
def queue_dhcp_destroy
return unless dhcp? and errors.empty?
queue.create(:name => _("Remove DHCP Settings for %s") % self, :priority => 5,
:action => [self, :del_dhcp])
true
end
90b83222 Ohad Levy
dc457681 Joseph Mitchell Magen
def queue_remove_dhcp_conflicts
90ff2a3a Dmitri Dolguikh
return unless (dhcp? and overwrite?)
dc457681 Joseph Mitchell Magen
logger.debug "Scheduling DHCP conflicts removal"
queue.create(:name => _("DHCP conflicts removal for %s") % self, :priority => 5,
:action => [self, :del_dhcp_conflicts]) if dhcp_record and dhcp_record.conflicting?
end
30ae12bf Ohad Levy
dc457681 Joseph Mitchell Magen
def ip_belongs_to_subnet?
return if subnet.nil? or ip.nil?
return unless dhcp?
unless subnet.contains? ip
fb69591a Lukas Zapletal
errors.add(:ip, _("does not match selected subnet"))
dc457681 Joseph Mitchell Magen
return false
90b83222 Ohad Levy
end
dc457681 Joseph Mitchell Magen
rescue
# probably an invalid ip / subnet were entered
# we let other validations handle that
end
a6f4f5f7 Ohad Levy
dc457681 Joseph Mitchell Magen
def dhcp_conflict_detected?
# we can't do any dhcp based validations when our MAC address is defined afterwards (e.g. in vm creation)
21e07e92 Trey Dockendorf
return false if mac.blank? or hostname.blank?
dc457681 Joseph Mitchell Magen
return false unless dhcp?
90ff2a3a Dmitri Dolguikh
if dhcp_record and dhcp_record.conflicting? and (not overwrite?)
failure(_("DHCP records %s already exists") % dhcp_record.conflicts.to_sentence, nil, :conflict)
return true
end
false
90b83222 Ohad Levy
end
end