Class: JobTemplate

Inherits:
Template
  • Object
show all
Extended by:
FriendlyId
Includes:
Authorizable, ForemanRemoteExecution::Exportable, Parameterizable::ByIdName, Taxonomix
Defined in:
app/models/job_template.rb

Defined Under Namespace

Classes: NonUniqueInputsError

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ForemanRemoteExecution::Exportable

#export_attr, #export_iterable, #to_export

Class Method Details

.base_classObject

we have to override the base_class because polymorphic associations does not detect it correctly, more details at apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many#1010-Polymorphic-has-many-within-inherited-class-gotcha



61
62
63
# File 'app/models/job_template.rb', line 61

def base_class
  self
end

.import!(name, text, metadata, force = false) ⇒ Object

This method is used by foreman_templates to import templates, the API should be kept compatible with it



80
81
82
83
84
# File 'app/models/job_template.rb', line 80

def import!(name, text, , force = false)
   = .dup
  .delete('associate')
  JobTemplateImporter.import!(name, text, )
end

.import_parsed(name, text, metadata, options = {}) ⇒ Object

rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'app/models/job_template.rb', line 87

def import_parsed(name, text, , options = {})
  transaction do
    return if .blank? || .delete('kind') != 'job_template' ||
              (.key?('model') && .delete('model') != self.to_s)
    ['name'] = name
    # Don't look for existing if we should always create a new template
    existing = self.find_by(:name => name) unless options.delete(:build_new)
    # Don't update if the template already exists, unless we're told to
    return if !options.delete(:update) && existing

    template = existing || self.new
    template.sync_inputs(.delete('template_inputs'))
    template.sync_foreign_input_sets(.delete('foreign_input_sets'))
    template.sync_feature(.delete('feature'))
    template.locked = false if options.delete(:force)
    template.assign_attributes(.merge(:template => text.gsub(/<%\#.+?.-?%>\n?/m, '').strip).merge(options))
    template.assign_taxonomies if template.new_record?
    template
  end
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
end

.import_raw(contents, options = {}) ⇒ Object

Import a template from ERB, with YAML metadata in the first comment. It will overwrite (sync) an existing template if options is true.



68
69
70
71
# File 'app/models/job_template.rb', line 68

def import_raw(contents, options = {})
   = (contents)
  import_parsed(['name'], contents, , options)
end

.import_raw!(contents, options = {}) ⇒ Object



73
74
75
76
77
# File 'app/models/job_template.rb', line 73

def import_raw!(contents, options = {})
  template = import_raw(contents, options)
  template.save! if template
  template
end

.parse_metadata(template) ⇒ Object



218
219
220
221
# File 'app/models/job_template.rb', line 218

def self.(template)
  match = template.match(/<%\#(.+?).-?%>/m)
  match.nil? ? {} : YAML.safe_load(match[1])
end

Instance Method Details

#assign_taxonomiesObject



137
138
139
140
141
142
# File 'app/models/job_template.rb', line 137

def assign_taxonomies
  if default
    organizations << Organization.all if SETTINGS[:organizations_enabled]
    locations << Location.all if SETTINGS[:locations_enabled]
  end
end

#dupObject



129
130
131
132
133
134
135
# File 'app/models/job_template.rb', line 129

def dup
  dup = super
  self.template_inputs.each do |input|
    dup.template_inputs.build input.attributes.except('template_id', 'id', 'created_at', 'updated_at')
  end
  dup
end

#effective_userObject



148
149
150
# File 'app/models/job_template.rb', line 148

def effective_user
  super || build_effective_user.tap(&:set_defaults)
end

#filenameObject

‘Package Action - SSH Default’ => ‘package_action_ssh_default.erb’



115
116
117
# File 'app/models/job_template.rb', line 115

def filename
  name.downcase.delete('-').gsub(/\s+/, '_') + '.erb'
end

#generate_description_formatObject



152
153
154
155
156
157
158
159
160
161
162
163
# File 'app/models/job_template.rb', line 152

def generate_description_format
  if description_format.blank?
    generated_description = '%{job_category}'
    unless template_inputs_with_foreign.empty?
      inputs = template_inputs_with_foreign.map(&:name).map { |name| %{#{name}="%{#{name}}"} }.join(' ')
      generated_description << " with inputs #{inputs}"
    end
    generated_description
  else
    description_format
  end
end

#metadataObject



110
111
112
# File 'app/models/job_template.rb', line 110

def 
  "<%#\n#{to_export(false).to_yaml.sub(/\A---$/, '').strip}\n%>\n\n"
end

#providerObject



144
145
146
# File 'app/models/job_template.rb', line 144

def provider
  RemoteExecutionProvider.provider_for(provider_type)
end

#sync_feature(feature_name) ⇒ Object



212
213
214
215
216
# File 'app/models/job_template.rb', line 212

def sync_feature(feature_name)
  if feature_name && (feature = RemoteExecutionFeature.feature(feature_name)) && feature.job_template.blank?
    self.remote_execution_features << feature
  end
end

#sync_foreign_input_sets(input_sets) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'app/models/job_template.rb', line 190

def sync_foreign_input_sets(input_sets)
  input_sets ||= []

  input_sets = input_sets.inject({}) do |h, input_set|
    target_template = JobTemplate.find_by!(:name => input_set.delete('template'))
    input_set['target_template_id'] = target_template.id
    h.update(target_template.id => input_set)
  end

  # Sync existing input sets
  foreign_input_sets.each do |existing_input_set|
    if input_sets.include?(existing_input_set.target_template_id)
      existing_input_set.assign_attributes(input_sets.delete(existing_input_set.target_template_id))
    else
      existing_input_set.mark_for_destruction
    end
  end

  # Create new input_sets
  input_sets.values.each { |input_set| self.foreign_input_sets.build(input_set) }
end

#sync_inputs(inputs) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'app/models/job_template.rb', line 172

def sync_inputs(inputs)
  inputs ||= []
  # Build a hash where keys are input names
  inputs = inputs.inject({}) { |h, input| h.update(input['name'] => input) }

  # Sync existing inputs
  template_inputs.each do |existing_input|
    if inputs.include?(existing_input.name)
      existing_input.assign_attributes(inputs.delete(existing_input.name))
    else
      existing_input.mark_for_destruction
    end
  end

  # Create new inputs
  inputs.values.each { |new_input| template_inputs.build(new_input) }
end

#to_erbObject



119
120
121
# File 'app/models/job_template.rb', line 119

def to_erb
   + template
end

#used_taxonomy_ids(type) ⇒ Object

Override method in Taxonomix as Template is not used attached to a Host, and matching a Host does not prevent removing a template from its taxonomy.



125
126
127
# File 'app/models/job_template.rb', line 125

def used_taxonomy_ids(type)
  []
end

#validate_unique_inputs!Object



165
166
167
168
169
170
# File 'app/models/job_template.rb', line 165

def validate_unique_inputs!
  duplicated_inputs = template_inputs_with_foreign.group_by(&:name).values.select { |values| values.size > 1 }.map(&:first)
  unless duplicated_inputs.empty?
    raise NonUniqueInputsError.new(N_('Duplicated inputs detected: %{duplicated_inputs}'), :duplicated_inputs => duplicated_inputs.map(&:name))
  end
end