foreman_templates 2.1.0 → 3.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3bd9ea7c7b68c51790a87d66ab47d73f8c8a732
4
- data.tar.gz: 9a9a5b69cbe4c1a1c46c9657eec4c25bdf7d03c8
3
+ metadata.gz: ab073792fefeb26fbe23885b712a9baa467753f0
4
+ data.tar.gz: c9b1d817144bd1fb43b7667a9e453000a4e047e0
5
5
  SHA512:
6
- metadata.gz: c00161195df295c0366d2eeb1d82526f50402e7d9bb01e7f1a149976dc297b12395df399e5b8233a5f428a81e61c41f5c4807dccc7f8f1dbee4c8066203c01d9
7
- data.tar.gz: 3a9876e223051b8ed1f3e1f5389558da85e0ab8ea389f10827d77ad3cee24d2bb6c413312fc191e42e1b37882bb0794966652c8b749618c31defb6d8ba4a2ab2
6
+ metadata.gz: 8d746a74ce4346d98e062cd6df27c163d411474925d52ee6e54594fc68f16ccf9776fb849a701c0ef137e8136c8faf2d1ff6d915e39e8214e7dea3c004bea478
7
+ data.tar.gz: 7ee0097bbc39da25acd264c7932db97c789edc1e8e042ffd7af0f984ebbe20ba7dd1cab8281390bc9022b729e1c6686ef73d81be835bb1abfb8a6035a6986223
data/README.md CHANGED
@@ -21,10 +21,12 @@ You can get the develop branch of the plugin by specifying your Gemfile in this
21
21
 
22
22
  ## Configuration
23
23
 
24
- There is UI no configuration at this time.
24
+ There is no UI configuration at this time.
25
25
 
26
26
  ## Usage
27
27
 
28
+ ### Import
29
+
28
30
  The plugin provides a Rake task to import the templates. To use it, simply do
29
31
 
30
32
  foreman-rake templates:sync
@@ -37,7 +39,7 @@ The importer will attempt to figure out the OS and Release the template refers t
37
39
  this is a new template being created, and we can find a matching OS in Foreman, the
38
40
  template will be automatically associated with the OS
39
41
 
40
- # Rake options
42
+ #### Rake options
41
43
 
42
44
  * verbose => Print extra information during the run [false]
43
45
  * repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
@@ -51,9 +53,9 @@ The `branch` default will use *develop* if you're on Foreman-nightly; or the
51
53
  matching *1.X-stable* branch for your version of Foreman (if it exists); or
52
54
  finally it will remain on the default branch as a fallback.
53
55
 
54
- ## Examples
56
+ #### Examples
55
57
 
56
- Just import all the templates in from the default repo
58
+ Just import all the templates from the default repo
57
59
 
58
60
  foreman-rake templates:sync
59
61
 
@@ -65,14 +67,69 @@ Import templates matching the name "Fedora"
65
67
 
66
68
  foreman-rake templates:sync filter='fedora'
67
69
 
68
- Import templates from a subsection of a git repo:
70
+ Import templates from a subdirectory of a git repo:
69
71
 
70
72
  foreman-rake templates:sync repo="http://github.com/GregSutcliffe/community-templates" dirname='/subdir'
71
73
 
74
+ ### Purge
75
+
76
+ This task deletes matching templates from the Foreman DB
77
+
78
+ #### Rake options
79
+
80
+ * prefix => The string all templates to be purged should begin with [Community ]
81
+ * negate => Negate the search [false]
82
+ * verbose => Print extra information during the run [false]
83
+
84
+ #### Examples
85
+
86
+ Just purge all the templates the begin with 'Community '
87
+
88
+ foreman-rake templates:purge
89
+
90
+ Purge all templates that begin with 'Oops '
91
+
92
+ foreman-rake templates:purge prefix='Oops '
93
+
94
+ Purge all templates that do not begin with 'Community '
95
+
96
+ foreman-rake templates:purge negate=true
97
+
98
+ ## Integration with other Foreman Plugins
99
+
100
+ `templates` will start processing a template by looking for a metadata entry of
101
+ `model`. If this is found, `templates` will call `import!` on this model.
102
+
103
+ That means it's possible for a plugin to define it's own handling of text and
104
+ metadata, relevant to the plugins own interests. The `import!` method will be
105
+ sent 3 arguments - the `name` of the template, the `text` of the template, and
106
+ a complete copy of the `metadata`.
107
+
108
+ As a trivial example for a random plugin, suppose `foreman_nosuchplugin` has
109
+ this code:
110
+
111
+ ```
112
+ module ForemanNosuchplugin
113
+ class SomeTemplate
114
+ def self.import!(name, text, metadata)
115
+ File.open("/tmp/#{name}",'w') {|f| f.write text }
116
+ end
117
+ end
118
+ end
119
+ ```
120
+
121
+ Assuming a template had "model: SomeTemplate" in it's metadata, this would then
122
+ get written to a file in `/tmp`.
123
+
124
+ `templates` will expect the `import!` method to return a Hash, containing:
125
+
126
+ * `:status` (boolean),
127
+ * `:diff` (text, may be nil), or
128
+ * `:old` and `:new` (in which case this plugin will calculate the diff)
129
+ * :result` (text, may be nil).
130
+
72
131
  ## TODO
73
132
 
74
- * Allow user to filter to a specific subset of templates
75
- * Add associations by template family
76
133
  * Add a button to the UI with Deface to run the rake task
77
134
 
78
135
  ## Copyright
@@ -0,0 +1,62 @@
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_oses(metadata)
21
+
22
+ # Printout helpers
23
+ c_or_u = template.new_record? ? 'Created' : 'Updated'
24
+ id_string = ('id' + template.id) rescue ''
25
+
26
+ if (metadata['associate'] == 'new' && template.new_record?) || (metadata['associate'] == 'always')
27
+ data[:operatingsystem_ids] = oses.map(&:id)
28
+ end
29
+
30
+ if data[:template] != template.template
31
+ diff = Diffy::Diff.new(
32
+ template.template,
33
+ data[:template],
34
+ :include_diff_info => true
35
+ ).to_s(:color)
36
+ status = template.update_attributes(data)
37
+ result = " #{c_or_u} Template #{id_string}:#{name}"
38
+ result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
39
+ elsif data[:operatingsystem_ids]
40
+ diff = nil
41
+ status = template.update_attributes(data)
42
+ result = " #{c_or_u} Template Associations #{id_string}:#{name}"
43
+ result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" unless oses.empty?
44
+ else
45
+ diff = nil
46
+ status = true
47
+ result = " No change to Template #{id_string}:#{name}"
48
+ end
49
+ { :diff => diff, :status => status, :result => result }
50
+ end
51
+
52
+ def map_oses(metadata)
53
+ if metadata['oses']
54
+ metadata['oses'].map do |os|
55
+ Operatingsystem.all.map { |db| db.to_label =~ /^#{os}/ ? db : nil }
56
+ end.flatten.compact
57
+ else
58
+ []
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
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 = { :layout => text }
12
+ oses = map_oses(metadata)
13
+
14
+ # Printout helpers
15
+ c_or_u = ptable.new_record? ? 'Created' : 'Updated'
16
+ id_string = ('id' + ptable.id) rescue ''
17
+
18
+ if (metadata['associate'] == 'new' && ptable.new_record?) || (metadata['associate'] == 'always')
19
+ data[:os_family] = oses.map(&:family).uniq.first
20
+ end
21
+
22
+ if data[:layout] != ptable.layout
23
+ diff = Diffy::Diff.new(
24
+ ptable.layout,
25
+ data[:layout],
26
+ :include_diff_info => true
27
+ ).to_s(:color)
28
+ status = ptable.update_attributes(data)
29
+ result = " #{c_or_u} Ptable #{id_string}:#{name}"
30
+ elsif data[:os_family]
31
+ diff = nil
32
+ status = ptable.update_attributes(data)
33
+ result = " #{c_or_u} Ptable Associations #{id_string}:#{name}"
34
+ result += "\n Operatingsystem Family:\n - #{oses.map(&:family).uniq.first}" unless oses.empty?
35
+ else
36
+ diff = nil
37
+ status = true
38
+ result = " No change to Ptable #{id_string}:#{name}"
39
+ end
40
+ { :diff => diff, :status => status, :result => result }
41
+ end
42
+
43
+ # TODO: DRY this, it's copied from ProvisioningTemplateImport
44
+ def map_oses(metadata)
45
+ if metadata['oses']
46
+ metadata['oses'].map do |os|
47
+ Operatingsystem.all.map { |db| db.to_label =~ /^#{os}/ ? db : nil }
48
+ end.flatten.compact
49
+ else
50
+ []
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ module ForemanTemplates::TemplateImport
2
+ extend ActiveSupport::Concern
3
+
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
+ }
12
+
13
+ # Printout helpers
14
+ c_or_u = snippet.new_record? ? 'Created' : 'Updated'
15
+ id_string = ('id' + snippet.id) rescue ''
16
+
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}"
29
+ end
30
+ { :diff => diff, :status => status, :result => result }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,167 @@
1
+ class NoKindError < Exception; end
2
+ class MissingKindError < Exception; end
3
+
4
+ module ForemanTemplates
5
+ class TemplateImporter
6
+ delegate :logger, :to => :Rails
7
+ attr_accessor :metadata, :name, :text
8
+
9
+ def initialize(args = {})
10
+ @verbose = args[:verbose] || false
11
+ @associate = args[:associate] || 'new'
12
+ @prefix = args[:prefix] || 'Community '
13
+ @dirname = args[:dirname] || '/'
14
+ @filter = args[:filter] || nil
15
+ @repo = args[:repo] || 'https://github.com/theforeman/community-templates.git'
16
+ @negate = args[:negate] || false
17
+ @branch = args[:branch] || false
18
+
19
+ # Rake hands off strings, not booleans, and "false" is true...
20
+ if @verbose.is_a?(String)
21
+ @verbose = if @verbose == 'false'
22
+ false
23
+ else
24
+ true
25
+ end
26
+ end
27
+ end
28
+
29
+ def import!
30
+ # Check out the community templates to a temp location
31
+ @dir = Dir.mktmpdir
32
+
33
+ begin
34
+ gitrepo = Git.clone(@repo, @dir)
35
+ branch = @branch ? @branch : get_default_branch(gitrepo)
36
+ gitrepo.checkout(branch) if branch
37
+
38
+ return parse_files!
39
+ ensure
40
+ FileUtils.remove_entry_secure(@dir) if File.exist?(@dir)
41
+ end
42
+ end
43
+
44
+ def parse_files!
45
+ result_lines = []
46
+
47
+ # Build a list of ERB files to parse
48
+ Dir["#{@dir}#{@dirname}/**/*.erb"].each do |template|
49
+ text = File.read(template)
50
+ result_lines << 'Parsing: ' + template.gsub(/#{@dir}#{@dirname}/, '') if @verbose
51
+
52
+ metadata = parse_metadata(text)
53
+ metadata['associate'] = @associate
54
+
55
+ # Get the name and filter
56
+ filename = template.split('/').last
57
+ title = filename.split('.').first
58
+ name = metadata['name'] || title
59
+ name = [@prefix, name].compact.join
60
+ next if @filter && !name.match(/#{@filter}/i)
61
+
62
+ raise MissingKindError unless metadata['kind']
63
+
64
+ begin
65
+ # Expects a return of { :diff, :status, :result }
66
+ data = if metadata['model'].present?
67
+ metadata['model'].constantize.import!(name, text, metadata)
68
+ else
69
+ # For backwards-compat before "model" metadata was added
70
+ case metadata['kind']
71
+ when 'ptable'
72
+ Ptable.import!(name, text, metadata)
73
+ when 'job_template'
74
+ # TODO: update REX templates to have `model` and delete this
75
+ update_job_template(name, text)
76
+ else
77
+ ProvisioningTemplate.import!(name, text, metadata)
78
+ end
79
+ end
80
+
81
+ if data[:diff].nil? && data[:old].present? && data[:new].present?
82
+ data[:diff] = calculate_diff(data[:old], data[:new])
83
+ end
84
+
85
+ if data[:status] == true && @verbose
86
+ result_lines << data[:result]
87
+ result_lines << data[:diff] unless data[:diff].nil?
88
+ elsif data[:status] == false
89
+ result_lines << "Template \"#{name}\": #{data[:result]}"
90
+ end
91
+ rescue MissingKindError
92
+ result_lines << " Skipping: '#{name}' - No template kind or model detected"
93
+ next
94
+ rescue NoKindError
95
+ result_lines << " Skipping: '#{name}' - Unknown template kind '#{metadata['kind']}'"
96
+ next
97
+ rescue NameError
98
+ result_lines << " Skipping: '#{name}' - Unknown template model '#{metadata['model']}'"
99
+ next
100
+ end
101
+ end
102
+ result_lines
103
+ end
104
+
105
+ def calculate_diff(old, new)
106
+ if old != new
107
+ Diffy::Diff.new(old, new, :include_diff_info => true).to_s(:color)
108
+ else
109
+ nil
110
+ end
111
+ end
112
+
113
+ def get_default_branch(repo)
114
+ branch_names = repo.branches.map(&:name).uniq
115
+
116
+ # Always use develop on Foreman-nightly, if present, or else relevant stable branch
117
+ target = SETTINGS[:version].tag == 'develop' ? 'develop' : "#{SETTINGS[:version].short}-stable"
118
+ return target if branch_names.include?(target)
119
+
120
+ # stay on default branch as fallback
121
+ nil
122
+ end
123
+
124
+ def parse_metadata(text)
125
+ # Pull out the first erb comment only - /m is for a multiline regex
126
+ extracted = text.match(/<%\#[\t a-z0-9=:]*(.+?).-?%>/m)
127
+ extracted.nil? ? {} : YAML.load(extracted[1])
128
+ end
129
+
130
+ def update_job_template(name, text)
131
+ file = name.gsub(/^#{@prefix}/, '')
132
+ puts 'Deprecation warning: JobTemplate support is moving to the Remote Execution plugin'
133
+ puts "- please add 'model: JobTemplate' to the metadata in '#{file}' to call the right method"
134
+
135
+ return {
136
+ :status => false,
137
+ :result => 'Skipping job template import, remote execution plugin is not installed.'
138
+ } unless defined?(JobTemplate)
139
+ template = JobTemplate.import(
140
+ text.sub(/^name: .*$/, "name: #{name}"),
141
+ :update => true
142
+ )
143
+
144
+ c_or_u = template.new_record? ? 'Created' : 'Updated'
145
+ id_string = ('id' + template.id) rescue ''
146
+
147
+ if template.template != template.template_was
148
+ diff = Diffy::Diff.new(
149
+ template.template_was,
150
+ template.template,
151
+ :include_diff_info => true
152
+ ).to_s(:color)
153
+ end
154
+
155
+ result = " #{c_or_u} Template #{id_string}:#{name}"
156
+ { :diff => diff, :status => template.save, :result => result }
157
+ end
158
+
159
+ def purge!
160
+ clause = "name #{@negate ? 'NOT ' : ''}LIKE ?"
161
+ ProvisioningTemplate.where(clause, "#{@prefix}%").each do |template|
162
+ puts template if @verbose
163
+ template.destroy
164
+ end
165
+ end # :purge
166
+ end
167
+ end
@@ -1,20 +1,28 @@
1
+ require 'fileutils'
2
+ require 'yaml'
1
3
  require 'diffy'
2
4
  require 'git'
3
5
 
4
6
  module ForemanTemplates
5
- #Inherit from the Rails module of the parent app (Foreman), not the plugin.
6
- #Thus, inhereits from ::Rails::Engine and not from Rails::Engine
7
+ # Inherit from the Rails module of the parent app (Foreman), not the plugin.
8
+ # Thus, inhereits from ::Rails::Engine and not from Rails::Engine
7
9
  class Engine < ::Rails::Engine
10
+ engine_name 'foreman_templates'
8
11
 
9
- initializer 'foreman_templates.register_plugin', :after=> :finisher_hook do |app|
12
+ initializer 'foreman_templates.register_plugin', :before => :finisher_hook do
10
13
  Foreman::Plugin.register :foreman_templates do
11
- requires_foreman '>= 1.9'
14
+ requires_foreman '>= 1.12'
12
15
  end
13
16
  end
14
17
 
15
- rake_tasks do
16
- load "templates.rake"
18
+ config.to_prepare do
19
+ begin
20
+ Template.send(:include, ForemanTemplates::TemplateImport)
21
+ Ptable.send(:include, ForemanTemplates::PtableImport)
22
+ ProvisioningTemplate.send(:include, ForemanTemplates::ProvisioningTemplateImport)
23
+ rescue => e
24
+ puts "#{ForemanTemplates::ENGINE_NAME}: skipping engine hook (#{e})"
25
+ end
17
26
  end
18
-
19
27
  end
20
28
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanTemplates
2
- VERSION = "2.1.0"
2
+ VERSION = '3.0.0'.freeze
3
3
  end
@@ -0,0 +1,75 @@
1
+ # Tasks
2
+ namespace :templates do
3
+ desc 'Synchronize templates from a git repo'
4
+ task :sync => :environment do
5
+ # Available options:
6
+ #* verbose => Print extra information during the run [false]
7
+ #* repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
8
+ #* branch => Branch in Git repo [default branch]
9
+ #* prefix => The string all imported templates should begin with [Community ]
10
+ #* dirname => The directory within the git tree containing the templates [/]
11
+ #* filter => Import names matching this regex (case-insensitive; snippets are not filtered)
12
+ #* associate => Associate to OS, always, new or never [new]
13
+
14
+ results = ForemanTemplates::TemplateImporter.new({
15
+ verbose: ENV['verbose'],
16
+ repo: ENV['repo'],
17
+ branch: ENV['branch'],
18
+ prefix: ENV['prefix'],
19
+ dirname: ENV['dirname'],
20
+ filter: ENV['filter'],
21
+ associate: ENV['associate'],
22
+ }).import!
23
+
24
+ puts results.join("\n")
25
+ end
26
+
27
+ desc 'Purge unwanted templates from foreman'
28
+ task :purge => :environment do
29
+ ForemanTemplates::TemplateImporter.new({
30
+ #* negate => negate query [false]
31
+ #* prefix => The string all templates to purge should ( or not ) begin with [Community ]
32
+ #* verbose => Print extra information during the run [false]
33
+ negate: ENV['negate'],
34
+ prefix: ENV['prefix'],
35
+ verbose: ENV['verbose'],
36
+ }).purge!
37
+ end
38
+
39
+ end
40
+
41
+ # Tests
42
+ namespace :test do
43
+ desc "Test ForemanTemplates"
44
+ Rake::TestTask.new(:foreman_templates) do |t|
45
+ test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
46
+ t.libs << ['test', test_dir]
47
+ t.pattern = "#{test_dir}/**/*_test.rb"
48
+ t.verbose = true
49
+ t.warning = false
50
+ end
51
+ end
52
+
53
+ namespace :foreman_templates do
54
+ task :rubocop do
55
+ begin
56
+ require 'rubocop/rake_task'
57
+ RuboCop::RakeTask.new(:rubocop_foreman_templates) do |task|
58
+ task.patterns = ["#{ForemanTemplates::Engine.root}/app/**/*.rb",
59
+ "#{ForemanTemplates::Engine.root}/lib/**/*.rb",
60
+ "#{ForemanTemplates::Engine.root}/test/**/*.rb"]
61
+ end
62
+ rescue
63
+ puts 'Rubocop not loaded.'
64
+ end
65
+
66
+ Rake::Task['rubocop_foreman_templates'].invoke
67
+ end
68
+ end
69
+
70
+ Rake::Task[:test].enhance ['test:foreman_templates']
71
+
72
+ load 'tasks/jenkins.rake'
73
+ if Rake::Task.task_defined?(:'jenkins:unit')
74
+ Rake::Task['jenkins:unit'].enhance ['test:foreman_templates', 'foreman_templates:rubocop']
75
+ end
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: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Sutcliffe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-11 00:00:00.000000000 Z
11
+ date: 2016-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diffy
@@ -49,10 +49,14 @@ files:
49
49
  - LICENSE
50
50
  - README.md
51
51
  - Rakefile
52
+ - app/models/concerns/foreman_templates/provisioning_template_import.rb
53
+ - app/models/concerns/foreman_templates/ptable_import.rb
54
+ - app/models/concerns/foreman_templates/template_import.rb
55
+ - app/services/foreman_templates/template_importer.rb
52
56
  - lib/foreman_templates.rb
53
57
  - lib/foreman_templates/engine.rb
54
58
  - lib/foreman_templates/version.rb
55
- - lib/templates.rake
59
+ - lib/tasks/foreman_templates_tasks.rake
56
60
  homepage: http://github.com/theforeman/foreman_templates
57
61
  licenses:
58
62
  - GPL-3
data/lib/templates.rake DELETED
@@ -1,234 +0,0 @@
1
- require 'fileutils'
2
- require 'yaml'
3
- require 'diffy'
4
- require 'git'
5
-
6
- class NoKindError < Exception ; end
7
-
8
- def db_oses
9
- @db_oses || Operatingsystem.all
10
- end
11
-
12
- def metadata(text)
13
- # Pull out the first erb comment only - /m is for a multiline regex
14
- extracted = text.match(/<%\#(.+?).-?%>/m)
15
- extracted == nil ? {} : YAML.load(extracted[1])
16
- end
17
-
18
- def map_oses
19
- oses = if @metadata['oses']
20
- @metadata['oses'].map do |os|
21
- db_oses.map { |db| db.to_label =~ /^#{os}/ ? db : nil}
22
- end.flatten.compact
23
- else
24
- []
25
- end
26
- return oses
27
- end
28
-
29
- def update_job_template
30
- return {:status => false, :result => 'Skipping job template import, remote execution plugin is not installed.'} unless defined?(JobTemplate)
31
- template = JobTemplate.import(@text.sub(/^name: .*$/, "name: #{@name}"), :update => true)
32
-
33
- string = template.new_record? ? 'Created' : 'Updated'
34
-
35
- if template.template != template.template_was
36
- diff = Diffy::Diff.new(template.template_was, template.template, :include_diff_info => true).to_s(:color)
37
- end
38
-
39
- result = " #{string} Template #{ 'id' + template.id rescue ''}:#{@name}"
40
-
41
- {:diff => diff, :status => template.save, :result => result}
42
- end
43
-
44
- def update_template
45
- # Get template type
46
- unless kind = TemplateKind.find_by_name(@metadata['kind'])
47
- raise NoKindError
48
- end
49
-
50
- db_template = ProvisioningTemplate.where(:name => @name).first_or_initialize
51
- data = {
52
- :template => @text,
53
- :snippet => false,
54
- :template_kind_id => kind.id
55
- }
56
- string = db_template.new_record? ? "Created" : "Updated"
57
-
58
- oses = map_oses
59
- if (@associate == 'new' and db_template.new_record?) or (@associate == 'always')
60
- data[:operatingsystem_ids] = oses.map(&:id)
61
- end
62
-
63
- if @text != db_template.template
64
- diff = Diffy::Diff.new(db_template.template, @text, :include_diff_info => true).to_s(:color)
65
- status = db_template.update_attributes(data)
66
- result = " #{string} Template #{ 'id' + db_template.id rescue ''}:#{@name}"
67
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" if !oses.empty?
68
- elsif data[:operatingsystem_ids]
69
- diff = nil
70
- status = db_template.update_attributes(data)
71
- result = " #{string} Template Associations #{ 'id' + db_template.id rescue ''}:#{@name}"
72
- result += "\n Operatingsystem Associations:\n - #{oses.map(&:fullname).join("\n - ")}" if !oses.empty?
73
- else
74
- diff = nil
75
- status = true
76
- result = " No change to Template #{ ( 'id' + db_template.id ) rescue ''}:#{@name}"
77
- end
78
- { :diff => diff, :status => status, :result => result }
79
- end
80
-
81
- def update_ptable
82
- db_ptable = Ptable.where(:name => @name).first_or_initialize
83
- data = { :layout => @text }
84
- string = db_ptable.new_record? ? "Created" : "Updated"
85
-
86
- oses = map_oses
87
- if (@associate == 'new' and db_ptable.new_record?) or (@associate == 'always')
88
- data[:os_family] = oses.map(&:family).uniq.first
89
- end
90
-
91
- if @text != db_ptable.layout
92
- diff = Diffy::Diff.new(db_ptable.layout, @text, :include_diff_info => true).to_s(:color)
93
- status = db_ptable.update_attributes(data)
94
- result = " #{string} Ptable #{ ( 'id' + db_ptable.id ) rescue ''}:#{@name}"
95
- elsif data[:os_family]
96
- diff = nil
97
- status = db_ptable.update_attributes(data)
98
- result = " #{string} Ptable Associations #{ ( 'id' + db_ptable.id ) rescue ''}:#{@name}"
99
- result += "\n Operatingsystem Family:\n - #{oses.map(&:family).uniq.first}" if !oses.empty?
100
- else
101
- diff = nil
102
- status = true
103
- result = " No change to Ptable #{ ( 'id' + db_ptable.id ) rescue ''}:#{@name}"
104
- end
105
- { :diff => diff, :status => status, :result => result }
106
- end
107
-
108
- def update_snippet
109
- db_snippet = ProvisioningTemplate.where(:name => @name).first_or_initialize
110
- data = {
111
- :template => @text,
112
- :snippet => true
113
- }
114
- string = db_snippet.new_record? ? "Created" : "Updated"
115
-
116
- if @text != db_snippet.template
117
- diff = Diffy::Diff.new(db_snippet.template, @text, :include_diff_info => true).to_s(:color)
118
- status = db_snippet.update_attributes(data)
119
- result = " #{string} Snippet #{ ('id' + db_snippet.id) rescue ''}:#{@name}"
120
- else
121
- diff = nil
122
- status = true
123
- result = " No change to Snippet #{ 'id' + db_snippet.id rescue ''}:#{@name}"
124
- end
125
- { :diff => diff, :status => status, :result => result }
126
- end
127
-
128
- def get_default_branch(repo)
129
- branch_names = repo.branches.map(&:name).uniq
130
-
131
- # Always use develop on Foreman-nightly, if present, or else relevant stable branch
132
- target = SETTINGS[:version].tag == 'develop' ? 'develop' : "#{SETTINGS[:version].short}-stable"
133
- return target if branch_names.include?(target)
134
-
135
- # stay on default branch as fallback
136
- return nil
137
- end
138
-
139
- desc <<-END_DESC
140
- Synchronize templates from a git repo
141
- END_DESC
142
- namespace :templates do
143
- task :sync => :environment do
144
- # Available options:
145
- #* verbose => Print extra information during the run [false]
146
- #* repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
147
- #* branch => Branch in Git repo [default branch]
148
- #* prefix => The string all imported templates should begin with [Community ]
149
- #* dirname => The directory within the git tree containing the templates [/]
150
- #* filter => Import names matching this regex (case-insensitive; snippets are not filtered)
151
- #* associate => Associate to OS, always, new or never [new]
152
-
153
- @verbose = ( ENV['verbose'] and ENV['verbose'] != 'false' ) ? true : false
154
- @associate = ENV['associate'] ? ENV['associate'] : 'new'
155
- prefix = ENV['prefix'] ? ENV['prefix'] : 'Community '
156
- dirname = ENV['dirname'] ? ENV['dirname'] : '/'
157
- filter = ENV['filter'] ? ENV['filter'] : nil
158
- repo = ENV['repo'] ? ENV['repo'] : "https://github.com/theforeman/community-templates.git"
159
-
160
- # Check out the community templates to a temp location
161
- dir = Dir.mktmpdir
162
- begin
163
- gitrepo = Git.clone(repo, dir)
164
- branch = ENV['branch'] ? ENV['branch'] : get_default_branch(gitrepo)
165
- gitrepo.checkout(branch) if branch
166
-
167
- # Build a list of ERB files to parse
168
- Dir["#{dir}#{dirname}/**/*.erb"].each do |template|
169
- @text = File.read(template)
170
- puts "Parsing: " + template.gsub(/#{dir}#{dirname}/,'') if @verbose
171
-
172
- @metadata = metadata(@text)
173
-
174
- # Get the name and filter
175
- filename = template.split('/').last
176
- title = filename.split('.').first
177
- @name = @metadata['name'] || title
178
- @name = [prefix, @name].compact.join()
179
- next if filter and not @name.match(/#{filter}/i)
180
-
181
- unless @metadata['kind']
182
- puts " Error: Must specify template kind"
183
- next
184
- end
185
-
186
- begin
187
- case @metadata['kind']
188
- when 'ptable'
189
- data = update_ptable
190
- when 'snippet'
191
- data = update_snippet
192
- when 'job_template'
193
- data = update_job_template
194
- else
195
- data = update_template
196
- end
197
-
198
- if data[:status] == true && @verbose
199
- puts data[:result]
200
- puts data[:diff]
201
- elsif data[:status] == false
202
- puts "Error with #{@name}"
203
- puts data[:result]
204
- end
205
- rescue NoKindError
206
- puts " Error: Unknown template type '#{@metadata['kind']}'"
207
- next
208
- end
209
- end
210
- ensure
211
- FileUtils.remove_entry_secure(dir) if File.exist?(dir)
212
- end
213
-
214
- end
215
- end
216
-
217
- # Setup Tests
218
- namespace :test do
219
- desc "Test ForemanTemplates plugin"
220
- Rake::TestTask.new(:templates) do |t|
221
- test_dir = File.join(File.dirname(__FILE__), '..', 'test')
222
- t.libs << ["test",test_dir]
223
- t.pattern = "#{test_dir}/**/*_test.rb"
224
- end
225
- end
226
- Rake::Task[:test].enhance do
227
- Rake::Task['test:templates'].invoke
228
- end
229
- load 'tasks/jenkins.rake'
230
- if Rake::Task.task_defined?('jenkins:unit')
231
- Rake::Task["jenkins:unit"].enhance do
232
- Rake::Task['test:templates'].invoke
233
- end
234
- end