Project

General

Profile

Download (4.39 KB) Statistics
| Branch: | Tag: | Revision:
class SmartProxy < ApplicationRecord
audited
include Authorizable
extend FriendlyId
friendly_id :name
include Taxonomix
include Parameterizable::ByIdName

validates_lengths_from_database
before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups, :subnets, :domains, [:puppet_ca_hosts, :hosts], [:puppet_ca_hostgroups, :hostgroups], :realms)
# TODO check if there is a way to look into the tftp_id too
# maybe with a predefined sql
has_and_belongs_to_many :features
has_many :subnets, :foreign_key => 'dhcp_id'
has_many :domains, :foreign_key => 'dns_id'
has_many_hosts :foreign_key => 'puppet_proxy_id'
has_many :hostgroups, :foreign_key => 'puppet_proxy_id'
has_many :puppet_ca_hosts, :class_name => 'Host::Managed', :foreign_key => 'puppet_ca_proxy_id'
has_many :puppet_ca_hostgroups, :class_name => 'Hostgroup', :foreign_key => 'puppet_ca_proxy_id'
has_many :realms, :foreign_key => 'realm_proxy_id'
validates :name, :uniqueness => true, :presence => true
validates :url, :presence => true, :url_schema => ['http', 'https'],
:uniqueness => { :message => N_('Only one declaration of a proxy is allowed') }

# There should be no problem with associating features before the proxy is saved as the whole operation is in a transaction
before_save :sanitize_url, :associate_features

scoped_search :on => :name, :complete_value => :true
scoped_search :on => :url, :complete_value => :true
scoped_search :relation => :features, :on => :name, :rename => :feature, :complete_value => :true

# with proc support, default_scope can no longer be chained
# include all default scoping here
default_scope lambda {
with_taxonomy_scope do
order('smart_proxies.name')
end
}

scope :with_features, ->(*feature_names) { where(:features => { :name => feature_names }).joins(:features) if feature_names.any? }

def hostname
URI(url).host
end

def to_s
hostname
end

def hosts_count
Host::Managed.search_for("smart_proxy = #{name}").count
end

def refresh
statuses.values.each { |status| status.revoke_cache! }
associate_features
errors
end

def taxonomy_foreign_conditions
conditions = {}
if has_feature?('Puppet') && has_feature?('Puppet CA')
conditions = "puppet_proxy_id = #{id} OR puppet_ca_proxy_id = #{id}"
elsif has_feature?('Puppet')
conditions[:puppet_proxy_id] = id
elsif has_feature?('Puppet CA')
conditions[:puppet_ca_proxy_id] = id
end
conditions
end

def has_feature?(feature)
self.features.any? { |proxy_feature| proxy_feature.name == feature }
end

def statuses
return @statuses if @statuses
@statuses = {}
features.each do |feature|
name = feature.name.delete(' ')
if (status = ProxyStatus.find_status_by_humanized_name(name))
@statuses[name.downcase.to_sym] = status.new(self)
end
end
@statuses[:version] = ProxyStatus::Version.new(self)

@statuses
end

private

def sanitize_url
self.url = url.chomp('/') unless url.empty?
end

def associate_features
begin
reply = ProxyAPI::Features.new(:url => url).features
unless reply.is_a?(Array)
logger.debug("Invalid response from proxy #{name}: Expected Array of features, got #{reply}.")
errors.add(:base, _('An invalid response was received while requesting available features from this proxy'))
throw :abort
end
valid_features = reply.map{|f| Feature.name_map[f]}.compact
if valid_features.any?
self.features = Feature.where(:name => valid_features)
else
self.features.clear
if reply.any?
errors.add :base, _('Features "%s" in this proxy are not recognized by Foreman. '\
'If these features come from a Smart Proxy plugin, make sure Foreman has the plugin installed too.') % reply.to_sentence
else
errors.add :base, _('No features found on this proxy, please make sure you enable at least one feature')
end
end
rescue => e
errors.add(:base, _('Unable to communicate with the proxy: %s') % e)
errors.add(:base, _('Please check the proxy is configured and running on the host.'))
end
throw :abort if features.empty?
end
end
(51-51/70)