foreman_templates 2.1.0 → 3.0.0

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: 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