foreman_templates 6.0.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/api/v2/template_controller.rb +10 -8
- data/app/controllers/concerns/foreman/controller/parameters/template_params.rb +19 -2
- data/app/services/foreman_templates/action.rb +2 -11
- data/app/services/foreman_templates/export_result.rb +41 -0
- data/app/services/foreman_templates/parse_result.rb +92 -0
- data/app/services/foreman_templates/template_exporter.rb +73 -25
- data/app/services/foreman_templates/template_importer.rb +88 -65
- data/lib/foreman_templates/version.rb +1 -1
- data/lib/tasks/foreman_templates_tasks.rake +8 -9
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0c518e8c2822c6112f13654488a324eb9c2918a
|
|
4
|
+
data.tar.gz: b32fab2dde41371d5367c8d95db70fd2eb85d0ab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b647c76ec12f0262f6dc95703487fee408ab094bb918b77f0df6141080cb90b3373cb7d4c27620488b75aa66c0d39450c033ed9ae9145e2cf023656189c3ee18
|
|
7
|
+
data.tar.gz: '0981be0b744c1a1573fdf0c8c7cec0f82357679cb3873d7ff7264a5af6cc1348e8b8d38da4b9ea5e073b82366e2a79ca284f8b0a4e4037a9951b816c5d692902'
|
|
@@ -9,7 +9,6 @@ module Api
|
|
|
9
9
|
param :filter, String, :required => false, :desc => N_("Export templates with names matching this regex (case-insensitive; snippets are not filtered).")
|
|
10
10
|
param :negate, :bool, :required => false, :desc => N_("Negate the prefix (for purging).")
|
|
11
11
|
param :dirname, String, :required => false, :desc => N_("The directory within Git repo containing the templates")
|
|
12
|
-
param :verbose, :bool, :required => false, :desc => N_("Set verbosity of import")
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
api :POST, "/templates/import/", N_("Initiate Import")
|
|
@@ -17,21 +16,24 @@ module Api
|
|
|
17
16
|
param :associate, Setting::TemplateSync.associate_types.keys, :required => false, :desc => N_("Associate to OS's, Locations & Organizations. Options are: always, new or never.")
|
|
18
17
|
param :force, :bool, :required => false, :desc => N_("Update templates that are locked")
|
|
19
18
|
param :lock, :bool, :required => false, :desc => N_("Lock imported templates")
|
|
19
|
+
param :verbose, :bool, :required => false, :desc => N_("Show template diff in response")
|
|
20
20
|
param_group :foreman_template_sync_params
|
|
21
|
+
param_group :taxonomies, ::Api::V2::BaseController
|
|
21
22
|
def import
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
verbose = params['verbose']
|
|
24
|
+
@result = ForemanTemplates::TemplateImporter.new(template_import_params).import!
|
|
25
|
+
render :json => { :message => { :templates => @result[:results].map { |res| res.to_h(verbose) },
|
|
26
|
+
:repo => @result[:repo],
|
|
27
|
+
:branch => @result[:branch] } }
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
api :POST, "/templates/export", N_("Initiate Export")
|
|
27
31
|
param :metadata_export_mode, Setting::TemplateSync.metadata_export_mode_types.keys, :required => false, :desc => N_("Specify how to handle metadata")
|
|
28
32
|
param_group :foreman_template_sync_params
|
|
33
|
+
param_group :taxonomies, ::Api::V2::BaseController
|
|
29
34
|
def export
|
|
30
|
-
ForemanTemplates::TemplateExporter.new(template_export_params).export!
|
|
31
|
-
render :json => { :message =>
|
|
32
|
-
rescue StandardError => e
|
|
33
|
-
logger.debug e
|
|
34
|
-
render :json => { :message => (_('Something went wrong during export: %s') % e.message) }, :status => :internal_server_error
|
|
35
|
+
@result = ForemanTemplates::TemplateExporter.new(template_export_params).export!
|
|
36
|
+
render :json => { :message => @result.to_h }, :status => @result.exported ? 200 : 500
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
end
|
|
@@ -3,6 +3,7 @@ module Foreman
|
|
|
3
3
|
module Parameters
|
|
4
4
|
module TemplateParams
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
|
+
include Foreman::Controller::Parameters::Taxonomix
|
|
6
7
|
|
|
7
8
|
class_methods do
|
|
8
9
|
def filter_params_list
|
|
@@ -25,11 +26,27 @@ module Foreman
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def template_import_params
|
|
28
|
-
self.class.template_params_filter(self.class.extra_import_params)
|
|
29
|
+
add_taxonomy_params(self.class.template_params_filter(self.class.extra_import_params)
|
|
30
|
+
.filter_params(params, parameter_filter_context, :none).with_indifferent_access)
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def template_export_params
|
|
32
|
-
self.class.template_params_filter(self.class.extra_export_params)
|
|
34
|
+
add_taxonomy_params(self.class.template_params_filter(self.class.extra_export_params)
|
|
35
|
+
.filter_params(params, parameter_filter_context, :none).with_indifferent_access)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def organization_params
|
|
39
|
+
self.class.organization_params_filter(Hash).filter_params(params, parameter_filter_context, :none)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def location_params
|
|
43
|
+
self.class.location_params_filter(Hash).filter_params(params, parameter_filter_context, :none)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def add_taxonomy_params(params)
|
|
49
|
+
params.merge(:organization_params => organization_params.to_h).merge(:location_params => location_params.to_h)
|
|
33
50
|
end
|
|
34
51
|
end
|
|
35
52
|
end
|
|
@@ -19,20 +19,11 @@ module ForemanTemplates
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def initialize(args = {})
|
|
22
|
+
@taxonomies = { :organizations => args[:organization_params] || {},
|
|
23
|
+
:locations => args[:location_params] || {} }
|
|
22
24
|
assign_attributes args
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
def get_default_branch(repo)
|
|
26
|
-
branch_names = repo.branches.map(&:name).uniq
|
|
27
|
-
|
|
28
|
-
# Always use develop on Foreman-nightly, if present, or else relevant stable branch
|
|
29
|
-
target = SETTINGS[:version].tag == 'develop' ? 'develop' : "#{SETTINGS[:version].short}-stable"
|
|
30
|
-
return target if branch_names.include?(target)
|
|
31
|
-
|
|
32
|
-
# stay on default branch as fallback
|
|
33
|
-
nil
|
|
34
|
-
end
|
|
35
|
-
|
|
36
27
|
def git_repo?
|
|
37
28
|
@repo.start_with?('http://', 'https://', 'git://', 'ssh://', 'git+ssh://', 'ssh+git://')
|
|
38
29
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module ForemanTemplates
|
|
2
|
+
class ExportResult
|
|
3
|
+
attr_accessor :exported, :error, :warning
|
|
4
|
+
|
|
5
|
+
def initialize(repo, branch, git_user)
|
|
6
|
+
@repo = repo
|
|
7
|
+
@branch = branch
|
|
8
|
+
@git_user = git_user
|
|
9
|
+
@error = nil
|
|
10
|
+
@warning = nil
|
|
11
|
+
@templates = []
|
|
12
|
+
@exported = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add_exported_templates(templates)
|
|
16
|
+
@templates.concat templates
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_h
|
|
20
|
+
{ :error => @error,
|
|
21
|
+
:warning => @warning,
|
|
22
|
+
:repo => @repo,
|
|
23
|
+
:branch => @branch,
|
|
24
|
+
:git_user => @git_user,
|
|
25
|
+
:templates => dumped_files_result }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def dumped_files_result
|
|
31
|
+
@templates.map { |template| to_template_h template }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_template_h(template)
|
|
35
|
+
{ :id => template.id,
|
|
36
|
+
:name => template.name,
|
|
37
|
+
:exported => @exported,
|
|
38
|
+
:type => template.class.name.underscore }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module ForemanTemplates
|
|
2
|
+
class ParseResult
|
|
3
|
+
attr_accessor :name, :template
|
|
4
|
+
attr_reader :imported, :diff, :exception, :additional_errors
|
|
5
|
+
|
|
6
|
+
def initialize(template_file)
|
|
7
|
+
@template_file = template_file.split('/').last
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_h(verbose = false)
|
|
11
|
+
res = {
|
|
12
|
+
:name => @name,
|
|
13
|
+
:id => @template.present? ? @template.id : nil,
|
|
14
|
+
:changed => changed?,
|
|
15
|
+
:imported => @imported,
|
|
16
|
+
:additional_errors => @additional_errors,
|
|
17
|
+
:exception => @exception ? @exception.message : nil,
|
|
18
|
+
:validation_errors => errors.to_h,
|
|
19
|
+
:file => @template_file,
|
|
20
|
+
:type => @template.present? ? @template.class.name.underscore : nil
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# false comes as a string when using rake tasks
|
|
24
|
+
res[:diff] = @diff if verbose && verbose != 'false'
|
|
25
|
+
res
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def errors
|
|
29
|
+
@template ? @template.errors : nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def corrupted_metadata
|
|
33
|
+
generic_error "Failed to parse metadata"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def matching_filter
|
|
37
|
+
generic_error "Skipping, 'name' filtered out based on 'filter' and 'negate' settings"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def no_metadata_name
|
|
41
|
+
generic_error "No 'name' found in metadata"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def missing_model
|
|
45
|
+
generic_error "No 'model' found in metadata"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def generic_error(additional_msg)
|
|
49
|
+
@imported = false
|
|
50
|
+
@additional_errors = additional_msg
|
|
51
|
+
Logging.logger('app').debug "Error in '#{@template_file}': #{additional_msg}"
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def check_for_errors
|
|
56
|
+
@imported = @template.errors.blank?
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def add_exception(exception)
|
|
61
|
+
@imported = false
|
|
62
|
+
@exception = exception
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def name_error(exception, template_type)
|
|
67
|
+
@imported = false
|
|
68
|
+
@exception = exception
|
|
69
|
+
@additional_errors = "Template type #{template_type} was not found, are you missing a plugin?"
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def determine_result_diff
|
|
74
|
+
return if @template.nil? || !@template.template_changed?
|
|
75
|
+
template_was = @template.template_was
|
|
76
|
+
template_is = @template.template
|
|
77
|
+
@diff = calculate_diff(template_was, template_is)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def changed?
|
|
81
|
+
@diff.present?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def calculate_diff(old, new)
|
|
85
|
+
if old.present? && new.present? && old != new
|
|
86
|
+
Diffy::Diff.new(old, new, :include_diff_info => true).to_s(:color)
|
|
87
|
+
else
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -7,61 +7,69 @@ module ForemanTemplates
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def export!
|
|
10
|
+
@export_result = ExportResult.new(@repo, @branch, foreman_git_user)
|
|
10
11
|
if git_repo?
|
|
11
12
|
export_to_git
|
|
12
13
|
else
|
|
13
14
|
export_to_files
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
return
|
|
17
|
+
return @export_result
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def export_to_files
|
|
20
21
|
@dir = get_absolute_repo_path
|
|
21
22
|
verify_path!(@dir)
|
|
22
23
|
dump_files!
|
|
24
|
+
@export_result.exported = true
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def export_to_git
|
|
26
28
|
@dir = Dir.mktmpdir
|
|
27
|
-
|
|
29
|
+
return @export_result if branch_missing?
|
|
28
30
|
git_repo = Git.clone(@repo, @dir)
|
|
29
|
-
logger.debug "cloned #{@repo} to #{@dir}"
|
|
30
|
-
branch = @branch ? @branch : get_default_branch(git_repo)
|
|
31
|
-
# either checkout to existing or create a new one and checkout afterwards
|
|
32
|
-
if branch
|
|
33
|
-
if git_repo.is_branch?(branch)
|
|
34
|
-
git_repo.checkout(branch)
|
|
35
|
-
else
|
|
36
|
-
git_repo.branch(branch).checkout
|
|
37
|
-
if git_repo.is_remote_branch?(branch) # if we work with remote branch we need to sync it first
|
|
38
|
-
git_repo.reset_hard("origin/#{branch}")
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
31
|
+
logger.debug "cloned '#{@repo}' to '#{@dir}'"
|
|
42
32
|
|
|
33
|
+
setup_git_branch git_repo
|
|
43
34
|
dump_files!
|
|
44
35
|
git_repo.add
|
|
45
36
|
|
|
46
37
|
status = git_repo.status
|
|
47
38
|
if status.added.any? || status.changed.any? || status.deleted.any? || status.untracked.any?
|
|
48
|
-
|
|
49
|
-
git_repo.commit "Templates export made by Foreman user #{User.current.try(:login) || User::ANONYMOUS_ADMIN}"
|
|
50
|
-
|
|
51
|
-
logger.debug "pushing to branch #{branch} at origin #{@repo}"
|
|
39
|
+
git_repo.commit "Templates export made by Foreman user #{foreman_git_user}"
|
|
52
40
|
git_repo.push 'origin', branch
|
|
41
|
+
@export_result.exported = true
|
|
53
42
|
else
|
|
54
|
-
|
|
43
|
+
@export_result.warning = 'No change detected, skipping the commit and push'
|
|
55
44
|
end
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
@export_result.error = e.message
|
|
56
47
|
ensure
|
|
57
48
|
FileUtils.remove_entry_secure(@dir) if File.exist?(@dir)
|
|
49
|
+
@export_result
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def setup_git_branch(git_repo)
|
|
53
|
+
logger.debug "checking out branch '#{@branch}'"
|
|
54
|
+
if git_repo.is_branch?(@branch)
|
|
55
|
+
git_repo.checkout(@branch)
|
|
56
|
+
else
|
|
57
|
+
git_repo.branch(@branch).checkout
|
|
58
|
+
if git_repo.is_remote_branch?(@branch) # if we work with remote branch we need to sync it first
|
|
59
|
+
git_repo.reset_hard("origin/#{@branch}")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def foreman_git_user
|
|
65
|
+
User.current.try(:login) || User::ANONYMOUS_ADMIN
|
|
58
66
|
end
|
|
59
67
|
|
|
60
68
|
def dump_files!
|
|
61
|
-
|
|
69
|
+
templates = templates_to_dump
|
|
70
|
+
templates.map do |template|
|
|
62
71
|
current_dir = get_dump_dir(template)
|
|
63
72
|
FileUtils.mkdir_p current_dir
|
|
64
|
-
|
|
65
73
|
filename = File.join(current_dir, get_template_filename(template))
|
|
66
74
|
File.open(filename, 'w+') do |file|
|
|
67
75
|
logger.debug "Writing to file #{filename}"
|
|
@@ -69,6 +77,7 @@ module ForemanTemplates
|
|
|
69
77
|
logger.debug "finished writing #{bytes}"
|
|
70
78
|
end
|
|
71
79
|
end
|
|
80
|
+
@export_result.add_exported_templates templates
|
|
72
81
|
end
|
|
73
82
|
|
|
74
83
|
def get_template_filename(template)
|
|
@@ -77,13 +86,13 @@ module ForemanTemplates
|
|
|
77
86
|
|
|
78
87
|
def get_dump_dir(template)
|
|
79
88
|
kind = template.respond_to?(:template_kind) ? template.template_kind.try(:name) || 'snippet' : nil
|
|
80
|
-
template_class_dir = template.model_name.
|
|
81
|
-
template_class_dir
|
|
89
|
+
template_class_dir = template.model_name.plural
|
|
90
|
+
template_class_dir = 'partition_tables_templates' if template_class_dir == 'ptables'
|
|
82
91
|
File.join(@dir, dirname.to_s, template_class_dir, kind.to_s)
|
|
83
92
|
end
|
|
84
93
|
|
|
85
94
|
def templates_to_dump
|
|
86
|
-
base =
|
|
95
|
+
base = find_templates
|
|
87
96
|
if filter.present?
|
|
88
97
|
method = negate ? :reject : :select
|
|
89
98
|
base.public_send(method) { |template| template.name.match(/#{filter}/i) }
|
|
@@ -92,6 +101,14 @@ module ForemanTemplates
|
|
|
92
101
|
end
|
|
93
102
|
end
|
|
94
103
|
|
|
104
|
+
def branch_missing?
|
|
105
|
+
if @branch.blank?
|
|
106
|
+
@export_result.error = "Please specify a branch when exporting into a git repo"
|
|
107
|
+
return true
|
|
108
|
+
end
|
|
109
|
+
false
|
|
110
|
+
end
|
|
111
|
+
|
|
95
112
|
# * refresh - template.to_erb stripping existing metadata,
|
|
96
113
|
# * remove - just template.template with stripping existing metadata,
|
|
97
114
|
# * keep - taking the whole template.template
|
|
@@ -107,5 +124,36 @@ module ForemanTemplates
|
|
|
107
124
|
raise "Unknown metadata export mode #{@metadata_export_mode}"
|
|
108
125
|
end
|
|
109
126
|
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def find_templates
|
|
131
|
+
@taxonomies.values.all?(&:empty?) ? Template.all : find_taxed_templates
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def find_taxed_templates
|
|
135
|
+
location_ids = taxes_ids('location')
|
|
136
|
+
organization_ids = taxes_ids('organization')
|
|
137
|
+
if location_ids.empty?
|
|
138
|
+
templates_query(organization_ids)
|
|
139
|
+
elsif organization_ids.empty?
|
|
140
|
+
templates_query(location_ids)
|
|
141
|
+
else
|
|
142
|
+
templates_query(organization_ids) & templates_query(location_ids)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def templates_query(tax_ids)
|
|
147
|
+
Template.where(:id => TaxableTaxonomy.where(:taxonomy_id => tax_ids,
|
|
148
|
+
:taxable_type => Template.subclasses.map(&:name)).pluck(:taxable_id))
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def taxes_ids(tax_type)
|
|
152
|
+
tax_type.capitalize.constantize
|
|
153
|
+
.where(:name => @taxonomies[tax_type.pluralize.to_sym]["#{tax_type}_names".to_sym])
|
|
154
|
+
.pluck(:id)
|
|
155
|
+
.concat(@taxonomies[tax_type.pluralize.to_sym]["#{tax_type}_ids".to_sym] || [])
|
|
156
|
+
.uniq
|
|
157
|
+
end
|
|
110
158
|
end
|
|
111
159
|
end
|
|
@@ -11,6 +11,7 @@ module ForemanTemplates
|
|
|
11
11
|
@verbose = parse_bool(@verbose)
|
|
12
12
|
@force = parse_bool(@force)
|
|
13
13
|
@lock = parse_bool(@lock)
|
|
14
|
+
@result_lines = []
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def import!
|
|
@@ -24,7 +25,7 @@ module ForemanTemplates
|
|
|
24
25
|
def import_from_files
|
|
25
26
|
@dir = get_absolute_repo_path
|
|
26
27
|
verify_path!(@dir)
|
|
27
|
-
|
|
28
|
+
parse_files!
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def import_from_git
|
|
@@ -32,95 +33,117 @@ module ForemanTemplates
|
|
|
32
33
|
@dir = Dir.mktmpdir
|
|
33
34
|
|
|
34
35
|
begin
|
|
36
|
+
logger.debug "cloned '#{@repo}' to '#{@dir}'"
|
|
35
37
|
gitrepo = Git.clone(@repo, @dir)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
if @branch
|
|
39
|
+
logger.debug "checking out branch '#{@branch}'"
|
|
40
|
+
gitrepo.checkout(@branch)
|
|
41
|
+
end
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
parse_files!
|
|
40
44
|
ensure
|
|
41
45
|
FileUtils.remove_entry_secure(@dir) if File.exist?(@dir)
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def parse_files!
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Dir["#{@dir}#{@dirname}/**/*.erb"].each do |template|
|
|
50
|
-
text = File.read(template)
|
|
51
|
-
result_lines << 'Parsing: ' + template.gsub(/#{@dir}#{@dirname}/, '') if @verbose
|
|
50
|
+
Dir["#{@dir}#{@dirname}/**/*.erb"].each do |template_file|
|
|
51
|
+
logger.debug 'Parsing: ' + template_file.gsub(/#{@dir}#{@dirname}/, '')
|
|
52
|
+
parse_result = ParseResult.new(template_file)
|
|
52
53
|
|
|
54
|
+
text = File.read(template_file)
|
|
53
55
|
metadata = Template.parse_metadata(text)
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
name =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
matching = !matching if @negate
|
|
61
|
-
unless matching
|
|
62
|
-
result_lines << "Skipping template '#{name}' since it's name is matching filter condition" if @verbose
|
|
63
|
-
next
|
|
64
|
-
end
|
|
65
|
-
end
|
|
57
|
+
next if metadata_corrupted?(metadata, parse_result)
|
|
58
|
+
|
|
59
|
+
next unless (name = auto_prefix_name(metadata, parse_result))
|
|
60
|
+
|
|
61
|
+
next if filtered_out name, parse_result
|
|
66
62
|
|
|
67
|
-
options = { :force => @force, :associate => @associate, :lock => @lock }
|
|
68
|
-
template_type = 'Unknown template type'
|
|
69
63
|
begin
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
data = {}
|
|
80
|
-
if template.template_changed?
|
|
81
|
-
data[:old] = template.template_was
|
|
82
|
-
data[:new] = template.template
|
|
83
|
-
if data[:diff].nil? && data[:old].present? && data[:new].present?
|
|
84
|
-
data[:diff] = calculate_diff(data[:old], data[:new])
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
if options[:force]
|
|
89
|
-
template.ignore_locking { template.save! }
|
|
90
|
-
else
|
|
91
|
-
template.save!
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
template_type = template.class.model_name.human
|
|
95
|
-
data[:status] = template.errors.blank? ? "#{template_type} '#{name}' import successful" : "#{template_type} '#{name}' import failed"
|
|
96
|
-
data[:errors] = template.errors.full_messages
|
|
97
|
-
|
|
98
|
-
if @verbose
|
|
99
|
-
result_lines << data[:diff] unless data[:diff].nil?
|
|
100
|
-
end
|
|
101
|
-
result_lines << data[:status]
|
|
102
|
-
result_lines << data[:errors] unless data[:errors].empty?
|
|
64
|
+
next unless (template_type = template_model(metadata, parse_result))
|
|
65
|
+
template = template_type.import_without_save(name, text, import_options)
|
|
66
|
+
parse_result.template = template
|
|
67
|
+
parse_result.determine_result_diff
|
|
68
|
+
|
|
69
|
+
save_template template, @force
|
|
70
|
+
@result_lines << parse_result.check_for_errors
|
|
71
|
+
rescue NameError => e
|
|
72
|
+
@result_lines << parse_result.name_error(e, metadata['model'])
|
|
103
73
|
rescue => e
|
|
104
|
-
|
|
105
|
-
result_lines << "#{template_type} '#{name}' import failed - #{e.message}"
|
|
106
|
-
next
|
|
74
|
+
@result_lines << parse_result.add_exception(e)
|
|
107
75
|
end
|
|
108
76
|
end
|
|
109
|
-
result_lines
|
|
77
|
+
{ :results => @result_lines, :repo => @repo, :branch => @branch }
|
|
110
78
|
end
|
|
111
79
|
|
|
112
|
-
def
|
|
113
|
-
|
|
80
|
+
def import_options
|
|
81
|
+
{ :force => @force,
|
|
82
|
+
:associate => @associate,
|
|
83
|
+
:lock => @lock,
|
|
84
|
+
:organization_params => @organizations,
|
|
85
|
+
:location_params => @locations }
|
|
114
86
|
end
|
|
115
87
|
|
|
116
|
-
def
|
|
117
|
-
if
|
|
118
|
-
|
|
88
|
+
def template_model(metadata, parse_result)
|
|
89
|
+
if metadata.key?('model')
|
|
90
|
+
metadata['model'].constantize
|
|
119
91
|
else
|
|
92
|
+
@result_lines << parse_result.missing_model
|
|
120
93
|
nil
|
|
121
94
|
end
|
|
122
95
|
end
|
|
123
96
|
|
|
97
|
+
def save_template(template, force)
|
|
98
|
+
result = nil
|
|
99
|
+
if force
|
|
100
|
+
result = template.ignore_locking { template.save }
|
|
101
|
+
else
|
|
102
|
+
result = template.save
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if result
|
|
106
|
+
logger.debug 'saved'
|
|
107
|
+
else
|
|
108
|
+
logger.error "couldn't save the template because of: #{template.errors.full_messages.join(', ')}"
|
|
109
|
+
end
|
|
110
|
+
result
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def filtered_out(name, parse_result)
|
|
114
|
+
if @filter && !name_matching_filter?(name)
|
|
115
|
+
@result_lines << parse_result.matching_filter
|
|
116
|
+
true
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def metadata_corrupted?(metadata, parse_result)
|
|
121
|
+
if metadata.empty?
|
|
122
|
+
@result_lines << parse_result.corrupted_metadata
|
|
123
|
+
return true
|
|
124
|
+
end
|
|
125
|
+
false
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def name_matching_filter?(name)
|
|
129
|
+
matching = name.match(/#{@filter}/i)
|
|
130
|
+
return !matching if @negate
|
|
131
|
+
matching
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def auto_prefix_name(metadata, parse_result)
|
|
135
|
+
unless (name = metadata['name'])
|
|
136
|
+
@result_lines << parse_result.no_metadata_name
|
|
137
|
+
return nil
|
|
138
|
+
end
|
|
139
|
+
parse_result.name = auto_prefix(name)
|
|
140
|
+
auto_prefix(name)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def auto_prefix(name)
|
|
144
|
+
name.start_with?(@prefix) ? name : [@prefix, name].compact.join
|
|
145
|
+
end
|
|
146
|
+
|
|
124
147
|
def purge!
|
|
125
148
|
clause = "name #{@negate ? 'NOT ' : ''}LIKE ?"
|
|
126
149
|
ProvisioningTemplate.where(clause, "#{@prefix}%").each do |template|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
require 'pp'
|
|
1
2
|
# Tasks
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
2
4
|
namespace :templates do
|
|
3
5
|
desc 'Import templates according to settings'
|
|
4
6
|
task :import => :environment do
|
|
@@ -15,11 +17,11 @@ namespace :templates do
|
|
|
15
17
|
# * filter => Import names matching this regex (case-insensitive; snippets are not filtered)
|
|
16
18
|
# * associate => Associate to OS's, Locations & Organizations. Options are: always, new or never [new]
|
|
17
19
|
# * lock => Lock imported templates [false]
|
|
18
|
-
|
|
19
20
|
User.current = User.anonymous_admin
|
|
21
|
+
verbose = ENV['verbose']
|
|
20
22
|
|
|
21
23
|
results = ForemanTemplates::TemplateImporter.new({
|
|
22
|
-
verbose:
|
|
24
|
+
verbose: verbose,
|
|
23
25
|
repo: ENV['repo'],
|
|
24
26
|
branch: ENV['branch'],
|
|
25
27
|
prefix: ENV['prefix'],
|
|
@@ -29,35 +31,31 @@ namespace :templates do
|
|
|
29
31
|
lock: ENV['lock'],
|
|
30
32
|
}).import!
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
pp(results.map { |result| result.to_h(verbose) })
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
task :sync => :import
|
|
36
|
-
|
|
37
38
|
desc 'Export templates according to settings'
|
|
38
39
|
task :export => :environment do
|
|
39
40
|
ActiveSupport::Deprecation.warn "You are using a deprecated behavior, 'rake templates:export' will be removed in a future version. Please use appropriate API endpoint for this functionality"
|
|
40
41
|
User.current = User.anonymous_admin
|
|
41
42
|
|
|
42
|
-
ForemanTemplates::TemplateExporter.new({
|
|
43
|
-
verbose: ENV['verbose'],
|
|
43
|
+
result = ForemanTemplates::TemplateExporter.new({
|
|
44
44
|
repo: ENV['repo'],
|
|
45
45
|
branch: ENV['branch'],
|
|
46
46
|
prefix: ENV['prefix'],
|
|
47
47
|
dirname: ENV['dirname'],
|
|
48
48
|
filter: ENV['filter'],
|
|
49
|
-
# associate: ENV['associate'],
|
|
50
49
|
metadata_export_mode: ENV['metadata_export_mode'],
|
|
51
50
|
}).export!
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
pp result
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
desc 'Purge unwanted templates from foreman'
|
|
57
56
|
task :purge => :environment do
|
|
58
57
|
ActiveSupport::Deprecation.warn "You are using a deprecated behavior, 'rake templates:purge' will be removed in a future version. Please use appropriate API endpoint for this functionality"
|
|
59
58
|
User.current = User.anonymous_admin
|
|
60
|
-
|
|
61
59
|
ForemanTemplates::TemplateImporter.new({
|
|
62
60
|
# * negate => negate query [false]
|
|
63
61
|
# * prefix => The string all templates to purge should ( or not ) begin with [Community ]
|
|
@@ -75,6 +73,7 @@ namespace :templates do
|
|
|
75
73
|
puts 'Clean up finished, you can now remove the plugin from your system'
|
|
76
74
|
end
|
|
77
75
|
end
|
|
76
|
+
# rubocop:enable Metrics/BlockLength
|
|
78
77
|
|
|
79
78
|
# Tests
|
|
80
79
|
namespace :test do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_templates
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Greg Sutcliffe
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-05-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diffy
|
|
@@ -68,6 +68,8 @@ files:
|
|
|
68
68
|
- app/models/setting/template_sync.rb
|
|
69
69
|
- app/services/foreman_templates/action.rb
|
|
70
70
|
- app/services/foreman_templates/cleaner.rb
|
|
71
|
+
- app/services/foreman_templates/export_result.rb
|
|
72
|
+
- app/services/foreman_templates/parse_result.rb
|
|
71
73
|
- app/services/foreman_templates/template_exporter.rb
|
|
72
74
|
- app/services/foreman_templates/template_importer.rb
|
|
73
75
|
- config/routes.rb
|