|
module Orchestration::DNS
|
|
extend ActiveSupport::Concern
|
|
include Orchestration::Common
|
|
|
|
included do
|
|
after_validation :dns_conflict_detected?, :unless => :skip_orchestration?
|
|
after_validation :queue_dns
|
|
before_destroy :queue_dns_destroy
|
|
register_rebuild(:rebuild_dns, N_('DNS'))
|
|
end
|
|
|
|
def dns_ready?
|
|
# host.managed? and managed? should always come first so that orchestration doesn't
|
|
# even get tested for such objects
|
|
SETTINGS[:unattended] && (host.nil? || host.managed?) && managed? && hostname.present?
|
|
end
|
|
|
|
def dns?
|
|
dns_ready? && ip_available? && domain.present? && domain.proxy.present?
|
|
end
|
|
|
|
def dns6?
|
|
dns_ready? && ip6_available? && domain.present? && domain.proxy.present?
|
|
end
|
|
|
|
def reverse_dns?
|
|
dns_ready? && ip_available? && subnet.present? && subnet.dns?
|
|
end
|
|
|
|
def reverse_dns6?
|
|
dns_ready? && ip6_available? && subnet6.present? && subnet6.dns?
|
|
end
|
|
|
|
def rebuild_dns
|
|
feasible = {}
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
feasible[record_type] = dns_feasible?(record_type)
|
|
logger.info "DNS record type #{record_type} not supported for #{name}, skipping orchestration rebuild" unless feasible[record_type]
|
|
end
|
|
return true unless feasible.any?
|
|
|
|
results = {}
|
|
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
del_dns_record_safe(record_type)
|
|
|
|
begin
|
|
results[record_type] = dns_feasible?(record_type) ? recreate_dns_record(record_type) : true
|
|
rescue => e
|
|
Foreman::Logging.exception "Failed to rebuild DNS record for #{name}(#{ip}/#{ip6})", e, :level => :error
|
|
return false
|
|
end
|
|
end
|
|
results.values.all?
|
|
end
|
|
|
|
def queue_dns
|
|
return log_orchestration_errors unless (dns? || dns6? || reverse_dns? || reverse_dns6?) && errors.empty?
|
|
queue_remove_dns_conflicts if overwrite?
|
|
new_record? ? queue_dns_create : queue_dns_update
|
|
end
|
|
|
|
def queue_dns_create
|
|
logger.debug "Scheduling new DNS entries"
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
if dns_feasible?(record_type)
|
|
queue.create(:name => _("Create %{type} for %{host}") % {:host => self, :type => dns_class(record_type).human}, :priority => 10,
|
|
:action => [self, :set_dns_record, record_type])
|
|
end
|
|
end
|
|
end
|
|
|
|
def queue_dns_update
|
|
return unless pending_dns_record_changes?
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
if old.dns_feasible?(record_type)
|
|
queue.create(:name => _("Remove %{type} for %{host}") % {:host => old, :type => dns_class(record_type).human }, :priority => 9,
|
|
:action => [old, :del_dns_record, record_type])
|
|
end
|
|
end
|
|
queue_dns_create
|
|
end
|
|
|
|
def queue_dns_destroy
|
|
return unless errors.empty?
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
if dns_feasible?(record_type)
|
|
queue.create(:name => _("Remove %{type} for %{host}") % {:host => self, :type => dns_class(record_type).human}, :priority => 1,
|
|
:action => [self, :del_dns_record, record_type])
|
|
end
|
|
end
|
|
end
|
|
|
|
def queue_remove_dns_conflicts
|
|
return unless errors.empty?
|
|
return unless overwrite?
|
|
logger.debug "Scheduling DNS conflict removal"
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
if dns_feasible?(record_type) && dns_record(record_type) && dns_record(record_type).conflicting?
|
|
queue.create(:name => _("Remove conflicting %{type} for %{host}") % {:host => self, :type => dns_class(record_type).human}, :priority => 0,
|
|
:action => [self, :del_conflicting_dns_record, record_type])
|
|
end
|
|
end
|
|
end
|
|
|
|
def pending_dns_record_changes?
|
|
!attr_equivalent?(old.ip, ip) || !attr_equivalent?(old.ip6, ip6) || !attr_equivalent?(old.hostname, hostname)
|
|
end
|
|
|
|
def dns_conflict_detected?
|
|
return false if ip.blank? || hostname.blank?
|
|
# can't validate anything if dont have an ip-address yet
|
|
return false unless require_ip4_validation? || require_ip6_validation?
|
|
# we should only alert on conflicts if overwrite mode is off
|
|
return false if overwrite?
|
|
|
|
status = true
|
|
DnsInterface::RECORD_TYPES.each do |record_type|
|
|
if dns_feasible?(record_type) && dns_record(record_type) && dns_record(record_type).conflicting?
|
|
conflicts = dns_record(record_type).conflicts
|
|
status = failure(_("%{type} %{conflicts} already exists") % {:conflicts => conflicts.to_sentence, :type => dns_class(record_type).human(conflicts.count)}, nil, :conflict)
|
|
end
|
|
end
|
|
!status # failure method returns 'false'
|
|
rescue Net::Error => e
|
|
if domain.nameservers.empty?
|
|
failure(_("Error connecting to system DNS server(s) - check /etc/resolv.conf"), e)
|
|
else
|
|
failure(_("Error connecting to '%{domain}' domain DNS servers: %{servers} - check query_local_nameservers and dns_conflict_timeout settings") % {:domain => domain.try(:name), :servers => domain.nameservers.join(',')}, e)
|
|
end
|
|
end
|
|
end
|