foreman_templates 5.0.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e20876391aee6555fefc6346da21ac4dd54e9e9
4
- data.tar.gz: 1cee72d5d2ec7e8e509791f50f7bd7ae2d168b6c
3
+ metadata.gz: 3889bfa2270632f8e0bfacc4a35a1a85c3eca1e6
4
+ data.tar.gz: 797795544b68cbb4b2d408e8293e6689d1e3ff02
5
5
  SHA512:
6
- metadata.gz: 28f7610e8b1b4b3aa1cff6a228db20d3ac4d8835265dd6d646a50d0c3ebe536e2548bf3e9184e72af7096f92a40b226a46303f1c13aad1f322018c3260f4e7ef
7
- data.tar.gz: 7e492ef86762d568446c9c1859957be35d38af649b998352c64f10fb401172773e0e4af6ad2b1d7d8b24d0851f80781fffed89c90f77539d1c77bc390642a35c
6
+ metadata.gz: da4517d69b72c25c3065db6f0afba3621b6165c9c7a8e317a52e0a4c24a81b369fac520cc50ea102ea7accc8b9934452ef38b4a6e270e15d28c2a606e4105688
7
+ data.tar.gz: ae821ae58dedaaa29a83e41924b1ac30383c0d40e827c6d039397ac7bfd95f7923c94d418fcc1f89bcc59a020ae3b58b385db90bcb71353420384e8b31d4ba01
@@ -1,15 +1,17 @@
1
1
  module Api
2
2
  module V2
3
3
  class TemplateController < ::Api::V2::BaseController
4
-
5
4
  api :POST, "/template/import/", N_("Initiate Import")
6
- param :repo, String, :required => false, :desc => N_("Import templates from a different repo.")
5
+ param :verbose, :bool, :required => false, :desc => N_("Set verbosity of import")
6
+ param :repo, String, :required => false, :desc => N_("Override the default repo from settings.")
7
7
  param :branch, String, :required => false, :desc => N_("Branch in Git repo.")
8
8
  param :prefix, String, :required => false, :desc => N_("The string all imported templates should begin with.")
9
9
  param :dirname, String, :required => false, :desc => N_("The directory within the git tree containing the templates.")
10
- param :filter, String, :required => false, :desc => N_("Import names matching this regex (case-insensitive; snippets are not filtered).")
10
+ param :filter, String, :required => false, :desc => N_("Import templates with names matching this regex (case-insensitive; snippets are not filtered).")
11
11
  param :negate, :bool, :required => false, :desc => N_("Negate the prefix (for purging).")
12
- param :associate, String, :required => false, :desc => N_("Associate to OS's, Locations & Organizations. Options are: always, new or never.")
12
+ param :associate, Setting::TemplateSync.associate_types.keys, :required => false, :desc => N_("Associate to OS's, Locations & Organizations. Options are: always, new or never.")
13
+ param :force, :bool, :required => false, :desc => N_("Update templates that are locked")
14
+
13
15
  def import
14
16
  results = ForemanTemplates::TemplateImporter.new({
15
17
  verbose: params['verbose'],
@@ -20,8 +22,33 @@ module Api
20
22
  filter: params['filter'],
21
23
  associate: params['associate'],
22
24
  negate: params['negate'],
25
+ force: params['force']
23
26
  }).import!
24
- render :json => {:message => results}
27
+ render :json => { :message => results }
28
+ end
29
+
30
+ api :POST, "/template/export", N_("Initiate Export")
31
+ param :verbose, :bool, :required => false, :desc => N_("Set verbosity of export")
32
+ param :repo, String, :required => false, :desc => N_("Override the default repo from settings")
33
+ param :branch, String, :required => false, :desc => N_("Branch in Git repo.")
34
+ param :filter, String, :required => false, :desc => N_("Export templates with names matching this regex (case-insensitive; snippets are not filtered).")
35
+ param :negate, :bool, :required => false, :desc => N_("Negate the prefix (for purging).")
36
+ param :metadata_export_mode, Setting::TemplateSync.metadata_export_mode_types.keys, :required => false, :desc => N_("Specify how to handle metadata")
37
+ param :dir, String, :required => false, :desc => N_("The directory within Git repo")
38
+ def export
39
+ ForemanTemplates::TemplateExporter.new({
40
+ verbose: params['verbose'],
41
+ repo: params['repo'],
42
+ branch: params['branch'],
43
+ filter: params['filter'],
44
+ negate: params['negate'],
45
+ metadata_export_mode: params['metadata_export_mode'],
46
+ dir: params['dir']
47
+ }).export!
48
+ render :json => { :message => _('Success') }
49
+ rescue => e
50
+ logger.debug e
51
+ render :json => { :message => (_('Something went wrong during export: %s') % e.message) }, :status => 500
25
52
  end
26
53
  end
27
54
  end
@@ -1,60 +1,94 @@
1
- module ForemanTemplates::ProvisioningTemplateImport
2
- extend ActiveSupport::Concern
3
-
4
- module ClassMethods
5
- def import!(name, text, metadata)
6
- # Check for snippet type
7
- return import_snippet!(name, text) if metadata['snippet'] || metadata['kind'] == 'snippet'
8
-
9
- # Get template type
10
- kind = TemplateKind.find_by_name(metadata['kind'])
11
- raise NoKindError unless kind
12
-
13
- # Data
14
- template = ProvisioningTemplate.where(:name => name).first_or_initialize
15
- data = {
16
- :template => text,
17
- :snippet => false,
18
- :template_kind_id => kind.id
19
- }
20
- oses = map_metadata(metadata, 'oses')
21
- locations = map_metadata(metadata, 'locations')
22
- organizations = map_metadata(metadata, 'organizations')
23
-
24
- # Printout helpers
25
- c_or_u = template.new_record? ? 'Created' : 'Updated'
26
- id_string = ('id' + template.id) rescue ''
27
-
28
- if (metadata['associate'] == 'new' && template.new_record?) || (metadata['associate'] == 'always')
29
- data[:operatingsystem_ids] = oses.map(&:id)
30
- data[:location_ids] = locations.map(&:id)
31
- data[:organization_ids] = organizations.map(&:id)
1
+ module ForemanTemplates
2
+ module ProvisioningTemplateImport
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def import!(name, text, metadata, force = false)
7
+ # Check for snippet type
8
+ return import_snippet!(name, text, force) if metadata['snippet'] || metadata['kind'] == 'snippet'
9
+
10
+ # Get template type
11
+ kind = TemplateKind.find_by(name: metadata['kind'])
12
+ raise NoKindError unless kind
13
+
14
+ # Data
15
+ template = ProvisioningTemplate.where(:name => name).first_or_initialize
16
+ data = {
17
+ :template => text,
18
+ :snippet => false,
19
+ :template_kind_id => kind.id
20
+ }
21
+ oses = map_metadata(metadata, 'oses')
22
+ locations = map_metadata(metadata, 'locations')
23
+ organizations = map_metadata(metadata, 'organizations')
24
+
25
+ # Printout helpers
26
+ c_or_u = template.new_record? ? 'Creating' : 'Updating'
27
+ id_string = template.new_record? ? '' : "id #{template.id}"
28
+ if template.locked? && !template.new_record? && !force
29
+ return { :diff => nil,
30
+ :status => false,
31
+ :result => "Skipping Template #{id_string}:#{name} - template is locked" }
32
+ end
33
+
34
+ associate_metadata data, template, metadata, oses, organizations, locations
35
+
36
+ diff = nil
37
+ status = nil
38
+ if template_changed?(data, template)
39
+ diff = create_diff(data, template)
40
+ template.ignore_locking do
41
+ status = template.update_attributes(data)
42
+ end
43
+ result = build_associations_result c_or_u, id_string, name, oses, organizations, locations
44
+ else
45
+ status = true
46
+ result = " No change to Template #{id_string}:#{name}"
47
+ end
48
+
49
+ { :diff => diff, :status => status, :result => result, :errors => template.errors }
50
+ end
51
+
52
+ def associate_metadata(data, template, metadata, oses, organizations, locations)
53
+ if (metadata['associate'] == 'new' && template.new_record?) || (metadata['associate'] == 'always')
54
+ data[:operatingsystem_ids] = oses.map(&:id)
55
+ data[:location_ids] = locations.map(&:id)
56
+ data[:organization_ids] = organizations.map(&:id)
57
+ end
58
+ data
59
+ end
60
+
61
+ def build_associations_result(c_or_u, id_string, name, oses, organizations, locations)
62
+ res = " #{c_or_u} Template #{id_string}:#{name}"
63
+ res += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
64
+ res += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
65
+ res += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
66
+ res
67
+ end
68
+
69
+ def create_diff(data, template)
70
+ if template_content_changed?(template.template, data[:template])
71
+ Diffy::Diff.new(
72
+ template.template,
73
+ data[:template],
74
+ :include_diff_info => true
75
+ ).to_s(:color)
76
+ else
77
+ nil
78
+ end
79
+ end
80
+
81
+ def template_content_changed?(template_template, data_template)
82
+ template_template != data_template
83
+ end
84
+
85
+ def associations_changed?(data)
86
+ !(data[:operatingsystem_ids] || data[:location_ids] || data[:organization_ids]).nil?
32
87
  end
33
88
 
34
- if data[:template] != template.template
35
- diff = Diffy::Diff.new(
36
- template.template,
37
- data[:template],
38
- :include_diff_info => true
39
- ).to_s(:color)
40
- status = template.update_attributes(data)
41
- result = " #{c_or_u} Template #{id_string}:#{name}"
42
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
43
- result += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
44
- result += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
45
- elsif data[:operatingsystem_ids] || data[:location_ids] || data[:organization_ids]
46
- diff = nil
47
- status = template.update_attributes(data)
48
- result = " #{c_or_u} Template Associations #{id_string}:#{name}"
49
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
50
- result += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
51
- result += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
52
- else
53
- diff = nil
54
- status = true
55
- result = " No change to Template #{id_string}:#{name}"
89
+ def template_changed?(data, template)
90
+ template_content_changed?(template.template, data[:template]) || associations_changed?(data)
56
91
  end
57
- { :diff => diff, :status => status, :result => result }
58
92
  end
59
93
  end
60
94
  end
@@ -1,57 +1,89 @@
1
- module ForemanTemplates::PtableImport
2
- extend ActiveSupport::Concern
3
-
4
- module ClassMethods
5
- def import!(name, text, metadata)
6
- # Check for snippet type
7
- return import_snippet!(name, text) if metadata['snippet']
8
-
9
- # Data
10
- ptable = Ptable.where(:name => name).first_or_initialize
11
- data = {
12
- :layout => text
13
- }
14
- oses = map_metadata(metadata, 'oses')
15
- locations = map_metadata(metadata, 'locations')
16
- organizations = map_metadata(metadata, 'organizations')
17
-
18
- # Printout helpers
19
- c_or_u = ptable.new_record? ? 'Created' : 'Updated'
20
- id_string = ('id' + ptable.id) rescue ''
21
-
22
- if (metadata['associate'] == 'new' && ptable.new_record?) || (metadata['associate'] == 'always')
23
- data[:operatingsystem_ids] = oses.map(&:id)
24
- data[:os_family] = oses.map(&:family).uniq.first
25
- data[:location_ids] = locations.map(&:id)
26
- data[:organization_ids] = organizations.map(&:id)
1
+ module ForemanTemplates
2
+ module PtableImport
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def import!(name, text, metadata, force = false)
7
+ # Check for snippet type
8
+ return import_snippet!(name, text, force) if metadata['snippet']
9
+
10
+ # Data
11
+ ptable = Ptable.where(:name => name).first_or_initialize
12
+ data = {
13
+ :layout => text
14
+ }
15
+ oses = map_metadata(metadata, 'oses')
16
+ locations = map_metadata(metadata, 'locations')
17
+ organizations = map_metadata(metadata, 'organizations')
18
+
19
+ # Printout helpers
20
+ c_or_u = ptable.new_record? ? 'Creating' : 'Updating'
21
+ id_string = ptable.new_record? ? '' : "id #{ptable.id}"
22
+ if ptable.locked? && !ptable.new_record? && !force
23
+ return { :diff => nil,
24
+ :status => false,
25
+ :result => "Skipping Partition Table #{id_string}:#{name} - partition table is locked" }
26
+ end
27
+
28
+ associate_metadata data, ptable, metadata, oses, organizations, locations
29
+
30
+ diff = nil
31
+ status = nil
32
+ if ptable_changed?(data, ptable)
33
+ diff = create_diff(data, ptable)
34
+ ptable.ignore_locking do
35
+ status = ptable.update_attributes(data)
36
+ end
37
+ result = build_associations_result c_or_u, id_string, name, oses, organizations, locations
38
+ else
39
+ status = true
40
+ result = " No change to Ptable #{id_string}:#{name}"
41
+ end
42
+ { :diff => diff, :status => status, :result => result, :errors => ptable.errors }
43
+ end
44
+
45
+ def associate_metadata(data, ptable, metadata, oses, organizations, locations)
46
+ if (metadata['associate'] == 'new' && ptable.new_record?) || (metadata['associate'] == 'always')
47
+ data[:operatingsystem_ids] = oses.map(&:id)
48
+ data[:os_family] = oses.map(&:family).uniq.first
49
+ data[:location_ids] = locations.map(&:id)
50
+ data[:organization_ids] = organizations.map(&:id)
51
+ end
52
+ data
53
+ end
54
+
55
+ def ptable_content_changed?(data_layout, ptable_layout)
56
+ data_layout != ptable_layout
57
+ end
58
+
59
+ def associations_changed?(data)
60
+ !(data[:os_family] || data[:location_ids] || data[:organization_ids]).nil?
61
+ end
62
+
63
+ def create_diff(data, ptable)
64
+ if ptable_content_changed?(data[:layout], ptable.layout)
65
+ Diffy::Diff.new(
66
+ ptable.layout,
67
+ data[:layout],
68
+ :include_diff_info => true
69
+ ).to_s(:color)
70
+ else
71
+ nil
72
+ end
73
+ end
74
+
75
+ def build_associations_result(c_or_u, id_string, name, oses, organizations, locations)
76
+ res = " #{c_or_u} Ptable #{id_string}:#{name}"
77
+ res += "\n Operatingsystem Family:\n - #{oses.map(&:family).uniq.first}" unless oses.empty?
78
+ res += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
79
+ res += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
80
+ res += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
81
+ res
27
82
  end
28
83
 
29
- if data[:layout] != ptable.layout
30
- diff = Diffy::Diff.new(
31
- ptable.layout,
32
- data[:layout],
33
- :include_diff_info => true
34
- ).to_s(:color)
35
- status = ptable.update_attributes(data)
36
- result = " #{c_or_u} Ptable #{id_string}:#{name}"
37
- result += "\n Operatingsystem Family:\n - #{oses.map(&:family).uniq.first}" unless oses.empty?
38
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
39
- result += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
40
- result += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
41
- elsif data[:os_family] || data[:location_ids] || data[:organization_ids]
42
- diff = nil
43
- status = ptable.update_attributes(data)
44
- result = " #{c_or_u} Ptable Associations #{id_string}:#{name}"
45
- result += "\n Operatingsystem Family:\n - #{oses.map(&:family).uniq.first}" unless oses.empty?
46
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
47
- result += "\n Organizations Associations:\n - #{organizations.map(&:name).join("\n - ")}" unless organizations.empty?
48
- result += "\n Location Associations:\n - #{locations.map(&:name).join("\n - ")}" unless locations.empty?
49
- else
50
- diff = nil
51
- status = true
52
- result = " No change to Ptable #{id_string}:#{name}"
84
+ def ptable_changed?(data, ptable)
85
+ ptable_content_changed?(data[:layout], ptable.layout) || associations_changed?(data)
53
86
  end
54
- { :diff => diff, :status => status, :result => result }
55
87
  end
56
88
  end
57
89
  end
@@ -1,53 +1,64 @@
1
- module ForemanTemplates::TemplateImport
2
- extend ActiveSupport::Concern
1
+ module ForemanTemplates
2
+ module TemplateImport
3
+ extend ActiveSupport::Concern
3
4
 
4
- module ClassMethods
5
- def import_snippet!(name, text)
6
- # Data
7
- snippet = self.where(:name => name).first_or_initialize
8
- data = {
9
- :template => text,
10
- :snippet => true
11
- }
5
+ module ClassMethods
6
+ def import_snippet!(name, text, force = false)
7
+ # Data
8
+ snippet = self.where(:name => name).first_or_initialize
9
+ data = {
10
+ :template => text,
11
+ :snippet => true
12
+ }
12
13
 
13
- # Printout helpers
14
- c_or_u = snippet.new_record? ? 'Created' : 'Updated'
15
- id_string = ('id' + snippet.id) rescue ''
14
+ # Printout helpers
15
+ c_or_u = snippet.new_record? ? 'Creating' : 'Updating'
16
+ id_string = snippet.new_record? ? '' : "id #{snippet.id}"
16
17
 
17
- if data[:template] != snippet.template
18
- diff = Diffy::Diff.new(
19
- snippet.template,
20
- data[:template],
21
- :include_diff_info => true
22
- ).to_s(:color)
23
- status = snippet.update_attributes(data)
24
- result = " #{c_or_u} Snippet #{id_string}:#{name}"
25
- else
26
- diff = nil
27
- status = true
28
- result = " No change to Snippet #{id_string}:#{name}"
18
+ if snippet.locked? && !snippet.new_record? && !force
19
+ return { :diff => nil,
20
+ :status => false,
21
+ :result => "Skipping snippet #{id_string}:#{name} - template is locked" }
22
+ end
23
+
24
+ status = nil
25
+ if data[:template] != snippet.template
26
+ diff = Diffy::Diff.new(
27
+ snippet.template,
28
+ data[:template],
29
+ :include_diff_info => true
30
+ ).to_s(:color)
31
+ snippet.ignore_locking do
32
+ status = snippet.update_attributes(data)
33
+ end
34
+ result = " #{c_or_u} Snippet #{id_string}:#{name}"
35
+ else
36
+ diff = nil
37
+ status = true
38
+ result = " No change to Snippet #{id_string}:#{name}"
39
+ end
40
+ { :diff => diff, :status => status, :result => result, :errors => snippet.errors }
29
41
  end
30
- { :diff => diff, :status => status, :result => result }
31
- end
32
42
 
33
- def map_metadata(metadata, param)
34
- if metadata[param]
35
- case param
36
- when 'oses'
37
- metadata[param].map do |os|
38
- Operatingsystem.all.map { |db| db.to_label =~ /^#{os}/ ? db : nil }
39
- end.flatten.compact
40
- when 'locations'
41
- metadata[param].map do |loc|
42
- Location.all.map { |db| db.name =~ /^#{loc}/ ? db : nil }
43
- end.flatten.compact
44
- when 'organizations'
45
- metadata[param].map do |org|
46
- Organization.all.map { |db| db.name =~ /^#{org}/ ? db : nil }
47
- end.flatten.compact
43
+ def map_metadata(metadata, param)
44
+ if metadata[param]
45
+ case param
46
+ when 'oses'
47
+ metadata[param].map do |os|
48
+ Operatingsystem.all.map { |db| db.to_label =~ /^#{os}/ ? db : nil }
49
+ end.flatten.compact
50
+ when 'locations'
51
+ metadata[param].map do |loc|
52
+ User.current.my_locations.map { |db| db.name =~ /^#{loc}/ ? db : nil }
53
+ end.flatten.compact
54
+ when 'organizations'
55
+ metadata[param].map do |org|
56
+ User.current.my_organizations.map { |db| db.name =~ /^#{org}/ ? db : nil }
57
+ end.flatten.compact
58
+ end
59
+ else
60
+ []
48
61
  end
49
- else
50
- []
51
62
  end
52
63
  end
53
64
  end
@@ -1,54 +1,56 @@
1
- class Setting::TemplateSync < Setting
2
- def self.associate_types
3
- {
4
- 'always' => _('Always'),
5
- 'new' => _('New'),
6
- 'never' => _('Never')
7
- }
8
- end
9
-
10
- def self.metadata_export_mode_types
11
- {
12
- 'refresh' => _('Refresh'),
13
- 'keep' => _('Keep'),
14
- 'remove' => _('Remove')
15
- }
16
- end
17
-
18
-
19
- def self.load_defaults
20
- return unless super
21
-
22
- %w(template_sync_filter template_sync_branch).each { |s| Setting::BLANK_ATTRS << s }
1
+ class Setting
2
+ class TemplateSync < ::Setting
3
+ def self.associate_types
4
+ {
5
+ 'always' => _('Always'),
6
+ 'new' => _('New'),
7
+ 'never' => _('Never')
8
+ }
9
+ end
23
10
 
24
- self.transaction do
25
- [
26
- self.set('template_sync_verbose', N_('Choose verbosity for Rake task importing templates'), false, N_('Verbosity')),
27
- self.set('template_sync_associate', N_('Associate templates to OS'), 'new', N_('Associate'), nil, { :collection => Proc.new { self.associate_types } }),
28
- self.set('template_sync_prefix', N_('The string all imported templates should begin with'), "Community ", N_('Prefix')),
29
- self.set('template_sync_dirname', N_('The directory within the Git repo containing the templates'), '/', N_('Dirname')),
30
- self.set('template_sync_filter', N_('Import or export names matching this regex (case-insensitive; snippets are not filtered)'), nil, N_('Filter')),
31
- self.set('template_sync_repo', N_('Default Git repo to sync from'), 'https://github.com/theforeman/community-templates.git', N_('Repo')),
32
- self.set('template_sync_negate', N_('Negate the prefix (for purging) / filter (for importing/exporting)'), false, N_('Negate')),
33
- self.set('template_sync_branch', N_('Default branch in Git repo'), nil, N_('Branch')),
34
- self.set('template_sync_metadata_export_mode', N_('Default metadata export mode, refresh re-renders metadata, keep will keep existing metadata, remove exports template withou metadata'), 'refresh', N_('Metadata export mode'), nil, { :collection => Proc.new { self.metadata_export_mode_types } })
35
- ].compact.each { |s| self.create! s.update(:category => "Setting::TemplateSync") }
11
+ def self.metadata_export_mode_types
12
+ {
13
+ 'refresh' => _('Refresh'),
14
+ 'keep' => _('Keep'),
15
+ 'remove' => _('Remove')
16
+ }
36
17
  end
37
18
 
38
- true
39
- end
19
+ def self.load_defaults
20
+ return unless super
21
+
22
+ %w(template_sync_filter template_sync_branch).each { |s| Setting::BLANK_ATTRS << s }
23
+
24
+ self.transaction do
25
+ [
26
+ self.set('template_sync_verbose', N_('Choose verbosity for Rake task importing templates'), false, N_('Verbosity')),
27
+ self.set('template_sync_associate', N_('Associate templates to OS'), 'new', N_('Associate'), nil, { :collection => Proc.new { self.associate_types } }),
28
+ self.set('template_sync_prefix', N_('The string all imported templates should begin with'), "Community ", N_('Prefix')),
29
+ self.set('template_sync_dirname', N_('The directory within the Git repo containing the templates'), '/', N_('Dirname')),
30
+ self.set('template_sync_filter', N_('Import or export names matching this regex (case-insensitive; snippets are not filtered)'), nil, N_('Filter')),
31
+ self.set('template_sync_repo', N_('Default Git repo to sync from'), 'https://github.com/theforeman/community-templates.git', N_('Repo')),
32
+ self.set('template_sync_negate', N_('Negate the prefix (for purging) / filter (for importing/exporting)'), false, N_('Negate')),
33
+ self.set('template_sync_branch', N_('Default branch in Git repo'), nil, N_('Branch')),
34
+ self.set('template_sync_metadata_export_mode', N_('Default metadata export mode, refresh re-renders metadata, keep will keep existing metadata, remove exports template withou metadata'), 'refresh', N_('Metadata export mode'), nil, { :collection => Proc.new { self.metadata_export_mode_types } }),
35
+ self.set('template_sync_force', N_('Should importing overwrite locked templates?'), false, N_('Force import')),
36
+ ].compact.each { |s| self.create! s.update(:category => "Setting::TemplateSync") }
37
+ end
38
+
39
+ true
40
+ end
40
41
 
41
- def validate_template_sync_associate(record)
42
- values = record.class.associate_types.keys
43
- if record.value && !values.include?(record.value)
44
- record.errors[:base] << (_("template_sync_associate must be one of %s") % values.join(', '))
42
+ def validate_template_sync_associate(record)
43
+ values = record.class.associate_types.keys
44
+ if record.value && !values.include?(record.value)
45
+ record.errors[:base] << (_("template_sync_associate must be one of %s") % values.join(', '))
46
+ end
45
47
  end
46
- end
47
48
 
48
- def validate_template_sync_metadata_export_mode(record)
49
- values = record.class.metadata_export_mode_types.keys
50
- if record.value && !values.include?(record.value)
51
- record.errors[:base] << (_("template_sync_metadata_export_mode must be one of %s") % values.join(', '))
49
+ def validate_template_sync_metadata_export_mode(record)
50
+ values = record.class.metadata_export_mode_types.keys
51
+ if record.value && !values.include?(record.value)
52
+ record.errors[:base] << (_("template_sync_metadata_export_mode must be one of %s") % values.join(', '))
53
+ end
52
54
  end
53
55
  end
54
56
  end
@@ -14,7 +14,7 @@ module ForemanTemplates
14
14
  end
15
15
  end
16
16
 
17
- def repond_to_missing?(method, include_private = false)
17
+ def respond_to_missing?(method, include_private = false)
18
18
  self.class.setting_overrides.include?(method)
19
19
  end
20
20
 
@@ -1,3 +1,5 @@
1
+ require 'shellwords'
2
+
1
3
  module ForemanTemplates
2
4
  class TemplateExporter < Action
3
5
  def self.setting_overrides
@@ -43,7 +45,7 @@ module ForemanTemplates
43
45
 
44
46
  status = git_repo.status
45
47
  if status.added.any? || status.changed.any? || status.deleted.any? || status.untracked.any?
46
- logger.debug "committing changes in cloned repo"
48
+ logger.debug 'committing changes in cloned repo'
47
49
  git_repo.commit "Templates export made by Foreman user #{User.current.try(:login) || User::ANONYMOUS_ADMIN}"
48
50
 
49
51
  logger.debug "pushing to branch #{branch} at origin #{@repo}"
@@ -70,7 +72,7 @@ module ForemanTemplates
70
72
  end
71
73
 
72
74
  def get_template_filename(template)
73
- template.name.downcase.tr(' ', '_') + '.erb'
75
+ Shellwords.escape(template.name.downcase.tr(' /', '_') + '.erb')
74
76
  end
75
77
 
76
78
  def get_dump_dir(template)
@@ -105,6 +107,5 @@ module ForemanTemplates
105
107
  raise "Unknown metadata export mode #{@metadata_export_mode}"
106
108
  end
107
109
  end
108
-
109
110
  end
110
111
  end
@@ -1,24 +1,18 @@
1
- class NoKindError < Exception; end
2
- class MissingKindError < Exception; end
1
+ class NoKindError < RuntimeError; end
2
+ class MissingKindError < RuntimeError; end
3
3
 
4
4
  module ForemanTemplates
5
5
  class TemplateImporter < Action
6
6
  attr_accessor :metadata, :name, :text
7
7
 
8
8
  def self.setting_overrides
9
- super + %i(associate)
9
+ super + %i(associate force)
10
10
  end
11
11
 
12
12
  def initialize(args = {})
13
13
  super
14
- # Rake hands off strings, not booleans, and "false" is true...
15
- if @verbose.is_a?(String)
16
- @verbose = if @verbose == 'false'
17
- false
18
- else
19
- true
20
- end
21
- end
14
+ @verbose = parse_bool(@verbose)
15
+ @force = parse_bool(@force)
22
16
  end
23
17
 
24
18
  def import!
@@ -69,23 +63,23 @@ module ForemanTemplates
69
63
  if @filter
70
64
  matching = name.match(/#{@filter}/i)
71
65
  matching = !matching if @negate
72
- next if !matching
66
+ next unless matching
73
67
  end
74
68
 
75
69
  begin
76
- # Expects a return of { :diff, :status, :result }
70
+ # Expects a return of { :diff, :status, :result, :errors }
77
71
  data = if metadata['model'].present?
78
- metadata['model'].constantize.import!(name, text, metadata)
72
+ metadata['model'].constantize.import!(name, text, metadata, @force)
79
73
  else
80
74
  # For backwards-compat before "model" metadata was added
81
75
  case metadata['kind']
82
76
  when 'ptable'
83
- Ptable.import!(name, text, metadata)
77
+ Ptable.import!(name, text, metadata, @force)
84
78
  when 'job_template'
85
79
  # TODO: update REX templates to have `model` and delete this
86
80
  update_job_template(name, text)
87
81
  else
88
- ProvisioningTemplate.import!(name, text, metadata)
82
+ ProvisioningTemplate.import!(name, text, metadata, @force)
89
83
  end
90
84
  end
91
85
 
@@ -93,12 +87,12 @@ module ForemanTemplates
93
87
  data[:diff] = calculate_diff(data[:old], data[:new])
94
88
  end
95
89
 
96
- if data[:status] == true && @verbose
90
+ if @verbose
97
91
  result_lines << data[:result]
98
92
  result_lines << data[:diff] unless data[:diff].nil?
99
- elsif data[:status] == false
100
- result_lines << "Template \"#{name}\": #{data[:result]}"
101
93
  end
94
+ result_lines << status_to_text(data[:status], name)
95
+ result_lines << data[:errors] unless data[:errors].empty?
102
96
  rescue MissingKindError
103
97
  result_lines << " Skipping: '#{name}' - No template kind or model detected"
104
98
  next
@@ -136,10 +130,12 @@ module ForemanTemplates
136
130
  puts 'Deprecation warning: JobTemplate support is moving to the Remote Execution plugin'
137
131
  puts "- please add 'model: JobTemplate' to the metadata in '#{file}' to call the right method"
138
132
 
139
- return {
140
- :status => false,
141
- :result => 'Skipping job template import, remote execution plugin is not installed.'
142
- } unless defined?(JobTemplate)
133
+ unless defined?(JobTemplate)
134
+ return {
135
+ :status => false,
136
+ :result => 'Skipping job template import, remote execution plugin is not installed.'
137
+ }
138
+ end
143
139
  template = JobTemplate.import(
144
140
  text.sub(/^name: .*$/, "name: #{name}"),
145
141
  :update => true
@@ -167,5 +163,21 @@ module ForemanTemplates
167
163
  template.destroy
168
164
  end
169
165
  end # :purge
166
+
167
+ private
168
+
169
+ def parse_bool(bool_name)
170
+ bool_name.is_a?(String) ? bool_name != 'false' : bool_name
171
+ end
172
+
173
+ def status_to_text(status, name)
174
+ msg = "#{name} - import "
175
+ msg << if status
176
+ "success"
177
+ else
178
+ 'failure'
179
+ end
180
+ msg
181
+ end
170
182
  end
171
183
  end
data/config/routes.rb CHANGED
@@ -1,13 +1,12 @@
1
1
  Rails.application.routes.draw do
2
-
3
- namespace :api, :defaults => {:format => 'json'} do
4
- scope "(:apiv)", :module => :v2, :defaults => {:apiv => 'v2'}, :apiv => /v1|v2/, :constraints => ApiConstraints.new(:version => 2) do
5
- resources :templates, :controller => :template, :only => :import do
2
+ namespace :api, :defaults => { :format => 'json' } do
3
+ scope "(:apiv)", :module => :v2, :defaults => { :apiv => 'v2' }, :apiv => /v1|v2/, :constraints => ApiConstraints.new(:version => 2) do
4
+ resources :templates, :controller => :template, :only => [] do
6
5
  collection do
7
6
  post 'import'
7
+ post 'export'
8
8
  end
9
9
  end
10
10
  end
11
11
  end
12
-
13
12
  end
@@ -23,6 +23,9 @@ module ForemanTemplates
23
23
  permission :import_templates, {
24
24
  :"api/v2/template" => [:import]
25
25
  }, :resource_type => 'Template'
26
+ permission :export_templates, {
27
+ :"api/v2/template" => [:export]
28
+ }, :resource_type => 'Template'
26
29
  end
27
30
  add_all_permissions_to_default_roles
28
31
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanTemplates
2
- VERSION = '5.0.0'.freeze
2
+ VERSION = '5.0.1'.freeze
3
3
  end
@@ -6,13 +6,13 @@ namespace :templates do
6
6
  ActiveSupport::Deprecation.warn('templates:sync task has been renamed to templates:import and will be removed in a future version')
7
7
  end
8
8
  # Available options:
9
- #* verbose => Print extra information during the run [false]
10
- #* repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
11
- #* branch => Branch in Git repo [default branch]
12
- #* prefix => The string all imported templates should begin with [Community ]
13
- #* dirname => The directory within the git tree containing the templates [/]
14
- #* filter => Import names matching this regex (case-insensitive; snippets are not filtered)
15
- #* associate => Associate to OS's, Locations & Organizations. Options are: always, new or never [new]
9
+ # * verbose => Print extra information during the run [false]
10
+ # * repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
11
+ # * branch => Branch in Git repo [default branch]
12
+ # * prefix => The string all imported templates should begin with [Community ]
13
+ # * dirname => The directory within the git tree containing the templates [/]
14
+ # * filter => Import names matching this regex (case-insensitive; snippets are not filtered)
15
+ # * associate => Associate to OS's, Locations & Organizations. Options are: always, new or never [new]
16
16
 
17
17
  User.current = User.anonymous_admin
18
18
 
@@ -54,9 +54,9 @@ namespace :templates do
54
54
  User.current = User.anonymous_admin
55
55
 
56
56
  ForemanTemplates::TemplateImporter.new({
57
- #* negate => negate query [false]
58
- #* prefix => The string all templates to purge should ( or not ) begin with [Community ]
59
- #* verbose => Print extra information during the run [false]
57
+ # * negate => negate query [false]
58
+ # * prefix => The string all templates to purge should ( or not ) begin with [Community ]
59
+ # * verbose => Print extra information during the run [false]
60
60
  negate: ENV['negate'],
61
61
  prefix: ENV['prefix'],
62
62
  verbose: ENV['verbose'],
@@ -69,7 +69,6 @@ namespace :templates do
69
69
  ForemanTemplates::Cleaner.new.clean_up!
70
70
  puts 'Clean up finished, you can now remove the plugin from your system'
71
71
  end
72
-
73
72
  end
74
73
 
75
74
  # Tests
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: 5.0.0
4
+ version: 5.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: 2017-04-25 00:00:00.000000000 Z
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diffy