foreman_git_templates 1.0.0 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/app/controllers/concerns/foreman_git_templates/unattended_controller_extensions.rb +24 -0
- data/app/helpers/foreman_git_templates/application_helper.rb +23 -0
- data/app/lib/foreman_git_templates/renderer.rb +10 -2
- data/app/models/concerns/foreman_git_templates/host_extensions.rb +27 -2
- data/app/models/concerns/foreman_git_templates/host_parameter_extensions.rb +19 -0
- data/app/models/concerns/foreman_git_templates/hostext/operating_system.rb +3 -3
- data/app/models/concerns/foreman_git_templates/orchestration/tftp.rb +16 -6
- data/app/models/setting/git_templates.rb +26 -0
- data/app/services/foreman_git_templates/repository_fetcher.rb +1 -1
- data/app/services/foreman_git_templates/repository_reader.rb +5 -2
- data/lib/foreman_git_templates/engine.rb +12 -0
- data/lib/foreman_git_templates/version.rb +1 -1
- data/lib/tasks/foreman_git_templates_tasks.rake +3 -30
- data/test/controllers/hosts_controller_test.rb +1 -1
- data/test/controllers/unattended_controller_test.rb +51 -2
- data/test/factories/foreman_git_templates_factories.rb +3 -1
- data/test/models/concerns/foreman_git_templates/hostext/operating_system_test.rb +27 -1
- data/test/models/concerns/foreman_git_templates/orchestration/tftp_test.rb +47 -11
- data/test/models/foreman_git_templates/host_parameter_test.rb +57 -0
- data/test/models/foreman_git_templates/host_test.rb +91 -2
- data/test/unit/foreman/renderer_test.rb +40 -0
- metadata +47 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef1542116b039a0e33811e4eaa3c65b3c05da618735f47f9f30fe5dd9b243599
|
4
|
+
data.tar.gz: fbbd7adb1894aac45862a92653cc2e84667a1ea14a19c2a1e17ab44d882e6358
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ba5ffceb6a9049d268589824b73bcf9c1d135d05db12242e08473abe3a2aa47fe4aa21129baf27e646e42d1ce7cddad8d7272b23d173c8a3bb82a75d64dec43
|
7
|
+
data.tar.gz: 9539d07fd4eee73f05d467a5a5f3e2b83d3ff34337b155a96913c53cc69006b25840010d07df79b90ae2f0d219a986e341d094bc4c06b3b80b89525d28938fab
|
data/README.md
CHANGED
@@ -44,6 +44,14 @@ From now the template content for this host will be fetched from the repository.
|
|
44
44
|
- `There was an error rendering the provision template: Cannot read <template> from repository`
|
45
45
|
- check if there is requested template in the repository
|
46
46
|
|
47
|
+
### Gitlab Repository Integration
|
48
|
+
|
49
|
+
If you want to use a private repository hosted on a Gitlab instance to store your Foreman templates, you can use [Gitlab's repositories API](https://docs.gitlab.com/ee/api/repositories.html#get-file-archive) to construct the `template_url` parameter in Foreman. Create a dedicated Foreman user in Gitlab and set up a Personal Access Token that you can use in the `template_url`.
|
50
|
+
|
51
|
+
```
|
52
|
+
https://gitlab.example.com/api/v4/projects/${GITLAB_PROJECT_ID}/repository/archive.tar.gz?sha=${GITLAB_BRANCH_NAME}&private_token=${PERSONAL_ACCESS_TOKEN}
|
53
|
+
```
|
54
|
+
|
47
55
|
## Contributing
|
48
56
|
|
49
57
|
Fork and send a Pull Request. Thanks!
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanGitTemplates
|
4
|
+
module UnattendedControllerExtensions
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module Overrides
|
8
|
+
def render_local_boot_template
|
9
|
+
return super unless @host&.repository_path
|
10
|
+
|
11
|
+
return unless verify_found_host
|
12
|
+
|
13
|
+
template = ForemanGitTemplates::DefaultLocalBootRepositoryTemplate.new(name: 'iPXE')
|
14
|
+
safe_render(template)
|
15
|
+
rescue ForemanGitTemplates::RepositoryReader::MissingFileError
|
16
|
+
render_ipxe_message(message: _('iPXE default local boot template not found in repository at templates/iPXE/default_local_boot.erb'))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
included do
|
21
|
+
prepend Overrides
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanGitTemplates
|
4
|
+
module ApplicationHelper
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module Overrides
|
8
|
+
def display_link_if_authorized(name, options = {}, html_options = {})
|
9
|
+
# rubocop:disable Rails/HelperInstanceVariable
|
10
|
+
|
11
|
+
return if @host&.repository_path && options[:use_route] == 'edit_provisioning_template'
|
12
|
+
|
13
|
+
# rubocop:enable Rails/HelperInstanceVariable
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
included do
|
20
|
+
prepend Overrides
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -2,14 +2,22 @@
|
|
2
2
|
|
3
3
|
module ForemanGitTemplates
|
4
4
|
module Renderer
|
5
|
-
|
5
|
+
REPOSITORY_SOURCE_CLASS = ForemanGitTemplates::Renderer::Source::Repository
|
6
|
+
|
7
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
8
|
+
def get_source(klass: nil, template:, **args)
|
9
|
+
return super if klass && klass != REPOSITORY_SOURCE_CLASS
|
10
|
+
|
6
11
|
repository_path = repository_path(args[:host])
|
7
12
|
if repository_path
|
8
|
-
|
13
|
+
REPOSITORY_SOURCE_CLASS.new(template, repository_path)
|
14
|
+
elsif !repository_path && Gem::Version.new(SETTINGS[:version].version) < Gem::Version.new('1.23')
|
15
|
+
super(klass: klass || Foreman::Renderer::Source::Database, template: template, **args)
|
9
16
|
else
|
10
17
|
super
|
11
18
|
end
|
12
19
|
end
|
20
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
13
21
|
|
14
22
|
private
|
15
23
|
|
@@ -2,10 +2,35 @@
|
|
2
2
|
|
3
3
|
module ForemanGitTemplates
|
4
4
|
module HostExtensions
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
validates_associated :host_parameters
|
9
|
+
end
|
10
|
+
|
11
|
+
def repository_klass
|
12
|
+
build? ? MainRepositoryTemplate : DefaultLocalBootRepositoryTemplate
|
13
|
+
end
|
14
|
+
|
5
15
|
def repository_path
|
6
|
-
return unless
|
16
|
+
return unless git_template_url
|
17
|
+
|
18
|
+
git_template_tmpfile&.path
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def git_template_url
|
24
|
+
@git_template_url ||= host_params['template_url']
|
25
|
+
end
|
26
|
+
|
27
|
+
def git_template_tmpfile
|
28
|
+
return unless git_template_url
|
7
29
|
|
8
|
-
@
|
30
|
+
@git_template_tmpfile ||= RepositoryFetcher.call(git_template_url)
|
31
|
+
rescue ::ForemanGitTemplates::RepositoryFetcher::RepositoryFetcherError => e
|
32
|
+
Foreman::Logging.exception("GitTemplates: Failed to fetch data from #{git_template_url}", e)
|
33
|
+
nil
|
9
34
|
end
|
10
35
|
end
|
11
36
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanGitTemplates
|
4
|
+
module HostParameterExtensions
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
validate :template_url_is_reachable, if: ->(p) { p.name == 'template_url' }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def template_url_is_reachable
|
14
|
+
RestClient::Request.execute(method: :head, url: value, timeout: Setting::GitTemplates['template_url_validation_timeout'])
|
15
|
+
rescue RestClient::ExceptionWithResponse, URI::InvalidURIError, SocketError => e
|
16
|
+
errors.add(:value, _('Cannot fetch templates from %{url}: %{error}') % { url: value, error: e.message })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -9,7 +9,7 @@ module ForemanGitTemplates
|
|
9
9
|
def provisioning_template(opts = {})
|
10
10
|
return super unless repository_path
|
11
11
|
|
12
|
-
kind = opts[:kind] || 'provision'
|
12
|
+
kind = opts[:kind].to_s || 'provision'
|
13
13
|
available_template_kinds.find { |template| template.name == kind }
|
14
14
|
end
|
15
15
|
|
@@ -17,8 +17,8 @@ module ForemanGitTemplates
|
|
17
17
|
return super unless repository_path
|
18
18
|
|
19
19
|
@available_template_kinds ||= template_kinds(provisioning).map do |kind|
|
20
|
-
|
21
|
-
RepositoryReader.call(repository_path,
|
20
|
+
repository_klass.new(name: kind.name).tap do |t|
|
21
|
+
t.template = RepositoryReader.call(repository_path, t.path)
|
22
22
|
end
|
23
23
|
rescue RepositoryReader::FileUnreadableError # file is missing or empty
|
24
24
|
next
|
@@ -9,16 +9,26 @@ module ForemanGitTemplates
|
|
9
9
|
delegate :render_template, to: :host
|
10
10
|
|
11
11
|
def generate_pxe_template(kind)
|
12
|
-
return super unless host.
|
12
|
+
return super unless host.params['template_url']
|
13
13
|
|
14
|
-
|
15
|
-
template = template_klass.new(name: kind)
|
14
|
+
template = host.repository_klass.new(name: kind)
|
16
15
|
render_template(template: template)
|
17
|
-
rescue ForemanGitTemplates::RepositoryReader::MissingFileError
|
18
|
-
# re-raise the exception if we have a main template defined for this type
|
19
|
-
raise e if host.available_template_kinds.map(&:name).include?(kind)
|
16
|
+
rescue ForemanGitTemplates::RepositoryReader::MissingFileError
|
20
17
|
nil
|
21
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def validate_tftp
|
23
|
+
return super unless host.params['template_url']
|
24
|
+
return unless tftp? || tftp6?
|
25
|
+
return unless host.operatingsystem
|
26
|
+
|
27
|
+
pxe_kind = host.operatingsystem.pxe_loader_kind(host)
|
28
|
+
return unless pxe_kind && host.provisioning_template(kind: pxe_kind).nil?
|
29
|
+
|
30
|
+
failure _('No %{kind} template was found for host %{host}. Repository url: %{url}') % { kind: pxe_kind, host: host.name, url: host.params['template_url'] }
|
31
|
+
end
|
22
32
|
end
|
23
33
|
|
24
34
|
included do
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Setting
|
4
|
+
class GitTemplates < ::Setting
|
5
|
+
def self.default_settings
|
6
|
+
[
|
7
|
+
set('template_url_validation_timeout', N_('Template URL validation timeout in seconds'), 15, N_('Template URL validation timeout'))
|
8
|
+
]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.load_defaults
|
12
|
+
# Check the table exists
|
13
|
+
return unless super
|
14
|
+
|
15
|
+
transaction do
|
16
|
+
default_settings.each { |s| create! s.update(category: 'Setting::GitTemplates') }
|
17
|
+
end
|
18
|
+
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.humanized_category
|
23
|
+
N_('GitTemplates')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -9,7 +9,7 @@ module ForemanGitTemplates
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call
|
12
|
-
Down.download(repository_url)
|
12
|
+
Down.download(repository_url)
|
13
13
|
rescue Down::ResponseError => e
|
14
14
|
raise RepositoryFetcherError, "Cannot fetch repository from #{repository_url}. Response code: #{e.response.code}"
|
15
15
|
rescue Down::Error => e
|
@@ -9,6 +9,7 @@ module ForemanGitTemplates
|
|
9
9
|
|
10
10
|
def call
|
11
11
|
raise MissingFileError, "The #{file} file is missing" if content.nil?
|
12
|
+
|
12
13
|
content
|
13
14
|
end
|
14
15
|
|
@@ -30,13 +31,15 @@ module ForemanGitTemplates
|
|
30
31
|
@content ||= Tar.untar(repository_path) do |tar|
|
31
32
|
return tar.each do |entry|
|
32
33
|
next unless entry.file? && entry.full_name.end_with?(file)
|
34
|
+
|
33
35
|
break entry.read.tap do |entry_content|
|
34
36
|
raise EmptyFileError, "The #{file} file is empty" if entry_content.nil?
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
38
|
-
rescue Errno::ENOENT
|
39
|
-
|
40
|
+
rescue Errno::ENOENT, Zlib::GzipFile::Error => e
|
41
|
+
Foreman::Logging.exception("GitTemplates: Cannot read repository from #{repository_path}", e)
|
42
|
+
raise RepositoryUnreadableError, _('Cannot read repository from %{repository_path}: %{error}') % { repository_path: repository_path, error: e.message }
|
40
43
|
end
|
41
44
|
end
|
42
45
|
end
|
@@ -6,6 +6,15 @@ module ForemanGitTemplates
|
|
6
6
|
|
7
7
|
config.autoload_paths += Dir["#{config.root}/app/lib"]
|
8
8
|
config.autoload_paths += Dir["#{config.root}/app/services"]
|
9
|
+
config.autoload_paths += Dir["#{config.root}/app/controllers/concerns"]
|
10
|
+
|
11
|
+
initializer 'foreman_git_templates.load_default_settings', before: :load_config_initializers do
|
12
|
+
require_dependency File.expand_path('../../app/models/setting/git_templates.rb', __dir__) if begin
|
13
|
+
Setting.table_exists?
|
14
|
+
rescue StandardError
|
15
|
+
(false)
|
16
|
+
end
|
17
|
+
end
|
9
18
|
|
10
19
|
initializer 'foreman_git_templates.register_plugin', before: :finisher_hook do |_app|
|
11
20
|
Foreman::Plugin.register :foreman_git_templates do
|
@@ -18,7 +27,10 @@ module ForemanGitTemplates
|
|
18
27
|
Foreman::Renderer.singleton_class.prepend(ForemanGitTemplates::Renderer)
|
19
28
|
Host::Managed.include(ForemanGitTemplates::Hostext::OperatingSystem)
|
20
29
|
Host::Managed.include(ForemanGitTemplates::HostExtensions)
|
30
|
+
HostParameter.include(ForemanGitTemplates::HostParameterExtensions)
|
21
31
|
Nic::Managed.include(ForemanGitTemplates::Orchestration::TFTP)
|
32
|
+
UnattendedController.include(ForemanGitTemplates::UnattendedControllerExtensions)
|
33
|
+
::ApplicationHelper.include(ForemanGitTemplates::ApplicationHelper)
|
22
34
|
rescue StandardError => e
|
23
35
|
Rails.logger.warn "ForemanGitTemplates: skipping engine hook (#{e})"
|
24
36
|
end
|
@@ -2,46 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
|
5
|
-
# Tasks
|
6
|
-
namespace :foreman_git_templates do
|
7
|
-
namespace :example do
|
8
|
-
desc 'Example Task'
|
9
|
-
task task: :environment do
|
10
|
-
# Task goes here
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
5
|
# Tests
|
16
6
|
namespace :test do
|
17
7
|
desc 'Test ForemanGitTemplates'
|
18
8
|
Rake::TestTask.new(:foreman_git_templates) do |t|
|
19
|
-
test_dir = File.join(
|
9
|
+
test_dir = File.join(ForemanGitTemplates::Engine.root, 'test')
|
20
10
|
t.libs << ['test', test_dir]
|
21
|
-
t.pattern =
|
11
|
+
t.pattern = File.join(test_dir, '**', '*_test.rb')
|
22
12
|
t.verbose = true
|
23
13
|
t.warning = false
|
24
14
|
end
|
25
15
|
end
|
26
16
|
|
27
|
-
namespace :foreman_git_templates do
|
28
|
-
task :rubocop do
|
29
|
-
begin
|
30
|
-
require 'rubocop/rake_task'
|
31
|
-
RuboCop::RakeTask.new(:rubocop_foreman_git_templates) do |task|
|
32
|
-
task.patterns = ["#{ForemanGitTemplates::Engine.root}/app/**/*.rb",
|
33
|
-
"#{ForemanGitTemplates::Engine.root}/lib/**/*.rb",
|
34
|
-
"#{ForemanGitTemplates::Engine.root}/test/**/*.rb"]
|
35
|
-
end
|
36
|
-
rescue StandardError
|
37
|
-
puts 'Rubocop not loaded.'
|
38
|
-
end
|
39
|
-
|
40
|
-
Rake::Task['rubocop_foreman_git_templates'].invoke
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
17
|
Rake::Task[:test].enhance ['test:foreman_git_templates']
|
45
18
|
|
46
19
|
load 'tasks/jenkins.rake'
|
47
|
-
Rake::Task['jenkins:unit'].enhance ['test:foreman_git_templates'
|
20
|
+
Rake::Task['jenkins:unit'].enhance ['test:foreman_git_templates'] if Rake::Task.task_defined?(:'jenkins:unit')
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'test_plugin_helper'
|
4
4
|
|
5
5
|
class HostsControllerTest < ActionController::TestCase
|
6
|
-
let(:host) { FactoryBot.create(:host, :managed, :with_template_url) }
|
6
|
+
let(:host) { FactoryBot.create(:host, :managed, :with_template_url, build: true) }
|
7
7
|
|
8
8
|
describe '#templates' do
|
9
9
|
it 'returns only templates that are defined in the archive' do
|
@@ -3,9 +3,9 @@
|
|
3
3
|
require 'test_plugin_helper'
|
4
4
|
|
5
5
|
class UnattendedControllerTest < ActionController::TestCase
|
6
|
-
let(:os) { FactoryBot.create(:operatingsystem, :
|
6
|
+
let(:os) { FactoryBot.create(:operatingsystem, :with_associations, type: 'Redhat') }
|
7
7
|
let(:host) do
|
8
|
-
FactoryBot.create(:host, :managed, :with_template_url, operatingsystem: os, ptable: os.ptables.first)
|
8
|
+
FactoryBot.create(:host, :managed, :with_template_url, build: true, operatingsystem: os, ptable: os.ptables.first)
|
9
9
|
end
|
10
10
|
|
11
11
|
test 'should render template from repository' do
|
@@ -68,4 +68,53 @@ class UnattendedControllerTest < ActionController::TestCase
|
|
68
68
|
assert_equal 'foo bar', response.body.strip
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
describe 'iPXE templates' do
|
73
|
+
let(:host) do
|
74
|
+
FactoryBot.create(:host, :managed, :with_template_url, build: false, operatingsystem: os, ptable: os.ptables.first)
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'host not in build mode' do
|
78
|
+
test 'should render iPXE local boot template from repository' do
|
79
|
+
assert_not_nil host.params['template_url']
|
80
|
+
|
81
|
+
Dir.mktmpdir do |dir|
|
82
|
+
kind = 'iPXE'
|
83
|
+
|
84
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
85
|
+
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, 5) { |io| io.write('local') }
|
86
|
+
tar.add_file_simple("templates/#{kind}/template.erb", 644, host.name.length) { |io| io.write(host.name) }
|
87
|
+
end
|
88
|
+
|
89
|
+
get :host_template, params: { kind: kind, hostname: host.name }, session: set_session_user
|
90
|
+
assert_response :success
|
91
|
+
assert_equal 'local', response.body.strip
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'host in build mode' do
|
97
|
+
setup do
|
98
|
+
host.update!(build: true)
|
99
|
+
end
|
100
|
+
|
101
|
+
test 'should render iPXE template from repository' do
|
102
|
+
host.reload
|
103
|
+
assert_not_nil host.params['template_url']
|
104
|
+
|
105
|
+
Dir.mktmpdir do |dir|
|
106
|
+
kind = 'iPXE'
|
107
|
+
|
108
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
109
|
+
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, 5) { |io| io.write('local') }
|
110
|
+
tar.add_file_simple("templates/#{kind}/template.erb", 644, host.name.length) { |io| io.write(host.name) }
|
111
|
+
end
|
112
|
+
|
113
|
+
get :host_template, params: { kind: kind, hostname: host.name }, session: set_session_user
|
114
|
+
assert_response :success
|
115
|
+
assert_equal host.name, response.body.strip
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
71
120
|
end
|
@@ -4,7 +4,9 @@ FactoryBot.modify do
|
|
4
4
|
factory :host do
|
5
5
|
trait :with_template_url do
|
6
6
|
after(:create) do |host, _evaluator|
|
7
|
-
|
7
|
+
url = 'http://www.api.com/repository.tar.gz'
|
8
|
+
WebMock::API.stub_request(:head, url).to_return(status: 200)
|
9
|
+
FactoryBot.create(:host_parameter, host: host, name: 'template_url', value: url)
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
@@ -4,7 +4,33 @@ require 'test_plugin_helper'
|
|
4
4
|
|
5
5
|
module Hostext
|
6
6
|
class OperatingSystemTest < ActiveSupport::TestCase
|
7
|
-
let(:host) { FactoryBot.create(:host, :managed, :with_template_url) }
|
7
|
+
let(:host) { FactoryBot.create(:host, :managed, :with_template_url, build: true) }
|
8
|
+
|
9
|
+
describe '#provisioning_template' do
|
10
|
+
it 'finds all PXELinux template kinds' do
|
11
|
+
Dir.mktmpdir do |dir|
|
12
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
13
|
+
tar.add_file_simple('templates/PXELinux/template.erb', 644, host.name.length) { |io| io.write(host.name) }
|
14
|
+
end
|
15
|
+
|
16
|
+
actual = host.provisioning_template(kind: 'PXELinux')
|
17
|
+
assert_equal 'PXELinux', actual.name
|
18
|
+
assert_equal host.name, actual.template
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'finds all PXELinux template kinds by symbol' do
|
23
|
+
Dir.mktmpdir do |dir|
|
24
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
25
|
+
tar.add_file_simple('templates/PXELinux/template.erb', 644, host.name.length) { |io| io.write(host.name) }
|
26
|
+
end
|
27
|
+
|
28
|
+
actual = host.provisioning_template(kind: :PXELinux)
|
29
|
+
assert_equal 'PXELinux', actual.name
|
30
|
+
assert_equal host.name, actual.template
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
8
34
|
|
9
35
|
test 'available_template_kinds finds only templates that are defined in the repository' do
|
10
36
|
Dir.mktmpdir do |dir|
|
@@ -15,10 +15,19 @@ class TFTPOrchestrationTest < ActiveSupport::TestCase
|
|
15
15
|
Dir.mktmpdir do |dir|
|
16
16
|
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
17
17
|
tar.add_file_simple("templates/#{kind}/template.erb", 644, template_content.length) { |io| io.write(template_content) }
|
18
|
-
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, default_local_boot_template_content.length) { |io| io.write(default_local_boot_template_content) }
|
19
18
|
end
|
20
19
|
|
21
|
-
assert_equal template_content, host.generate_pxe_template(
|
20
|
+
assert_equal template_content, host.generate_pxe_template(kind)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when corresponding default local boot template file is missing in the repo' do
|
25
|
+
it 'does not generate a pxe template' do
|
26
|
+
Dir.mktmpdir do |dir|
|
27
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz"
|
28
|
+
|
29
|
+
assert_nil host.generate_pxe_template(kind)
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
@@ -29,41 +38,67 @@ class TFTPOrchestrationTest < ActiveSupport::TestCase
|
|
29
38
|
it 'renders default local boot template' do
|
30
39
|
Dir.mktmpdir do |dir|
|
31
40
|
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
32
|
-
tar.add_file_simple("templates/#{kind}/template.erb", 644, template_content.length) { |io| io.write(template_content) }
|
33
41
|
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, default_local_boot_template_content.length) { |io| io.write(default_local_boot_template_content) }
|
34
42
|
end
|
35
43
|
|
36
|
-
assert_equal default_local_boot_template_content, host.generate_pxe_template(
|
44
|
+
assert_equal default_local_boot_template_content, host.generate_pxe_template(kind)
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
40
|
-
|
48
|
+
context 'when corresponding default local boot template file is missing in the repo' do
|
49
|
+
it 'does not generate a pxe template' do
|
50
|
+
Dir.mktmpdir do |dir|
|
51
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz"
|
52
|
+
|
53
|
+
assert_nil host.generate_pxe_template(kind)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#validate_tftp' do
|
61
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, build: false, pxe_loader: 'PXELinux BIOS') }
|
62
|
+
let(:kind) { 'PXELinux' }
|
63
|
+
let(:template_content) { 'main template content' }
|
64
|
+
let(:default_local_boot_template_content) { 'default local boot template content' }
|
65
|
+
|
66
|
+
context 'host is in build mode' do
|
67
|
+
setup do
|
68
|
+
host.primary_interface.expects(:valid?).returns(true) if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
69
|
+
host.update(build: true)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'validates that the host is ready for tftp' do
|
41
73
|
Dir.mktmpdir do |dir|
|
42
74
|
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
43
75
|
tar.add_file_simple("templates/#{kind}/template.erb", 644, template_content.length) { |io| io.write(template_content) }
|
44
76
|
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, default_local_boot_template_content.length) { |io| io.write(default_local_boot_template_content) }
|
45
77
|
end
|
46
78
|
|
47
|
-
|
79
|
+
host.provision_interface.send(:validate_tftp)
|
80
|
+
assert_empty host.errors.messages
|
48
81
|
end
|
49
82
|
end
|
83
|
+
end
|
50
84
|
|
51
|
-
|
85
|
+
context 'host is not build mode' do
|
86
|
+
it 'validates that the host is ready for tftp' do
|
52
87
|
Dir.mktmpdir do |dir|
|
53
88
|
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
54
89
|
tar.add_file_simple("templates/#{kind}/template.erb", 644, template_content.length) { |io| io.write(template_content) }
|
90
|
+
tar.add_file_simple("templates/#{kind}/default_local_boot.erb", 644, default_local_boot_template_content.length) { |io| io.write(default_local_boot_template_content) }
|
55
91
|
end
|
56
92
|
|
57
|
-
|
58
|
-
|
59
|
-
end
|
93
|
+
host.provision_interface.send(:validate_tftp)
|
94
|
+
assert_empty host.errors.messages
|
60
95
|
end
|
61
96
|
end
|
62
97
|
end
|
63
98
|
end
|
64
99
|
|
65
100
|
describe '#setTFTP' do
|
66
|
-
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url) }
|
101
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, pxe_loader: 'PXELinux BIOS') }
|
67
102
|
|
68
103
|
let(:kind) { 'PXELinux' }
|
69
104
|
let(:template_content) { 'main template content' }
|
@@ -71,6 +106,7 @@ class TFTPOrchestrationTest < ActiveSupport::TestCase
|
|
71
106
|
|
72
107
|
context 'host is in build mode' do
|
73
108
|
setup do
|
109
|
+
host.primary_interface.expects(:valid?).returns(true) if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
74
110
|
host.update(build: true)
|
75
111
|
end
|
76
112
|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
module ForemanGitTemplates
|
6
|
+
class HostParameterTest < ActiveSupport::TestCase
|
7
|
+
describe 'template_url validation' do
|
8
|
+
let(:template_url) { 'http://api.com/repo.tar.gz' }
|
9
|
+
let(:host) { FactoryBot.create(:host) }
|
10
|
+
let(:host_parameter) { FactoryBot.build(:host_parameter, name: 'template_url', value: template_url, host: host) }
|
11
|
+
|
12
|
+
context 'when template_url returns 200' do
|
13
|
+
it 'is valid' do
|
14
|
+
stub_request(:head, template_url).to_return(status: 200)
|
15
|
+
|
16
|
+
assert host_parameter.valid?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when template_url returns 401' do
|
21
|
+
it 'is invlid' do
|
22
|
+
stub_request(:head, template_url).to_return(status: 401)
|
23
|
+
|
24
|
+
assert_equal false, host_parameter.valid?
|
25
|
+
assert_not_empty host_parameter.errors[:value]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when template_url returns 404' do
|
30
|
+
it 'is invlid' do
|
31
|
+
stub_request(:head, template_url).to_return(status: 404)
|
32
|
+
|
33
|
+
assert_equal false, host_parameter.valid?
|
34
|
+
assert_not_empty host_parameter.errors[:value]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when template_url returns 500' do
|
39
|
+
it 'is invlid' do
|
40
|
+
stub_request(:head, template_url).to_return(status: 500)
|
41
|
+
|
42
|
+
assert_equal false, host_parameter.valid?
|
43
|
+
assert_not_empty host_parameter.errors[:value]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when template_url is not a valid URL' do
|
48
|
+
let(:template_url) { 'not URL value' }
|
49
|
+
|
50
|
+
it 'is invlid' do
|
51
|
+
assert_equal false, host_parameter.valid?
|
52
|
+
assert_not_empty host_parameter.errors[:value]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -6,11 +6,12 @@ module ForemanGitTemplates
|
|
6
6
|
class HostTest < ActiveSupport::TestCase
|
7
7
|
describe '#repository_path' do
|
8
8
|
context 'with template_url parameter' do
|
9
|
-
let(:
|
9
|
+
let(:repo_tempfile) { Tempfile.new }
|
10
|
+
let(:repo_path) { repo_tempfile.path }
|
10
11
|
let(:host) { FactoryBot.create(:host, :managed, :with_template_url) }
|
11
12
|
|
12
13
|
it 'returns path to the repository' do
|
13
|
-
ForemanGitTemplates::RepositoryFetcher.expects(:call).once.with(host.params['template_url']).returns(
|
14
|
+
ForemanGitTemplates::RepositoryFetcher.expects(:call).once.with(host.params['template_url']).returns(repo_tempfile)
|
14
15
|
assert_equal repo_path, host.repository_path
|
15
16
|
end
|
16
17
|
end
|
@@ -24,5 +25,93 @@ module ForemanGitTemplates
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
28
|
+
|
29
|
+
describe '#update' do
|
30
|
+
let(:os) { FactoryBot.create(:operatingsystem, :with_associations, type: 'Redhat') }
|
31
|
+
|
32
|
+
setup do
|
33
|
+
host.expects(:skip_orchestration_for_testing?).at_least_once.returns(false)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with valid template_url' do
|
37
|
+
setup do
|
38
|
+
ProxyAPI::TFTP.any_instance.expects(:set).returns(true)
|
39
|
+
|
40
|
+
if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
41
|
+
ProxyAPI::TFTP.any_instance.expects(:bootServer).returns('127.0.0.1')
|
42
|
+
ProxyAPI::DHCP.any_instance.expects(:set).returns(true)
|
43
|
+
ProxyAPI::DHCP.any_instance.expects(:record).with(host.subnet.network, host.dhcp_records.first.mac).returns(host.dhcp_records.first)
|
44
|
+
ProxyAPI::DHCP.any_instance.expects(:records_by_ip).with(host.subnet.network, host.provision_interface.ip).returns([host.dhcp_records.first])
|
45
|
+
ProxyAPI::DHCP.any_instance.expects(:delete).returns(true)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when host is in build mode' do
|
50
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, operatingsystem: os, build: true) }
|
51
|
+
|
52
|
+
it 'updates the host' do
|
53
|
+
ProxyAPI::TFTP.any_instance.expects(:fetch_boot_file).twice.returns(true)
|
54
|
+
|
55
|
+
Dir.mktmpdir do |dir|
|
56
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
57
|
+
tar.add_file_simple('templates/PXEGrub2/template.erb', 644, host.name.length) { |io| io.write(host.name) }
|
58
|
+
end
|
59
|
+
|
60
|
+
assert host.update(name: 'newname')
|
61
|
+
assert_empty host.errors.messages
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when host is not in build mode' do
|
67
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, operatingsystem: os, build: false) }
|
68
|
+
|
69
|
+
it 'updates the host' do
|
70
|
+
Dir.mktmpdir do |dir|
|
71
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
72
|
+
tar.add_file_simple('templates/PXEGrub2/default_local_boot.erb', 644, host.name.length) { |io| io.write(host.name) }
|
73
|
+
end
|
74
|
+
|
75
|
+
assert host.update(name: 'newname')
|
76
|
+
assert_empty host.errors.messages
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with invalid template_url' do
|
83
|
+
setup do
|
84
|
+
stub_request(:get, host.params['template_url']).to_return(status: 404)
|
85
|
+
|
86
|
+
if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
87
|
+
ProxyAPI::TFTP.any_instance.expects(:bootServer).returns('127.0.0.1')
|
88
|
+
ProxyAPI::DHCP.any_instance.expects(:record).with(host.subnet.network, host.dhcp_records.first.mac).returns(host.dhcp_records.first)
|
89
|
+
ProxyAPI::DHCP.any_instance.expects(:records_by_ip).with(host.subnet.network, host.provision_interface.ip).returns([host.dhcp_records.first])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:expected_errors) { ["No PXEGrub2 template was found for host #{host.name}. Repository url: #{host.params['template_url']}"] }
|
94
|
+
|
95
|
+
context 'when host is in build mode' do
|
96
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, operatingsystem: os, build: true) }
|
97
|
+
|
98
|
+
it 'does not update the host' do
|
99
|
+
assert_equal false, host.update(name: 'newname')
|
100
|
+
assert_equal expected_errors, host.errors[:base]
|
101
|
+
assert_equal expected_errors, host.errors[:'interfaces.base']
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when host is not in build mode' do
|
106
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, operatingsystem: os, build: false) }
|
107
|
+
|
108
|
+
it 'does not update the host' do
|
109
|
+
assert_equal false, host.update(name: 'newname')
|
110
|
+
assert_equal expected_errors, host.errors[:base]
|
111
|
+
assert_equal expected_errors, host.errors[:'interfaces.base']
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
27
116
|
end
|
28
117
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
class RendererTest < ActiveSupport::TestCase
|
6
|
+
describe '.get_source' do
|
7
|
+
subject { Foreman::Renderer.get_source(template: template, host: host, klass: source_klass) }
|
8
|
+
|
9
|
+
let(:template) { FactoryBot.create(:provisioning_template) }
|
10
|
+
|
11
|
+
context 'when the host has a template_url defined' do
|
12
|
+
let(:host) { FactoryBot.create(:host, :with_template_url) }
|
13
|
+
|
14
|
+
context 'when the source class is not passed' do
|
15
|
+
let(:source_klass) { nil }
|
16
|
+
|
17
|
+
it 'uses ForemanGitTemplates::Renderer::Source::Repository' do
|
18
|
+
Dir.mktmpdir do |dir|
|
19
|
+
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz"
|
20
|
+
|
21
|
+
assert_equal ForemanGitTemplates::Renderer::Source::Repository, subject.class
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when the source class is implicitly passed' do
|
27
|
+
let(:source_klass) { Foreman::Renderer::Source::Database }
|
28
|
+
|
29
|
+
it { assert_equal Foreman::Renderer::Source::Database, subject.class }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when the host has no template_url defined' do
|
34
|
+
let(:host) { FactoryBot.create(:host) }
|
35
|
+
let(:source_klass) { nil }
|
36
|
+
|
37
|
+
it { assert_equal Foreman::Renderer::Source::Database, subject.class }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_git_templates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dmTECH GmbH
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: down
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rdoc
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -42,17 +56,31 @@ dependencies:
|
|
42
56
|
name: rubocop
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- -
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0
|
75
|
+
version: '0'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
|
-
- -
|
80
|
+
- - ">="
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0
|
55
|
-
description:
|
82
|
+
version: '0'
|
83
|
+
description:
|
56
84
|
email:
|
57
85
|
- opensource@dm.de
|
58
86
|
executables: []
|
@@ -62,16 +90,20 @@ files:
|
|
62
90
|
- LICENSE
|
63
91
|
- README.md
|
64
92
|
- Rakefile
|
93
|
+
- app/controllers/concerns/foreman_git_templates/unattended_controller_extensions.rb
|
94
|
+
- app/helpers/foreman_git_templates/application_helper.rb
|
65
95
|
- app/lib/foreman_git_templates/renderer.rb
|
66
96
|
- app/lib/foreman_git_templates/renderer/source/repository.rb
|
67
97
|
- app/lib/foreman_git_templates/tar.rb
|
68
98
|
- app/models/concerns/foreman_git_templates/host_extensions.rb
|
99
|
+
- app/models/concerns/foreman_git_templates/host_parameter_extensions.rb
|
69
100
|
- app/models/concerns/foreman_git_templates/hostext/operating_system.rb
|
70
101
|
- app/models/concerns/foreman_git_templates/orchestration/tftp.rb
|
71
102
|
- app/models/foreman_git_templates/base_repository_template.rb
|
72
103
|
- app/models/foreman_git_templates/default_local_boot_repository_template.rb
|
73
104
|
- app/models/foreman_git_templates/main_repository_template.rb
|
74
105
|
- app/models/foreman_git_templates/snippet_repository_template.rb
|
106
|
+
- app/models/setting/git_templates.rb
|
75
107
|
- app/services/foreman_git_templates/repository_fetcher.rb
|
76
108
|
- app/services/foreman_git_templates/repository_reader.rb
|
77
109
|
- config/routes.rb
|
@@ -84,17 +116,19 @@ files:
|
|
84
116
|
- test/factories/foreman_git_templates_factories.rb
|
85
117
|
- test/models/concerns/foreman_git_templates/hostext/operating_system_test.rb
|
86
118
|
- test/models/concerns/foreman_git_templates/orchestration/tftp_test.rb
|
119
|
+
- test/models/foreman_git_templates/host_parameter_test.rb
|
87
120
|
- test/models/foreman_git_templates/host_test.rb
|
88
121
|
- test/models/foreman_git_templates/snippet_repository_template_test.rb
|
89
122
|
- test/test_plugin_helper.rb
|
90
123
|
- test/unit/foreman/renderer/source/repository_test.rb
|
124
|
+
- test/unit/foreman/renderer_test.rb
|
91
125
|
- test/unit/repository_fetcher_test.rb
|
92
126
|
- test/unit/repository_reader_test.rb
|
93
127
|
homepage: https://github.com/dm-drogeriemarkt/foreman_git_templates
|
94
128
|
licenses:
|
95
129
|
- GPL-3.0
|
96
130
|
metadata: {}
|
97
|
-
post_install_message:
|
131
|
+
post_install_message:
|
98
132
|
rdoc_options: []
|
99
133
|
require_paths:
|
100
134
|
- lib
|
@@ -109,17 +143,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
143
|
- !ruby/object:Gem::Version
|
110
144
|
version: '0'
|
111
145
|
requirements: []
|
112
|
-
|
113
|
-
|
114
|
-
signing_key:
|
146
|
+
rubygems_version: 3.1.2
|
147
|
+
signing_key:
|
115
148
|
specification_version: 4
|
116
149
|
summary: Adds support for using templates from Git repositories
|
117
150
|
test_files:
|
118
151
|
- test/unit/repository_fetcher_test.rb
|
119
152
|
- test/unit/foreman/renderer/source/repository_test.rb
|
153
|
+
- test/unit/foreman/renderer_test.rb
|
120
154
|
- test/unit/repository_reader_test.rb
|
121
155
|
- test/models/foreman_git_templates/snippet_repository_template_test.rb
|
122
156
|
- test/models/foreman_git_templates/host_test.rb
|
157
|
+
- test/models/foreman_git_templates/host_parameter_test.rb
|
123
158
|
- test/models/concerns/foreman_git_templates/hostext/operating_system_test.rb
|
124
159
|
- test/models/concerns/foreman_git_templates/orchestration/tftp_test.rb
|
125
160
|
- test/factories/foreman_git_templates_factories.rb
|