Project

General

Profile

« Previous | Next » 

Revision 6b4b489f

Added by Ori Rabin over 8 years ago

fixes #10832 - separating lookup keys into puppet and variable

View differences:

app/controllers/api/v1/lookup_keys_controller.rb
param :per_page, String, :desc => "number of entries per request"
def index
@lookup_keys = LookupKey.
authorized(:view_external_variables).
search_for(*search_options).paginate(paginate_options)
@lookup_keys = PuppetclassLookupKey.authorized(:view_external_variables).
search_for(*search_options).paginate(paginate_options).to_a +
VariableLookupKey.authorized(:view_external_variables).
search_for(*search_options).paginate(paginate_options).to_a
end
api :GET, "/lookup_keys/:id/", "Show a lookup key."
app/controllers/concerns/api/v2/lookup_keys_common_controller.rb
def find_smart_variable
id = params.keys.include?('smart_variable_id') ? params['smart_variable_id'] : params['id']
@smart_variable = LookupKey.authorized(:view_external_variables).smart_variables.find_by_id(id.to_i) if id.to_i > 0
@smart_variable = VariableLookupKey.authorized(:view_external_variables).smart_variables.find_by_id(id.to_i) if id.to_i > 0
@smart_variable ||= (puppet_cond = { :puppetclass_id => @puppetclass.id } if @puppetclass
LookupKey.authorized(:view_external_variables).smart_variables.where(puppet_cond).find_by_key(id)
VariableLookupKey.authorized(:view_external_variables).smart_variables.where(puppet_cond).find_by_key(id)
)
@smart_variable
end
......
end
def smart_variables_resource_scope
return LookupKey.authorized(:view_external_variables).smart_variables unless (@puppetclass || @host || @hostgroup)
return VariableLookupKey.authorized(:view_external_variables).smart_variables unless (@puppetclass || @host || @hostgroup)
puppetclass_ids = @puppetclass.id if @puppetclass
puppetclass_ids ||= @hostgroup.all_puppetclasses.map(&:id) if @hostgroup
puppetclass_ids ||= @host.all_puppetclasses.map(&:id) if @host
LookupKey.authorized(:view_external_variables).global_parameters_for_class(puppetclass_ids)
VariableLookupKey.authorized(:view_external_variables).global_parameters_for_class(puppetclass_ids)
end
def find_smart_class_parameter
id = params.keys.include?('smart_class_parameter_id') ? params['smart_class_parameter_id'] : params['id']
@smart_class_parameter = LookupKey.authorized(:view_external_variables).smart_class_parameters.find_by_id(id.to_i) if id.to_i > 0
@smart_class_parameter = PuppetclassLookupKey.authorized(:view_external_variables).smart_class_parameters.find_by_id(id.to_i) if id.to_i > 0
@smart_class_parameter ||= (puppet_cond = { 'environment_classes.puppetclass_id'=> @puppetclass.id } if @puppetclass
env_cond = { 'environment_classes.environment_id' => @environment.id } if @environment
LookupKey.authorized(:view_external_variables).smart_class_parameters.where(puppet_cond).where(env_cond).where(:key => id).first
PuppetclassLookupKey.authorized(:view_external_variables).smart_class_parameters.where(puppet_cond).where(env_cond).where(:key => id).first
)
@smart_class_parameter
end
......
end
def smart_class_parameters_resource_scope
base = LookupKey.authorized(:view_external_variables)
base = PuppetclassLookupKey.authorized(:view_external_variables)
return base.smart_class_parameters unless (@puppetclass || @environment || @host || @hostgroup)
if @puppetclass && @environment
base.smart_class_parameters_for_class(@puppetclass.id, @environment.id)
app/controllers/lookup_keys_controller.rb
def index
@lookup_keys = resource_base.search_for(params[:search], :order => params[:order])
.includes(:param_classes)
.includes(:puppetclass)
.paginate(:page => params[:page])
@puppetclass_authorizer = Authorizer.new(User.current, :collection => @lookup_keys.map(&:puppetclass_id).compact.uniq)
@puppetclass_authorizer = Authorizer.new(User.current, :collection => @lookup_keys.pluck(:puppetclass_id).compact.uniq)
end
def edit
end
def update
if @lookup_key.update_attributes(params[:lookup_key])
if resource.update_attributes(params[resource_name])
process_success
else
process_error
......
end
def destroy
if @lookup_key.destroy
if resource.destroy
process_success
else
process_error
app/controllers/puppetclass_lookup_keys_controller.rb
class PuppetclassLookupKeysController < LookupKeysController
before_filter :setup_search_options, :only => :index
def index
@lookup_keys = resource_base.search_for(params[:search], :order => params[:order])
.paginate(:page => params[:page])
.includes(:param_classes)
@puppetclass_authorizer = Authorizer.new(User.current, :collection => @lookup_keys.pluck(:puppetclass_id).compact.uniq)
end
def resource
@puppetclass_lookup_key
end
end
app/controllers/variable_lookup_keys_controller.rb
class VariableLookupKeysController < LookupKeysController
def resource
@variable_lookup_key
end
end
app/helpers/hosts_and_hostgroups_helper.rb
def interesting_klasses(obj)
classes = obj.all_puppetclasses
classes_ids = classes.reorder('').pluck('puppetclasses.id')
smart_vars = LookupKey.reorder('').where(:puppetclass_id => classes_ids).uniq.pluck(:puppetclass_id)
class_vars = LookupKey.reorder('').joins(:environment_classes).where(:environment_classes => { :puppetclass_id => classes_ids }).uniq.pluck('environment_classes.puppetclass_id')
smart_vars = VariableLookupKey.reorder('').where(:puppetclass_id => classes_ids).uniq.pluck(:puppetclass_id)
class_vars = PuppetclassLookupKey.reorder('').joins(:environment_classes).where(:environment_classes => { :puppetclass_id => classes_ids }).uniq.pluck('environment_classes.puppetclass_id')
klasses = (smart_vars + class_vars).uniq
classes.where(:id => klasses)
app/helpers/lookup_keys_helper.rb
# Show the parent puppetclass as a context, but permit no change.
if params["puppetclass_id"]
select_f f, :puppetclass_id, [Puppetclass.find(params["puppetclass_id"])], :id, :to_label, {}, {:label => _("Puppet class"), :disabled => true}
elsif f.object.is_param && f.object.param_class
elsif f.object.puppet? && f.object.param_class
field(f, :puppetclass_id, :label => _('Puppet Class')) do
content_tag(:input, nil, :value => f.object.param_class, :type => 'text', :disabled => true)
end
......
def param_type_selector(f, options = {})
selectable_f f, :key_type, options_for_select(LookupKey::KEY_TYPES.map { |e| [_(e),e] }, f.object.key_type),{},
options.merge({ :disabled => (f.object.is_param && !f.object.override), :size => "col-md-8", :class=> "without_select2",
options.merge({ :disabled => (f.object.puppet? && !f.object.override), :size => "col-md-8", :class=> "without_select2",
:help_inline => popover("",_("<dl>" +
"<dt>String</dt> <dd>Everything is taken as a string.</dd>" +
"<dt>Boolean</dt> <dd>Common representation of boolean values are accepted.</dd>" +
......
def validator_type_selector(f)
selectable_f f, :validator_type, options_for_select(LookupKey::VALIDATOR_TYPES.map { |e| [_(e),e] }, f.object.validator_type),{:include_blank => _("None")},
{ :disabled => (f.object.is_param && !f.object.override), :size => "col-md-8", :class=> "without_select2",
{ :disabled => (f.object.puppet? && !f.object.override), :size => "col-md-8", :class=> "without_select2",
:onchange => 'validatorTypeSelected(this)',
:help_inline => popover("",_("<dl>" +
"<dt>List</dt> <dd>A list of the allowed values, specified in the Validator rule field.</dd>" +
app/models/concerns/counter_cache_fix.rb
if key =~ /_id/
association = self.association(key.sub(/_id$/, '').to_sym)
if association.options[ :counter_cache ]
counter_name = self.class.name.underscore.split("/")[0].pluralize.to_sym
association.klass.reset_counters(old_value, counter_name) if old_value
association.klass.reset_counters(new_value, counter_name) if new_value
# in case of counter cache on STI, specify the :inverse_of option, otherwise, we might throw an error.
# i.e. VariableLookupKey belongs to puppetclass, but the association name on the puppetclass is lookup_keys, not puppetclass_lookup_keys
# thus, we define the correct name for the association to be derived.
if association.options[:inverse_of].is_a?(Symbol)
counter_name = association.options[:inverse_of]
else
counter_name = self.class.name.underscore.split("/")[0].pluralize.to_sym
end
association_name = counter_name.to_s.sub(/_count$/, "").to_sym
association.klass.reset_counters(old_value, association_name) if old_value
association.klass.reset_counters(new_value, association_name) if new_value
end
end
end
app/models/environment_class.rb
class EnvironmentClass < ActiveRecord::Base
belongs_to :environment
belongs_to :puppetclass
belongs_to :lookup_key
validates :lookup_key_id, :uniqueness => {:scope => [:environment_id, :puppetclass_id]}
belongs_to :puppetclass_lookup_key
validates :puppetclass_lookup_key_id, :uniqueness => {:scope => [:environment_id, :puppetclass_id]}
validates :puppetclass_id, :environment_id, :presence => true
scope :parameters_for_class, lambda {|puppetclasses_ids, environment_id|
all_parameters_for_class(puppetclasses_ids, environment_id).where(:lookup_keys => {:override => true})
all_parameters_for_class(puppetclasses_ids, environment_id).where(:puppetclass_lookup_keys => {:override => true})
}
scope :all_parameters_for_class, lambda {|puppetclasses_ids, environment_id|
where(:puppetclass_id => puppetclasses_ids, :environment_id => environment_id).
where('lookup_key_id is NOT NULL').
includes(:lookup_key)
where('puppetclass_lookup_key_id is NOT NULL').
includes(:puppetclass_lookup_key)
}
scope :used_by_other_environment_classes, lambda{|lookup_key_id, this_environment_class_id|
where(:lookup_key_id => lookup_key_id).
scope :used_by_other_environment_classes, lambda{|puppetclass_lookup_key_id, this_environment_class_id|
where(:puppetclass_lookup_key_id => puppetclass_lookup_key_id).
where("id != #{this_environment_class_id}")
}
# These counters key track of unique puppet class keys (parameters) across environments
after_create do |record|
Puppetclass.increment_counter(:global_class_params_count, self.puppetclass.id) unless self.lookup_key.blank? ||
EnvironmentClass.used_by_other_environment_classes(self.lookup_key, self.id).count > 0
Puppetclass.increment_counter(:global_class_params_count, self.puppetclass.id) unless self.puppetclass_lookup_key.blank? ||
EnvironmentClass.used_by_other_environment_classes(self.puppetclass_lookup_key, self.id).count > 0
end
after_destroy do |record|
Puppetclass.decrement_counter(:global_class_params_count, self.puppetclass.id) unless self.lookup_key.blank? ||
EnvironmentClass.used_by_other_environment_classes(self.lookup_key, self.id).count > 0
Puppetclass.decrement_counter(:global_class_params_count, self.puppetclass.id) unless self.puppetclass_lookup_key.blank? ||
EnvironmentClass.used_by_other_environment_classes(self.puppetclass_lookup_key, self.id).count > 0
end
def lookup_key_id=(val)
Foreman::Deprecation.deprecation_warning("1.12", "lookup_key_id= is deprecated, please use puppetclass_lookup_key_id= instead.")
self.puppetclass_lookup_key_id=val
end
def lookup_key=(val)
Foreman::Deprecation.deprecation_warning("1.12", "lookup_key= is deprecated, please use puppetclass_lookup_key= instead.")
self.puppetclass_lookup_key=val
end
#TODO move these into scopes?
def self.is_in_any_environment(puppetclass, lookup_key)
EnvironmentClass.where(:puppetclass_id => puppetclass, :lookup_key_id => lookup_key ).count > 0
def self.is_in_any_environment(puppetclass, puppetclass_lookup_key)
EnvironmentClass.where(:puppetclass_id => puppetclass, :puppetclass_lookup_key_id => puppetclass_lookup_key ).count > 0
end
def self.key_in_environment(env, puppetclass, lookup_key)
EnvironmentClass.where(:environment_id => env, :puppetclass_id => puppetclass, :lookup_key_id => lookup_key ).first
def self.key_in_environment(env, puppetclass, puppetclass_lookup_key)
EnvironmentClass.where(:environment_id => env, :puppetclass_id => puppetclass, :puppetclass_lookup_key_id => puppetclass_lookup_key ).first
end
end
app/models/lookup_key.rb
class LookupKey < ActiveRecord::Base
include Authorizable
include CounterCacheFix
KEY_TYPES = [N_("string"), N_("boolean"), N_("integer"), N_("real"), N_("array"), N_("hash"), N_("yaml"), N_("json")]
VALIDATOR_TYPES = [N_("regexp"), N_("list") ]
KEY_DELM = ","
EQ_DELM = "="
VALUE_REGEX =/\A[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+(#{KEY_DELM}[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+)*\Z/
audited :associated_with => :audit_class, :allow_mass_assignment => true, :except => :lookup_values_count
validates_lengths_from_database
serialize :default_value
belongs_to :puppetclass, :inverse_of => :lookup_keys, :counter_cache => true
has_many :environment_classes, :dependent => :destroy
has_many :environments, :through => :environment_classes, :uniq => true
has_many :param_classes, :through => :environment_classes, :source => :puppetclass
def param_class
param_classes.first
end
def audit_class
param_class || puppetclass
end
has_many :lookup_values, :dependent => :destroy, :inverse_of => :lookup_key
accepts_nested_attributes_for :lookup_values,
:reject_if => :reject_invalid_lookup_values,
:allow_destroy => true
before_validation :cast_default_value, :unless => Proc.new{|p| p.use_puppet_default }
validates :key, :uniqueness => {:scope => :is_param }, :unless => Proc.new{|p| p.is_param?}
validates :key, :presence => true
validates :puppetclass, :presence => true, :unless => Proc.new {|k| k.is_param?}
validates :validator_type, :inclusion => { :in => VALIDATOR_TYPES, :message => N_("invalid")}, :allow_blank => true, :allow_nil => true
validates :key_type, :inclusion => {:in => KEY_TYPES, :message => N_("invalid")}, :allow_blank => true, :allow_nil => true
validate :validate_default_value
validates_associated :lookup_values
validate :ensure_type, :disable_merge_overrides, :disable_avoid_duplicates, :disable_merge_default
before_save :sanitize_path
attr_name :key
scoped_search :on => :key, :complete_value => true, :default_order => true
scoped_search :on => :lookup_values_count, :rename => :values_count
scoped_search :on => :override, :complete_value => {:true => true, :false => false}
scoped_search :on => :merge_overrides, :complete_value => {:true => true, :false => false}
scoped_search :on => :merge_default, :complete_value => {:true => true, :false => false}
scoped_search :on => :avoid_duplicates, :complete_value => {:true => true, :false => false}
scoped_search :in => :param_classes, :on => :name, :rename => :puppetclass, :complete_value => true
scoped_search :in => :lookup_values, :on => :value, :rename => :value, :complete_value => true
default_scope -> { order('lookup_keys.key') }
scope :override, -> { where(:override => true) }
scope :smart_class_parameters_for_class, lambda { |puppetclass_ids, environment_id|
joins(:environment_classes).where(:environment_classes => {:puppetclass_id => puppetclass_ids, :environment_id => environment_id})
}
scope :parameters_for_class, lambda { |puppetclass_ids, environment_id|
override.smart_class_parameters_for_class(puppetclass_ids,environment_id)
}
scope :global_parameters_for_class, lambda { |puppetclass_ids|
where(:puppetclass_id => puppetclass_ids)
}
scope :smart_variables, -> { where('lookup_keys.puppetclass_id > 0').readonly(false) }
scope :smart_class_parameters, -> { where(:is_param => true).joins(:environment_classes).readonly(false) }
# new methods for API instead of revealing db names
alias_attribute :parameter, :key
alias_attribute :variable, :key
alias_attribute :parameter_type, :key_type
alias_attribute :variable_type, :key_type
alias_attribute :override_value_order, :path
alias_attribute :override_values_count, :lookup_values_count
alias_attribute :override_values, :lookup_values
alias_attribute :override_value_ids, :lookup_value_ids
# to prevent errors caused by find_resource from override_values controller
def self.find_by_name(str)
nil
end
def to_label
"#{audit_class}::#{key}"
end
def is_smart_variable?
puppetclass_id.to_i > 0
end
def is_smart_class_parameter?
is_param? && environment_classes.any?
end
def supports_merge?
['array', 'hash'].include?(key_type)
end
def supports_uniq?
key_type == 'array'
end
def to_param
Parameterizable.parameterize("#{id}-#{key}")
end
def to_s
key
end
def path
path = read_attribute(:path)
path.blank? ? array2path(Setting["Default_variables_Lookup_Path"]) : path
end
def path=(v)
return unless v
using_default = v.tr("\r","") == array2path(Setting["Default_variables_Lookup_Path"])
write_attribute(:path, using_default ? nil : v)
end
def reject_invalid_lookup_values(attributes)
attributes[:match].empty? ||
(attributes[:value].blank? &&
(attributes[:use_puppet_default].nil? || attributes[:use_puppet_default] == "0"))
end
def default_value_before_type_cast
value_before_type_cast default_value
end
def value_before_type_cast(val)
case key_type.to_sym
when :json, :array
begin
val = JSON.dump(val)
rescue JSON::GeneratorError => error
## http://projects.theforeman.org/issues/9553
## @TODO: remove when upgrading to json >= 1.8
logger.debug "Fallback to quirks mode from error: '#{error}'"
val = JSON.dump_in_quirks_mode(val)
end
when :yaml, :hash
val = YAML.dump val
val.sub!(/\A---\s*$\n/, '')
end unless key_type.blank?
val
end
def path_elements
path.split.map do |paths|
paths.split(KEY_DELM).map do |element|
element
end
end
end
def contains_erb?(value)
value =~ /<%.*%>/
end
def overridden?(host)
return false unless host.is_a?(Host::Base) || host.is_a?(Hostgroup)
lookup_values.find_by_match(host.send(:lookup_value_match)).present?
end
private
# Generate possible lookup values type matches to a given host
def path2matches(host)
raise ::Foreman::Exception.new(N_("Invalid Host")) unless host.class.model_name == "Host"
matches = []
path_elements.each do |rule|
match = []
rule.each do |element|
match << "#{element}#{EQ_DELM}#{attr_to_value(host,element)}"
end
matches << match.join(KEY_DELM)
end
matches
end
# translates an element such as domain to its real value per host
# tries to find the host attribute first, parameters and then fallback to a puppet fact.
def attr_to_value(host, element)
# direct host attribute
return host.send(element) if host.respond_to?(element)
# host parameter
return host.host_params[element] if host.host_params.include?(element)
# fact attribute
if (fn = host.fact_names.first(:conditions => { :name => element }))
return FactValue.where(:host_id => host.id, :fact_name_id => fn.id).first.value
end
end
def sanitize_path
self.path = path.tr("\s","").downcase unless path.blank?
end
def array2path(array)
raise ::Foreman::Exception.new(N_("invalid path")) unless array.is_a?(Array)
array.map do |sub_array|
sub_array.is_a?(Array) ? sub_array.join(KEY_DELM) : sub_array
end.join("\n")
end
def cast_default_value
return true if default_value.nil? || contains_erb?(default_value)
begin
Foreman::Parameters::Caster.new(self, :attribute_name => :default_value, :to => key_type).cast!
true
rescue
errors.add(:default_value, _("is invalid"))
false
end
end
def load_yaml_or_json(value)
return value unless value.is_a? String
begin
JSON.load value
rescue
YAML.load value
end
end
def ensure_type
if puppetclass_id.present? and is_param?
self.errors.add(:base, _('Global variable or class Parameter, not both'))
end
end
def validate_default_value
Foreman::Parameters::Validator.new(self,
:type => validator_type,
:validate_with => validator_rule,
:getter => :default_value).validate!
end
def disable_merge_overrides
if merge_overrides && !supports_merge?
self.errors.add(:merge_overrides, _("can only be set for array or hash"))
end
end
def disable_avoid_duplicates
if avoid_duplicates && (!merge_overrides || !supports_uniq?)
self.errors.add(:avoid_duplicates, _("can only be set for arrays that have merge_overrides set to true"))
end
end
def disable_merge_default
if merge_default && !merge_overrides
self.errors.add(:merge_default, _("can only be set when merge overrides is set"))
end
end
end
app/models/lookup_keys/lookup_key.rb
class LookupKey < ActiveRecord::Base
include Authorizable
include CounterCacheFix
KEY_TYPES = [N_("string"), N_("boolean"), N_("integer"), N_("real"), N_("array"), N_("hash"), N_("yaml"), N_("json")]
VALIDATOR_TYPES = [N_("regexp"), N_("list") ]
KEY_DELM = ","
EQ_DELM = "="
VALUE_REGEX =/\A[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+(#{KEY_DELM}[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+)*\Z/
audited :associated_with => :audit_class, :allow_mass_assignment => true, :except => :lookup_values_count
validates_lengths_from_database
serialize :default_value
has_many :lookup_values, :dependent => :destroy, :inverse_of => :lookup_key
accepts_nested_attributes_for :lookup_values,
:reject_if => :reject_invalid_lookup_values,
:allow_destroy => true
before_validation :cast_default_value
validates :key, :presence => true
validates :validator_type, :inclusion => { :in => VALIDATOR_TYPES, :message => N_("invalid")}, :allow_blank => true, :allow_nil => true
validates :key_type, :inclusion => {:in => KEY_TYPES, :message => N_("invalid")}, :allow_blank => true, :allow_nil => true
validate :validate_default_value
validates_associated :lookup_values
validate :disable_merge_overrides, :disable_avoid_duplicates, :disable_merge_default
before_save :sanitize_path
attr_name :key
def self.inherited(child)
child.instance_eval do
scoped_search :on => :key, :complete_value => true, :default_order => true
scoped_search :on => :lookup_values_count, :rename => :values_count
scoped_search :on => :override, :complete_value => {:true => true, :false => false}
scoped_search :on => :merge_overrides, :complete_value => {:true => true, :false => false}
scoped_search :on => :merge_default, :complete_value => {:true => true, :false => false}
scoped_search :on => :avoid_duplicates, :complete_value => {:true => true, :false => false}
scoped_search :in => :lookup_values, :on => :value, :rename => :value, :complete_value => true
end
end
default_scope -> { order('lookup_keys.key') }
scope :override, -> { where(:override => true) }
# new methods for API instead of revealing db names
alias_attribute :parameter, :key
alias_attribute :variable, :key
alias_attribute :parameter_type, :key_type
alias_attribute :variable_type, :key_type
alias_attribute :override_value_order, :path
alias_attribute :override_values_count, :lookup_values_count
alias_attribute :override_values, :lookup_values
alias_attribute :override_value_ids, :lookup_value_ids
# to prevent errors caused by find_resource from override_values controller
def self.find_by_name(str)
nil
end
def audit_class
self
end
def to_label
"#{audit_class}::#{key}"
end
def supports_merge?
['array', 'hash'].include?(key_type)
end
def supports_uniq?
key_type == 'array'
end
def to_param
Parameterizable.parameterize("#{id}-#{key}")
end
def to_s
key
end
def path
path = read_attribute(:path)
path.blank? ? array2path(Setting["Default_variables_Lookup_Path"]) : path
end
def path=(v)
return unless v
using_default = v.tr("\r","") == array2path(Setting["Default_variables_Lookup_Path"])
write_attribute(:path, using_default ? nil : v)
end
def reject_invalid_lookup_values(attributes)
attributes[:match].empty? ||
(attributes[:value].blank? &&
(attributes[:use_puppet_default].nil? || attributes[:use_puppet_default] == "0"))
end
def default_value_before_type_cast
value_before_type_cast default_value
end
def value_before_type_cast(val)
case key_type.to_sym
when :json, :array
begin
val = JSON.dump(val)
rescue JSON::GeneratorError => error
## http://projects.theforeman.org/issues/9553
## @TODO: remove when upgrading to json >= 1.8
logger.debug "Fallback to quirks mode from error: '#{error}'"
val = JSON.dump_in_quirks_mode(val)
end
when :yaml, :hash
val = YAML.dump val
val.sub!(/\A---\s*$\n/, '')
end unless key_type.blank?
val
end
def path_elements
path.split.map do |paths|
paths.split(KEY_DELM).map do |element|
element
end
end
end
def contains_erb?(value)
value =~ /<%.*%>/
end
def overridden?(host)
return false unless host.is_a?(Host::Base) || host.is_a?(Hostgroup)
lookup_values.find_by_match(host.send(:lookup_value_match)).present?
end
def puppet?
false
end
private
# Generate possible lookup values type matches to a given host
def path2matches(host)
raise ::Foreman::Exception.new(N_("Invalid Host")) unless host.class.model_name == "Host"
matches = []
path_elements.each do |rule|
match = []
rule.each do |element|
match << "#{element}#{EQ_DELM}#{attr_to_value(host,element)}"
end
matches << match.join(KEY_DELM)
end
matches
end
# translates an element such as domain to its real value per host
# tries to find the host attribute first, parameters and then fallback to a puppet fact.
def attr_to_value(host, element)
# direct host attribute
return host.send(element) if host.respond_to?(element)
# host parameter
return host.host_params[element] if host.host_params.include?(element)
# fact attribute
if (fn = host.fact_names.first(:conditions => { :name => element }))
return FactValue.where(:host_id => host.id, :fact_name_id => fn.id).first.value
end
end
def sanitize_path
self.path = path.tr("\s","").downcase unless path.blank?
end
def array2path(array)
raise ::Foreman::Exception.new(N_("invalid path")) unless array.is_a?(Array)
array.map do |sub_array|
sub_array.is_a?(Array) ? sub_array.join(KEY_DELM) : sub_array
end.join("\n")
end
def cast_default_value
return true if default_value.nil? || contains_erb?(default_value)
begin
Foreman::Parameters::Caster.new(self, :attribute_name => :default_value, :to => key_type).cast!
true
rescue
errors.add(:default_value, _("is invalid"))
false
end
end
def load_yaml_or_json(value)
return value unless value.is_a? String
begin
JSON.load value
rescue
YAML.load value
end
end
def validate_default_value
Foreman::Parameters::Validator.new(self,
:type => validator_type,
:validate_with => validator_rule,
:getter => :default_value).validate!
end
def disable_merge_overrides
if merge_overrides && !supports_merge?
self.errors.add(:merge_overrides, _("can only be set for array or hash"))
end
end
def disable_avoid_duplicates
if avoid_duplicates && (!merge_overrides || !supports_uniq?)
self.errors.add(:avoid_duplicates, _("can only be set for arrays that have merge_overrides set to true"))
end
end
def disable_merge_default
if merge_default && !merge_overrides
self.errors.add(:merge_default, _("can only be set when merge overrides is set"))
end
end
end
app/models/lookup_keys/puppetclass_lookup_key.rb
class PuppetclassLookupKey < LookupKey
has_many :environment_classes, :dependent => :destroy
has_many :environments, :through => :environment_classes, :uniq => true
has_many :param_classes, :through => :environment_classes, :source => :puppetclass
scoped_search :in => :param_classes, :on => :name, :rename => :puppetclass, :complete_value => true
scope :smart_class_parameters_for_class, lambda { |puppetclass_ids, environment_id|
joins(:environment_classes).where(:environment_classes => {:puppetclass_id => puppetclass_ids, :environment_id => environment_id})
}
scope :parameters_for_class, lambda { |puppetclass_ids, environment_id|
override.smart_class_parameters_for_class(puppetclass_ids,environment_id)
}
scope :smart_class_parameters, -> { joins(:environment_classes).readonly(false) }
def param_class
param_classes.first
end
def audit_class
param_class
end
def cast_default_value
super unless use_puppet_default
true
end
def validate_default_value
super unless use_puppet_default
true
end
def puppet?
true
end
end
app/models/lookup_keys/variable_lookup_key.rb
class VariableLookupKey < LookupKey
belongs_to :puppetclass, :inverse_of => :lookup_keys, :counter_cache => :variable_lookup_keys_count
validates :puppetclass, :presence => true
validates :key, :uniqueness => true
scoped_search :in => :puppetclass, :on => :name, :complete_value => true, :rename => :puppetclass
def audit_class
puppetclass
end
def param_class
puppetclass
end
scope :global_parameters_for_class, lambda { |puppetclass_ids|
where(:puppetclass_id => puppetclass_ids)
}
scope :smart_variables, -> { where('lookup_keys.puppetclass_id > 0').readonly(false) }
end
app/models/puppetclass.rb
has_many_hosts :through => :host_classes, :dependent => :destroy
has_many :config_group_classes
has_many :config_groups, :through => :config_group_classes, :dependent => :destroy
has_many :lookup_keys, :inverse_of => :puppetclass, :dependent => :destroy
has_many :lookup_keys, :inverse_of => :puppetclass, :dependent => :destroy, :class_name => 'VariableLookupKey'
accepts_nested_attributes_for :lookup_keys, :reject_if => ->(a) { a[:key].blank? }, :allow_destroy => true
# param classes
has_many :class_params, :through => :environment_classes, :uniq => true,
:source => :lookup_key, :conditions => 'environment_classes.lookup_key_id is NOT NULL'
:source => :puppetclass_lookup_key, :conditions => 'environment_classes.puppetclass_lookup_key_id is NOT NULL'
accepts_nested_attributes_for :class_params, :reject_if => ->(a) { a[:key].blank? }, :allow_destroy => true
validates :name, :uniqueness => true, :presence => true, :no_whitespace => true
audited :allow_mass_assignment => true, :except => [:total_hosts, :lookup_keys_count, :global_class_params_count]
audited :allow_mass_assignment => true, :except => [:total_hosts, :variable_lookup_keys_count, :global_class_params_count]
alias_attribute :smart_variables, :lookup_keys
alias_attribute :smart_variable_ids, :lookup_key_ids
......
scoped_search :on => :name, :complete_value => :true
scoped_search :on => :total_hosts
scoped_search :on => :global_class_params_count, :rename => :params_count # Smart Parameters
scoped_search :on => :lookup_keys_count, :rename => :variables_count # Smart Variables
scoped_search :on => :variable_lookup_keys_count, :rename => :variables_count # Smart Variables
scoped_search :in => :environments, :on => :name, :complete_value => :true, :rename => "environment"
scoped_search :in => :hostgroups, :on => :name, :complete_value => :true, :rename => "hostgroup"
scoped_search :in => :config_groups, :on => :name, :complete_value => :true, :rename => "config_group"
app/services/classification/class_param.rb
protected
def class_parameters
@keys ||= LookupKey.includes(:environment_classes).parameters_for_class(puppetclass_ids, environment_id)
@keys ||= PuppetclassLookupKey.includes(:environment_classes).parameters_for_class(puppetclass_ids, environment_id)
end
private
app/services/classification/global_param.rb
protected
def class_parameters
@keys ||= LookupKey.global_parameters_for_class(puppetclass_ids)
@keys ||= VariableLookupKey.global_parameters_for_class(puppetclass_ids)
end
end
end
app/services/foreman/access_permissions.rb
permission_set.security_block :external_variables do |map|
map.permission :view_external_variables, {:lookup_keys => [:index, :show, :auto_complete_search],
:puppetclass_lookup_keys => [:index, :show, :auto_complete_search],
:variable_lookup_keys => [:index, :show, :auto_complete_search],
:lookup_values => [:index],
:"api/v1/lookup_keys" => [:index, :show],
:"api/v2/smart_variables" => [:index, :show],
:"api/v2/smart_class_parameters" => [:index, :show],
:"api/v2/override_values" => [:index, :show]}
map.permission :create_external_variables, {:lookup_keys => [:new, :create],
:puppetclass_lookup_keys => [:new, :create],
:variable_lookup_keys => [:new, :create],
:lookup_values => [:create],
:"api/v1/lookup_keys" => [:create],
:"api/v2/smart_variables" => [:create],
:"api/v2/smart_class_parameters" => [:create],
:"api/v2/override_values" => [:create]}
map.permission :edit_external_variables, {:lookup_keys => [:edit, :update],
:puppetclass_lookup_keys => [:edit, :update],
:variable_lookup_keys => [:edit, :update],
:lookup_values => [:create, :update, :destroy],
:"api/v1/lookup_keys" => [:update],
:"api/v2/smart_variables" => [:update],
:"api/v2/smart_class_parameters" => [:update],
:"api/v2/override_values" => [:create, :update, :destroy]}
map.permission :destroy_external_variables, {:lookup_keys => [:destroy],
:puppetclass_lookup_keys => [:destroy],
:variable_lookup_keys => [:destroy],
:lookup_values => [:destroy],
:"api/v1/lookup_keys" => [:destroy],
:"api/v2/smart_variables" => [:destroy],
app/services/menu/loader.rb
menu.item :environments, :caption => N_('Environments')
menu.item :puppetclasses, :caption => N_('Classes')
menu.item :config_groups, :caption => N_('Config groups')
menu.item :lookup_keys, :caption => N_('Smart variables')
menu.item :variable_lookup_keys, :caption => N_('Smart variables')
menu.item :puppetclass_lookup_keys, :caption => N_('Smart class parameters')
end
menu.sub_menu :infrastructure_menu, :caption => N_('Infrastructure') do
app/services/puppet_class_importer.rb
return [] unless db_environments.include?(environment) && actual_environments.include?(environment)
HashWithIndifferentAccess[
db_classes(environment).map do |db_class|
params = EnvironmentClass.all_parameters_for_class(db_class.id, find_or_create_env(environment).id).map(&:lookup_key)
params = EnvironmentClass.all_parameters_for_class(db_class.id, find_or_create_env(environment).id).map(&:puppetclass_lookup_key)
compare_classes(environment, db_class.name, params)
end.compact
]
......
def find_or_create_puppet_class_param(klass, param_name, value)
klass.class_params.where(:key => param_name).first ||
LookupKey.create!(:key => param_name, :is_param => true,
:required => value.nil?, :override => value.nil?, :default_value => value,
:key_type => Foreman::ImporterPuppetclass.suggest_key_type(value))
PuppetclassLookupKey.create!(:key => param_name, :required => value.nil?,
:override => value.nil?, :default_value => value,
:key_type => Foreman::ImporterPuppetclass.suggest_key_type(value))
end
end
app/views/api/v1/lookup_keys/index.json.rabl
collection @lookup_keys
collection @lookup_keys, :object_root => "lookup_key"
extends "api/v1/lookup_keys/show"
app/views/api/v1/lookup_keys/show.json.rabl
object @lookup_key
object @lookup_key => :lookup_key
attributes :key, :is_param, :required, :override, :description, :default_value, :id
attributes :key, :required, :override, :description, :default_value, :id
node(:is_param) { |key| key.puppet? }
app/views/common_parameters/_puppetclass_parameter.html.erb
<tr class="form-group <%= 'error' if f.object.errors.any? %>">
<td class="col-md-3">
<%= f.hidden_field :lookup_key_id, :'data-property' => 'lookup_key_id' %>
<% puppetclass = f.object.lookup_key ? f.object.lookup_key.puppetclass || f.object.lookup_key.param_class : nil %>
<% puppetclass = f.object.lookup_key ? f.object.lookup_key.param_class : nil %>
<%= text_field_tag '', (puppetclass.name rescue ''), :class => 'form-control', :'data-property' => 'class', :disabled => true, :title => _('Puppetclass') %>
</td>
<td class="col-md-2">
app/views/lookup_keys/_edit.html.erb
<%= form_for(lookup_key) do |f| %>
<%= render 'lookup_keys/fields', :f => f %>
<%= submit_or_cancel f %>
<% end %>
app/views/lookup_keys/_fields.html.erb
<div id='<%= (f.object.key || 'new_lookup_keys').to_s.gsub(' ', '_') + '_' + f.object.id.to_s %>' class='tab-pane fields'>
<% is_param = f.object.is_param %>
<% is_param = f.object.puppet? %>
<%= remove_child_link(_("Remove %s?") % (f.object.new_record? ? _("Variable") : f.object), f, { :class => 'btn btn-danger hide' }) unless controller_name == "lookup_keys" %>
<%= remove_child_link(_("Remove %s?") % (f.object.new_record? ? _("Variable") : f.object), f, { :class => 'btn btn-danger hide' }) unless controller_name == "variable_lookup_keys" || "puppetclass_lookup_keys" %>
<fieldset>
<legend><%= _("Parameter details") %></legend>
<%= text_f f, :key, :disabled => f.object.is_param, :size => "col-md-8" %>
<%= text_f f, :key, :disabled => is_param, :size => "col-md-8" %>
<%= f.hidden_field :key if is_param %>
<%= textarea_f f, :description, :rows => :auto, :size => "col-md-8", :class => "no-stretch" %>
<%= text_f(f, :environment_classes, :value => f.object.environment_classes.map(&:environment).to_sentence, :label => _('Puppet Environments'), :size => "col-md-8", :disabled => true) if is_param %>
......
</fieldset>
<fieldset>
<legend><%= _("Default behavior") %></legend>
<h6><%= _("Override the default value of the Puppet class parameter.") if f.object.is_param%></h6>
<h6><%= _("Override the default value of the Puppet class parameter.") if is_param%></h6>
<%= checkbox_f(f, :override, :onchange => 'toggleOverrideValue(this)', :size => "col-md-8",
:help_inline => popover('', _('Whether the class parameter value is managed by Foreman.'))
) if is_param %>
<%= param_type_selector(f, :onchange => 'keyTypeChange(this)') %>
<%= textarea_f f, :default_value, :value => f.object.default_value_before_type_cast, :size => "col-md-8",
:disabled => (f.object.is_param && (!f.object.override || f.object.use_puppet_default)),
:disabled => (is_param && (!f.object.override || f.object.use_puppet_default)),
:fullscreen => :true,
:rows => :auto,
:help_inline => popover('', _("Value to use when there is no match.")),
......
<%= checkbox_f(f, :use_puppet_default, :label => _('Use Puppet default'), :size => "col-md-8",
:help_inline => use_puppet_default_help,
:onchange => 'toggleUsePuppetDefaultValue(this, "default_value")',
:disabled => (f.object.is_param && !f.object.override)) if is_param %>
:disabled => (is_param && !f.object.override)) if is_param %>
</br>
</fieldset>
<fieldset>
......
</div>
</fieldset>
</br>
<div class="matcher-parent" <%= "id=#{(f.object.key || 'new_lookup_keys').to_s.gsub(' ', '_')}_lookup_key_override_value" %> style=<%= "display:none;" if (f.object.is_param && !f.object.override) %>>
<div class="matcher-parent" <%= "id=#{(f.object.key || 'new_lookup_keys').to_s.gsub(' ', '_')}_lookup_key_override_value" %> style=<%= "display:none;" if (is_param && !f.object.override) %>>
<fieldset>
<legend><%= _("Prioritize attribute order") %></legend>
<h6><%= popover("", _("The order in which matchers keys are processed, first match wins.<br> You may use multiple attributes as a matcher key, for example, an order of <code>host group, environment</code> would expect a matcher such as <code>hostgroup = \"web servers\", environment = production</code>"),
app/views/lookup_keys/edit.html.erb
<%= javascript "lookup_keys" %>
<% title(_("Edit Smart Variable")) %>
<%= form_for(@lookup_key) do |f| %>
<%= render 'fields', :f => f %>
<%= submit_or_cancel f %>
<% end %>
app/views/lookup_keys/index.html.erb
<%= javascript "lookup_keys" %>
<% title _("Smart variables") %>
<% title_actions documentation_button('4.2.4SmartVariables') %>
<table class="table table-bordered table-striped table-two-pane">
<thead>
<tr>
<th><%= sort :key, :as => _("Variable") %></th>
<th><%= sort :puppetclass, :as => _("Puppetclass") %></th>
<th><%= sort :values_count, :as => _('Number of values'), :default => "DESC" %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @lookup_keys.each do |lookup_key| %>
<tr>
<td class="display-two-pane"><%= link_to_if_authorized trunc_with_tooltip(lookup_key.key), hash_for_edit_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'edit_external_variables', :authorizer => authorizer) %></td>
<% puppet_class = lookup_key.param_class %>
<td class="display-two-pane"><%= link_to_if_authorized trunc_with_tooltip(puppet_class), hash_for_edit_puppetclass_path(:id => puppet_class).merge(:auth_object => puppet_class, :authorizer => @puppetclass_authorizer) if puppet_class %></td>
<td><%=h lookup_key.lookup_values_count %></td>
<td><%= display_delete_if_authorized hash_for_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'destroy_external_variables', :authorizer => authorizer),
:data => { :confirm => _("Delete %s?") % lookup_key.key } %></td>
</tr>
<% end %>
</tbody>
</table>
<%= will_paginate_with_info @lookup_keys %>
app/views/puppetclass_lookup_keys/edit.html.erb
<%= javascript "lookup_keys" %>
<% title(_("Edit Smart class parameters")) %>
<%= render 'lookup_keys/edit', :lookup_key => @puppetclass_lookup_key %>
app/views/puppetclass_lookup_keys/index.html.erb
<%= javascript "lookup_keys" %>
<% title _("Smart class parameters") %>
<% title_actions documentation_button('4.2.5ParameterizedClasses') %>
<table class="table table-bordered table-striped table-two-pane">
<thead>
<tr>
<th><%= sort :key, :as => _("Parameter") %></th>
<th><%= sort :puppetclass, :as => _("Puppetclass") %></th>
<th><%= sort :values_count, :as => _('Number of values'), :default => "DESC" %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @lookup_keys.each do |lookup_key| %>
<tr>
<td class="display-two-pane"><%= link_to_if_authorized trunc_with_tooltip(lookup_key.key), hash_for_edit_puppetclass_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'edit_external_variables', :authorizer => authorizer) %></td>
<% puppet_class = lookup_key.param_class %>
<td><%= link_to_if_authorized trunc_with_tooltip(puppet_class), hash_for_edit_puppetclass_path(:id => puppet_class).merge(:auth_object => puppet_class, :authorizer => @puppetclass_authorizer) if puppet_class %></td>
<td><%=h lookup_key.lookup_values_count %></td>
<td><%= display_delete_if_authorized hash_for_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'destroy_external_variables', :authorizer => authorizer),
:data => { :confirm => _("Delete %s?") % lookup_key.key } %></td>
</tr>
<% end %>
</tbody>
</table>
<%= will_paginate_with_info @lookup_keys %>
app/views/puppetclasses/index.html.erb
<td><%= puppetclass.all_hostgroups(false).map {|hg| link_to_if_authorized trunc_with_tooltip(hg), hash_for_edit_hostgroup_path(:id=>hg).merge(:auth_object => hg, :authorizer => @hostgroups_authorizer)}.to_sentence.html_safe %></td>
<td> <%= link_to puppetclass.total_hosts, hosts_path(:search => "class = #{puppetclass.name}")%></td>
<td><%= puppetclass.global_class_params_count %> </td>
<td><%= puppetclass.lookup_keys_count %> </td>
<td><%
<td><%= puppetclass.variable_lookup_keys_count %> </td>
<td>
<%
links = [display_delete_if_authorized(hash_for_puppetclass_path(:id => puppetclass).merge(:auth_object => puppetclass, :authorizer => authorizer), :data => { :confirm => _("Delete %s?") % puppetclass.name }, :action => :delete)]
links.push(display_link_if_authorized(_('Override all parameters'), hash_for_override_puppetclass_path(:enable => true, :id => puppetclass), :method => :post, :data => { :confirm => _("This will set all parameters of the class %s as overridden. Continue?") % puppetclass.name })) if puppetclass.class_params.present? && !overridden?(puppetclass)
links.push(display_link_if_authorized(_('Set parameters to defaults'), hash_for_override_puppetclass_path(:enable => false, :id => puppetclass), :method => :post, :data => { :confirm => _("This will reset parameters of the class %s to their default values. Continue?") % puppetclass.name })) if puppetclass.class_params.present? && overridden?(puppetclass)
app/views/variable_lookup_keys/edit.html.erb
<%= javascript "lookup_keys" %>
<% title(_("Edit Smart Variable")) %>
<%= render 'lookup_keys/edit', :lookup_key => @variable_lookup_key%>
app/views/variable_lookup_keys/index.html.erb
<%= javascript "lookup_keys" %>
<% title _("Smart variables") %>
<% title_actions documentation_button('4.2.4SmartVariables') %>
<table class="table table-bordered table-striped table-two-pane">
<thead>
<tr>
<th><%= sort :key, :as => _("Variable") %></th>
<th><%= sort :puppetclass, :as => _("Puppetclass") %></th>
<th><%= sort :values_count, :as => _('Number of values'), :default => "DESC" %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @lookup_keys.each do |lookup_key| %>
<tr>
<td class="display-two-pane"><%= link_to_if_authorized trunc_with_tooltip(lookup_key.key), hash_for_edit_variable_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'edit_external_variables', :authorizer => authorizer) %></td>
<td><%= link_to_if_authorized trunc_with_tooltip(lookup_key.puppetclass), hash_for_edit_puppetclass_path(:id => lookup_key.puppetclass).merge(:auth_object => lookup_key.puppetclass, :authorizer => @puppetclass_authorizer) %></td>
<td><%=h lookup_key.lookup_values_count %></td>
<td><%= display_delete_if_authorized hash_for_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'destroy_external_variables', :authorizer => authorizer),
:data => { :confirm => _("Delete %s?") % lookup_key.key } %></td>
</tr>
<% end %>
</tbody>
</table>
<%= will_paginate_with_info @lookup_keys %>
config/application.rb
config.autoload_paths += %W(#{config.root}/app/models/auth_sources)
config.autoload_paths += %W(#{config.root}/app/models/compute_resources)
config.autoload_paths += %W(#{config.root}/app/models/lookup_keys)
config.autoload_paths += %W(#{config.root}/app/models/operatingsystems)
config.autoload_paths += %W(#{config.root}/app/models/parameters)
config.autoload_paths += %W(#{config.root}/app/models/trends)
config/routes.rb
end
resources :bookmarks, :except => [:show]
resources :lookup_keys, :except => [:show, :new, :create] do
resources :lookup_values, :only => [:index, :create, :update, :destroy]
collection do
get 'auto_complete_search'
[:lookup_keys, :variable_lookup_keys, :puppetclass_lookup_keys].each do |key|
resources key, :except => [:show, :new, :create] do
resources :lookup_values, :only => [:index, :create, :update, :destroy]
collection do
get 'auto_complete_search'
end
end
end
db/migrate/20150606065713_add_sti_to_lookup_keys.rb
class AddStiToLookupKeys < ActiveRecord::Migration
def up
add_column :lookup_keys, :type, :string
LookupKey.where(:is_param => true).update_all(:type => 'PuppetclassLookupKey')
LookupKey.where(:is_param => false).update_all(:type => 'VariableLookupKey')
add_index :lookup_keys, :type
remove_foreign_key :environment_classes, :lookup_keys if foreign_key_exists?(:environment_classes, :lookup_keys)
rename_column :environment_classes, :lookup_key_id, :puppetclass_lookup_key_id
add_foreign_key :environment_classes, :lookup_keys, :column => :puppetclass_lookup_key_id, :name => "environment_classes_lookup_key_id_fk"
end
def down
LookupKey.where(:type => "PuppetclassLookupKey").update_all(:is_param => true)
remove_column :lookup_keys, :type
remove_foreign_key :environment_classes, :lookup_keys if foreign_key_exists?(:environment_classes, :lookup_keys)
rename_column :environment_classes, :puppetclass_lookup_key_id, :lookup_key_id
add_foreign_key :environment_classes, :lookup_keys
end
end
db/migrate/20150614171717_rename_puppetclass_counters_for_lk_sti.rb
class RenamePuppetclassCountersForLkSti < ActiveRecord::Migration
def up
# This is the counter for the total number of params for a given puppet class
# across all environments. It was poorly named.
rename_column :puppetclasses, :lookup_keys_count, :variable_lookup_keys_count
end
def down
rename_column :puppetclasses, :variable_lookup_keys_count, :lookup_keys_count
end
end
db/migrate/20150714132601_remove_is_param.rb
class RemoveIsParam < ActiveRecord::Migration
def up
remove_column :lookup_keys, :is_param
end
def down
add_column :lookup_keys, :is_param, :boolean
end
end
locale/en/foreman.po
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Avoid duplicates"
msgid "Variable lookup key"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Default value"
msgid "VariableLookupKey|Avoid duplicates"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Default value"
msgstr "Default value"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Description"
msgid "VariableLookupKey|Description"
msgstr "Description"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Is param"
msgid "VariableLookupKey|Is param"
msgstr "Is parameter"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Key"
msgid "VariableLookupKey|Key"
msgstr "Parameter"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Key type"
msgid "VariableLookupKey|Key type"
msgstr "Parameter type"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Lookup values count"
msgid "VariableLookupKey|Variable lookup values count"
msgstr "Number of values"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Merge overrides"
msgid "VariableLookupKey|Merge overrides"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Override"
msgstr "Override"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Path"
msgstr "Path"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Required"
msgstr "Required"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Validator rule"
msgstr "Validator rule"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "VariableLookupKey|Validator type"
msgstr "Validator type"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "Puppetclass lookup key"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Avoid duplicates"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Default value"
msgstr "Default value"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Description"
msgstr "Description"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Is param"
msgstr "Is parameter"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Key"
msgstr "Parameter"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Key type"
msgstr "Parameter type"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "PuppetclassLookupKey|Merge overrides"
msgstr ""
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Override"
msgid "PuppetclassLookupKey|Override"
msgstr "Override"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Path"
msgid "PuppetclassLookupKey|Path"
msgstr "Path"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Required"
msgid "PuppetclassLookupKey|Required"
msgstr "Required"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Validator rule"
msgid "PuppetclassLookupKey|Validator rule"
msgstr "Validator rule"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
msgid "LookupKey|Validator type"
msgid "PuppetclassLookupKey|Validator type"
msgstr "Validator type"
#. TRANSLATORS: "Table name" or "Table name|Column name" for error messages
locale/model_attributes.rb
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('Lookup key')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Avoid duplicates')
_('Variable lookup key')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Default value')
_('VariableLookupKey|Avoid duplicates')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Description')
_('VariableLookupKey|Default value')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Is param')
_('VariableLookupKey|Description')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Key')
_('VariableLookupKey|Is param')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Key type')
_('VariableLookupKey|Key')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Lookup values count')
_('VariableLookupKey|Key type')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Merge overrides')
_('VariableLookupKey|Variable lookup values count')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Override')
_('VariableLookupKey|Merge overrides')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Path')
_('VariableLookupKey|Override')
# TRANSLATORS: "Table name" or "Table name|Column name" for error messages
_('LookupKey|Required')
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff