-
Notifications
You must be signed in to change notification settings - Fork 55
/
template_importer.rb
183 lines (156 loc) · 5.38 KB
/
template_importer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
class NoKindError < RuntimeError; end
class MissingKindError < RuntimeError; end
module ForemanTemplates
class TemplateImporter < Action
attr_accessor :metadata, :name, :text
def self.setting_overrides
super + %i(associate force)
end
def initialize(args = {})
super
@verbose = parse_bool(@verbose)
@force = parse_bool(@force)
end
def import!
if git_repo?
import_from_git
else
import_from_files
end
end
def import_from_files
@dir = get_absolute_repo_path
verify_path!(@dir)
return parse_files!
end
def import_from_git
# Check out the community templates to a temp location
@dir = Dir.mktmpdir
begin
gitrepo = Git.clone(@repo, @dir)
branch = @branch ? @branch : get_default_branch(gitrepo)
gitrepo.checkout(branch) if branch
return parse_files!
ensure
FileUtils.remove_entry_secure(@dir) if File.exist?(@dir)
end
end
def parse_files!
result_lines = []
# Build a list of ERB files to parse
Dir["#{@dir}#{@dirname}/**/*.erb"].each do |template|
text = File.read(template)
result_lines << 'Parsing: ' + template.gsub(/#{@dir}#{@dirname}/, '') if @verbose
metadata = parse_metadata(text)
metadata['associate'] = @associate
# Get the name and filter
filename = template.split('/').last
title = filename.split('.').first
name = metadata['name'] || title
name = auto_prefix(name)
if @filter
matching = name.match(/#{@filter}/i)
matching = !matching if @negate
next unless matching
end
begin
# Expects a return of { :diff, :status, :result, :errors }
data = if metadata['model'].present?
metadata['model'].constantize.import!(name, text, metadata, @force)
else
# For backwards-compat before "model" metadata was added
case metadata['kind']
when 'ptable'
Ptable.import!(name, text, metadata, @force)
when 'job_template'
# TODO: update REX templates to have `model` and delete this
update_job_template(name, text)
else
ProvisioningTemplate.import!(name, text, metadata, @force)
end
end
if data[:diff].nil? && data[:old].present? && data[:new].present?
data[:diff] = calculate_diff(data[:old], data[:new])
end
if @verbose
result_lines << data[:result]
result_lines << data[:diff] unless data[:diff].nil?
end
result_lines << status_to_text(data[:status], name)
result_lines << data[:errors] unless data[:errors].empty?
rescue MissingKindError
result_lines << " Skipping: '#{name}' - No template kind or model detected"
next
rescue NoKindError
result_lines << " Skipping: '#{name}' - Unknown template kind '#{metadata['kind']}'"
next
rescue NameError
result_lines << " Skipping: '#{name}' - Unknown template model '#{metadata['model']}'"
next
end
end
result_lines
end
def auto_prefix(name)
name.start_with?(@prefix) ? name : [@prefix, name].compact.join
end
def calculate_diff(old, new)
if old != new
Diffy::Diff.new(old, new, :include_diff_info => true).to_s(:color)
else
nil
end
end
def parse_metadata(text)
# Pull out the first erb comment only - /m is for a multiline regex
extracted = text.match(/<%\#[\t a-z0-9=:]*(.+?).-?%>/m)
extracted.nil? ? {} : YAML.load(extracted[1])
end
def update_job_template(name, text)
file = name.gsub(/^#{@prefix}/, '')
puts 'Deprecation warning: JobTemplate support is moving to the Remote Execution plugin'
puts "- please add 'model: JobTemplate' to the metadata in '#{file}' to call the right method"
unless defined?(JobTemplate)
return {
:status => false,
:result => 'Skipping job template import, remote execution plugin is not installed.'
}
end
template = JobTemplate.import(
text.sub(/^name: .*$/, "name: #{name}"),
:update => true
)
c_or_u = template.new_record? ? 'Created' : 'Updated'
id_string = ('id' + template.id) rescue ''
if template.template != template.template_was
diff = Diffy::Diff.new(
template.template_was,
template.template,
:include_diff_info => true
).to_s(:color)
end
result = " #{c_or_u} Template #{id_string}:#{name}"
{ :diff => diff, :status => template.save, :result => result }
end
def purge!
clause = "name #{@negate ? 'NOT ' : ''}LIKE ?"
ProvisioningTemplate.where(clause, "#{@prefix}%").each do |template|
puts template if @verbose
template.destroy
end
end # :purge
private
def parse_bool(bool_name)
bool_name.is_a?(String) ? bool_name != 'false' : bool_name
end
def status_to_text(status, name)
msg = "#{name} - import "
msg << if status
"success"
else
'failure'
end
msg
end
end
end