foreman/app/models/concerns/orchestration/dhcp.rb @ 2fba6ad7
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
|