foreman_templates 3.1.0 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -2
- data/app/models/setting/template_sync.rb +54 -0
- data/app/services/foreman_templates/action.rb +56 -0
- data/app/services/foreman_templates/template_exporter.rb +110 -0
- data/app/services/foreman_templates/template_importer.rb +30 -26
- data/lib/foreman_templates/engine.rb +5 -1
- data/lib/foreman_templates/version.rb +1 -1
- data/lib/tasks/foreman_templates_tasks.rake +23 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93bf3ba6264276231731d04135d565544b718db2
|
4
|
+
data.tar.gz: dbc56dbd3b5b992dc9537c043eea071e61085140
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1887e56355692e0edc5a4961237763a7dca030bc3326ef10874ed8e51541b9809add0ac9c340dae9ec5634fb5cbd0d8e8eb339fde42b86ef91a7b93827eed97
|
7
|
+
data.tar.gz: d10d1091249e6ec67815f36903049c570c04fcfe109ba9520c2a173bc54667f6eaca8cd7027d1bceaa692fb959313b92b6d348a8071ce9f0b874ceb80c9528e3
|
data/README.md
CHANGED
@@ -21,7 +21,8 @@ You can get the develop branch of the plugin by specifying your Gemfile in this
|
|
21
21
|
|
22
22
|
## Configuration
|
23
23
|
|
24
|
-
|
24
|
+
The plugin comes with settings providing sane defaults for import. You can change them under Administer > Settings, TemplateSync tab.
|
25
|
+
These can be overriden for each import by passing options directly to a Rake task (see [Usage](https://github.com/theforeman/foreman_templates#usage) section for how to do that)
|
25
26
|
|
26
27
|
## Usage
|
27
28
|
|
@@ -42,7 +43,7 @@ template will be automatically associated with the OS
|
|
42
43
|
#### Rake options
|
43
44
|
|
44
45
|
* verbose => Print extra information during the run [false]
|
45
|
-
* repo => Sync templates from a different
|
46
|
+
* repo => Sync templates from a different repo [https://github.com/theforeman/community-templates]. Importing from git and file system is supported.
|
46
47
|
* branch => Branch in Git repo [_see note below_]
|
47
48
|
* prefix => The string all imported templates should begin with [Community]
|
48
49
|
* dirname => The directory within the git tree containing the templates [/]
|
@@ -53,6 +54,8 @@ The `branch` default will use *develop* if you're on Foreman-nightly; or the
|
|
53
54
|
matching *1.X-stable* branch for your version of Foreman (if it exists); or
|
54
55
|
finally it will remain on the default branch as a fallback.
|
55
56
|
|
57
|
+
Passing any option to a Rake task overrides its default value from a corresponding Setting.
|
58
|
+
|
56
59
|
#### Examples
|
57
60
|
|
58
61
|
Just import all the templates from the default repo
|
@@ -71,6 +74,10 @@ Import templates from a subdirectory of a git repo:
|
|
71
74
|
|
72
75
|
foreman-rake templates:sync repo="http://github.com/GregSutcliffe/community-templates" dirname='/subdir'
|
73
76
|
|
77
|
+
Import templates from file system:
|
78
|
+
|
79
|
+
foreman-rake templates:sync repo="/path/to/my/templates"
|
80
|
+
|
74
81
|
### Purge
|
75
82
|
|
76
83
|
This task deletes matching templates from the Foreman DB
|
@@ -0,0 +1,54 @@
|
|
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 }
|
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
|
+
].compact.each { |s| self.create! s.update(:category => "Setting::TemplateSync") }
|
36
|
+
end
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
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(', '))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
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(', '))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ForemanTemplates
|
2
|
+
class Action
|
3
|
+
delegate :logger, :to => :Rails
|
4
|
+
|
5
|
+
def self.setting_overrides
|
6
|
+
%i(verbose prefix dirname filter repo negate branch)
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(method, *args, &block)
|
10
|
+
if self.class.setting_overrides.include?(method)
|
11
|
+
instance_variable_get("@#{method}")
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def repond_to_missing?(method, include_private = false)
|
18
|
+
self.class.setting_overrides.include?(method)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(args = {})
|
22
|
+
assign_attributes args
|
23
|
+
end
|
24
|
+
|
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
|
+
def git_repo?
|
37
|
+
@repo.start_with?('http://', 'https://', 'git://')
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_absolute_repo_path
|
41
|
+
File.expand_path(@repo)
|
42
|
+
end
|
43
|
+
|
44
|
+
def verify_path!(path)
|
45
|
+
raise "Using file-based synchronization, but couldn't find #{path}" unless Dir.exist?(path)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def assign_attributes(args = {})
|
51
|
+
self.class.setting_overrides.each do |attribute|
|
52
|
+
instance_variable_set("@#{attribute}", args[attribute.to_sym] || Setting["template_sync_#{attribute}".to_sym])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module ForemanTemplates
|
2
|
+
class TemplateExporter < Action
|
3
|
+
def self.setting_overrides
|
4
|
+
super + %i(metadata_export_mode)
|
5
|
+
end
|
6
|
+
|
7
|
+
def export!
|
8
|
+
if git_repo?
|
9
|
+
export_to_git
|
10
|
+
else
|
11
|
+
export_to_files
|
12
|
+
end
|
13
|
+
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
|
17
|
+
def export_to_files
|
18
|
+
@dir = get_absolute_repo_path
|
19
|
+
verify_path!(@dir)
|
20
|
+
dump_files!
|
21
|
+
end
|
22
|
+
|
23
|
+
def export_to_git
|
24
|
+
@dir = Dir.mktmpdir
|
25
|
+
|
26
|
+
git_repo = Git.clone(@repo, @dir)
|
27
|
+
logger.debug "cloned #{@repo} to #{@dir}"
|
28
|
+
branch = @branch ? @branch : get_default_branch(git_repo)
|
29
|
+
# either checkout to existing or create a new one and checkout afterwards
|
30
|
+
if branch
|
31
|
+
if git_repo.is_branch?(branch)
|
32
|
+
git_repo.checkout(branch)
|
33
|
+
else
|
34
|
+
git_repo.branch(branch).checkout
|
35
|
+
if git_repo.is_remote_branch?(branch) # if we work with remote branch we need to sync it first
|
36
|
+
git_repo.reset_hard("origin/#{branch}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
dump_files!
|
42
|
+
git_repo.add
|
43
|
+
|
44
|
+
status = git_repo.status
|
45
|
+
if status.added.any? || status.changed.any? || status.deleted.any? || status.untracked.any?
|
46
|
+
logger.debug "committing changes in cloned repo"
|
47
|
+
git_repo.commit "Templates export made by Foreman user #{User.current.try(:login) || User::ANONYMOUS_ADMIN}"
|
48
|
+
|
49
|
+
logger.debug "pushing to branch #{branch} at origin #{@repo}"
|
50
|
+
git_repo.push 'origin', branch
|
51
|
+
else
|
52
|
+
logger.debug 'no change detected, skipping the commit and push'
|
53
|
+
end
|
54
|
+
ensure
|
55
|
+
FileUtils.remove_entry_secure(@dir) if File.exist?(@dir)
|
56
|
+
end
|
57
|
+
|
58
|
+
def dump_files!
|
59
|
+
templates_to_dump.map do |template|
|
60
|
+
current_dir = get_dump_dir(template)
|
61
|
+
FileUtils.mkdir_p current_dir
|
62
|
+
|
63
|
+
filename = File.join(current_dir, get_template_filename(template))
|
64
|
+
File.open(filename, 'w+') do |file|
|
65
|
+
logger.debug "Writing to file #{filename}"
|
66
|
+
bytes = file.write template.public_send(export_method)
|
67
|
+
logger.debug "finished writing #{bytes}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_template_filename(template)
|
73
|
+
template.name.downcase.tr(' ', '_') + '.erb'
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_dump_dir(template)
|
77
|
+
kind = template.respond_to?(:template_kind) ? template.template_kind.try(:name) || 'snippet' : nil
|
78
|
+
template_class_dir = template.model_name.human.pluralize.downcase.tr(' ', '_')
|
79
|
+
template_class_dir += '_templates' if template_class_dir == 'partition_tables'
|
80
|
+
File.join(@dir, dirname.to_s, template_class_dir, kind.to_s)
|
81
|
+
end
|
82
|
+
|
83
|
+
def templates_to_dump
|
84
|
+
base = Template.all
|
85
|
+
if filter.present?
|
86
|
+
method = negate ? :reject : :select
|
87
|
+
base.public_send(method) { |template| template.name.match(/#{filter}/i) }
|
88
|
+
else
|
89
|
+
base
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# * refresh - template.to_erb stripping existing metadata,
|
94
|
+
# * remove - just template.template with stripping existing metadata,
|
95
|
+
# * keep - taking the whole template.template
|
96
|
+
def export_method
|
97
|
+
case @metadata_export_mode
|
98
|
+
when 'refresh'
|
99
|
+
:to_erb
|
100
|
+
when 'remove'
|
101
|
+
:template_without_metadata
|
102
|
+
when 'keep'
|
103
|
+
:template
|
104
|
+
else
|
105
|
+
raise "Unknown metadata export mode #{@metadata_export_mode}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -2,20 +2,15 @@ class NoKindError < Exception; end
|
|
2
2
|
class MissingKindError < Exception; end
|
3
3
|
|
4
4
|
module ForemanTemplates
|
5
|
-
class TemplateImporter
|
6
|
-
delegate :logger, :to => :Rails
|
5
|
+
class TemplateImporter < Action
|
7
6
|
attr_accessor :metadata, :name, :text
|
8
7
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
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
|
8
|
+
def self.setting_overrides
|
9
|
+
super + %i(associate)
|
10
|
+
end
|
18
11
|
|
12
|
+
def initialize(args = {})
|
13
|
+
super
|
19
14
|
# Rake hands off strings, not booleans, and "false" is true...
|
20
15
|
if @verbose.is_a?(String)
|
21
16
|
@verbose = if @verbose == 'false'
|
@@ -27,6 +22,20 @@ module ForemanTemplates
|
|
27
22
|
end
|
28
23
|
|
29
24
|
def import!
|
25
|
+
if git_repo?
|
26
|
+
import_from_git
|
27
|
+
else
|
28
|
+
import_from_files
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def import_from_files
|
33
|
+
@dir = get_absolute_repo_path
|
34
|
+
verify_path!(@dir)
|
35
|
+
return parse_files!
|
36
|
+
end
|
37
|
+
|
38
|
+
def import_from_git
|
30
39
|
# Check out the community templates to a temp location
|
31
40
|
@dir = Dir.mktmpdir
|
32
41
|
|
@@ -56,10 +65,12 @@ module ForemanTemplates
|
|
56
65
|
filename = template.split('/').last
|
57
66
|
title = filename.split('.').first
|
58
67
|
name = metadata['name'] || title
|
59
|
-
name =
|
60
|
-
|
61
|
-
|
62
|
-
|
68
|
+
name = auto_prefix(name)
|
69
|
+
if @filter
|
70
|
+
matching = name.match(/#{@filter}/i)
|
71
|
+
matching = !matching if @negate
|
72
|
+
next if !matching
|
73
|
+
end
|
63
74
|
|
64
75
|
begin
|
65
76
|
# Expects a return of { :diff, :status, :result }
|
@@ -102,6 +113,10 @@ module ForemanTemplates
|
|
102
113
|
result_lines
|
103
114
|
end
|
104
115
|
|
116
|
+
def auto_prefix(name)
|
117
|
+
name.start_with?(@prefix) ? name : [@prefix, name].compact.join
|
118
|
+
end
|
119
|
+
|
105
120
|
def calculate_diff(old, new)
|
106
121
|
if old != new
|
107
122
|
Diffy::Diff.new(old, new, :include_diff_info => true).to_s(:color)
|
@@ -110,17 +125,6 @@ module ForemanTemplates
|
|
110
125
|
end
|
111
126
|
end
|
112
127
|
|
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
128
|
def parse_metadata(text)
|
125
129
|
# Pull out the first erb comment only - /m is for a multiline regex
|
126
130
|
extracted = text.match(/<%\#[\t a-z0-9=:]*(.+?).-?%>/m)
|
@@ -9,9 +9,13 @@ module ForemanTemplates
|
|
9
9
|
class Engine < ::Rails::Engine
|
10
10
|
engine_name 'foreman_templates'
|
11
11
|
|
12
|
+
initializer 'foreman_templates.load_default_settings', :before => :load_config_initializers do
|
13
|
+
require_dependency File.expand_path('../../../app/models/setting/template_sync.rb', __FILE__) if (Setting.table_exists? rescue(false))
|
14
|
+
end
|
15
|
+
|
12
16
|
initializer 'foreman_templates.register_plugin', :before => :finisher_hook do
|
13
17
|
Foreman::Plugin.register :foreman_templates do
|
14
|
-
requires_foreman '>= 1.
|
18
|
+
requires_foreman '>= 1.14'
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# Tasks
|
2
2
|
namespace :templates do
|
3
|
-
desc '
|
4
|
-
task :
|
3
|
+
desc 'Import templates according to settings'
|
4
|
+
task :import => :environment do
|
5
|
+
if Rake.application.top_level_tasks.include?('templates:sync')
|
6
|
+
ActiveSupport::Deprecation.warn('templates:sync task has been renamed to templates:import and will be removed in a future version')
|
7
|
+
end
|
5
8
|
# Available options:
|
6
9
|
#* verbose => Print extra information during the run [false]
|
7
10
|
#* repo => Sync templates from a different Git repo [https://github.com/theforeman/community-templates]
|
@@ -24,6 +27,24 @@ namespace :templates do
|
|
24
27
|
puts results.join("\n")
|
25
28
|
end
|
26
29
|
|
30
|
+
task :sync => :import
|
31
|
+
|
32
|
+
desc 'Export templates according to settings'
|
33
|
+
task :export => :environment do
|
34
|
+
ForemanTemplates::TemplateExporter.new({
|
35
|
+
verbose: ENV['verbose'],
|
36
|
+
repo: ENV['repo'],
|
37
|
+
branch: ENV['branch'],
|
38
|
+
prefix: ENV['prefix'],
|
39
|
+
dirname: ENV['dirname'],
|
40
|
+
filter: ENV['filter'],
|
41
|
+
# associate: ENV['associate'],
|
42
|
+
metadata_export_mode: ENV['metadata_export_mode'],
|
43
|
+
}).export!
|
44
|
+
|
45
|
+
puts 'Export finished'
|
46
|
+
end
|
47
|
+
|
27
48
|
desc 'Purge unwanted templates from foreman'
|
28
49
|
task :purge => :environment do
|
29
50
|
ForemanTemplates::TemplateImporter.new({
|
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:
|
4
|
+
version: 4.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:
|
11
|
+
date: 2017-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diffy
|
@@ -52,6 +52,9 @@ files:
|
|
52
52
|
- app/models/concerns/foreman_templates/provisioning_template_import.rb
|
53
53
|
- app/models/concerns/foreman_templates/ptable_import.rb
|
54
54
|
- app/models/concerns/foreman_templates/template_import.rb
|
55
|
+
- app/models/setting/template_sync.rb
|
56
|
+
- app/services/foreman_templates/action.rb
|
57
|
+
- app/services/foreman_templates/template_exporter.rb
|
55
58
|
- app/services/foreman_templates/template_importer.rb
|
56
59
|
- lib/foreman_templates.rb
|
57
60
|
- lib/foreman_templates/engine.rb
|