foreman_git_templates 1.0.1 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- 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 +8 -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 +2 -2
- data/app/models/concerns/foreman_git_templates/orchestration/tftp.rb +23 -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 +7 -3
- data/test/models/concerns/foreman_git_templates/orchestration/tftp_test.rb +20 -23
- 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: 030b1cb7373a31b3b7a72326668906b00d523c5c92a0a62e41d2467570aa9d8e
|
4
|
+
data.tar.gz: 0b27bc9ebb34b8b288234b366a6d1ac431eb0413d883e08ba605a9d419f2660a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1fcc6b0035e91332f0600389db9445ca00c201c534ec19c26e2b55e0f2e33f23df73d0904b0256bdd81b7cf8b77903a3c17480aeb47174931c70efe11065b3e
|
7
|
+
data.tar.gz: 6ef071e866eeca0076167ab6f04a780cd3b4c46b88bec95cb241a8fb91cc193e64e01aafd65c79d5c813ed59480f742a836675be62a50eb0621318db026e773d
|
@@ -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,10 +2,16 @@
|
|
2
2
|
|
3
3
|
module ForemanGitTemplates
|
4
4
|
module Renderer
|
5
|
-
|
5
|
+
REPOSITORY_SOURCE_CLASS = ForemanGitTemplates::Renderer::Source::Repository
|
6
|
+
|
7
|
+
def get_source(klass: nil, template:, **args)
|
8
|
+
return super if klass && klass != REPOSITORY_SOURCE_CLASS
|
9
|
+
|
6
10
|
repository_path = repository_path(args[:host])
|
7
11
|
if repository_path
|
8
|
-
|
12
|
+
REPOSITORY_SOURCE_CLASS.new(template, repository_path)
|
13
|
+
elsif !repository_path && Gem::Version.new(SETTINGS[:version].version) < Gem::Version.new('1.23')
|
14
|
+
super(klass: klass || Foreman::Renderer::Source::Database, template: template, **args)
|
9
15
|
else
|
10
16
|
super
|
11
17
|
end
|
@@ -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
|
@@ -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,33 @@ 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 feasible_for_git_template_rendering?
|
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
|
32
|
+
|
33
|
+
def feasible_for_git_template_rendering?
|
34
|
+
return false unless host.is_a?(Host::Managed)
|
35
|
+
return false unless host.params['template_url']
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
22
39
|
end
|
23
40
|
|
24
41
|
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,7 @@ 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
8
|
|
9
9
|
describe '#provisioning_template' do
|
10
10
|
it 'finds all PXELinux template kinds' do
|
@@ -13,7 +13,9 @@ module Hostext
|
|
13
13
|
tar.add_file_simple('templates/PXELinux/template.erb', 644, host.name.length) { |io| io.write(host.name) }
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
actual = host.provisioning_template(kind: 'PXELinux')
|
17
|
+
assert_equal 'PXELinux', actual.name
|
18
|
+
assert_equal host.name, actual.template
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -23,7 +25,9 @@ module Hostext
|
|
23
25
|
tar.add_file_simple('templates/PXELinux/template.erb', 644, host.name.length) { |io| io.write(host.name) }
|
24
26
|
end
|
25
27
|
|
26
|
-
|
28
|
+
actual = host.provisioning_template(kind: :PXELinux)
|
29
|
+
assert_equal 'PXELinux', actual.name
|
30
|
+
assert_equal host.name, actual.template
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
@@ -15,47 +15,42 @@ 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)
|
22
21
|
end
|
23
22
|
end
|
24
|
-
end
|
25
23
|
|
26
|
-
|
27
|
-
|
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
28
|
|
29
|
-
|
30
|
-
Dir.mktmpdir do |dir|
|
31
|
-
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
|
-
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) }
|
29
|
+
assert_nil host.generate_pxe_template(kind)
|
34
30
|
end
|
35
|
-
|
36
|
-
assert_equal default_local_boot_template_content, host.generate_pxe_template('PXELinux')
|
37
31
|
end
|
38
32
|
end
|
33
|
+
end
|
39
34
|
|
40
|
-
|
35
|
+
context 'host is not in build mode' do
|
36
|
+
let(:host) { FactoryBot.create(:host, :managed, :with_template_url, build: false) }
|
37
|
+
|
38
|
+
it 'renders default local boot template' do
|
41
39
|
Dir.mktmpdir do |dir|
|
42
40
|
stub_repository host.params['template_url'], "#{dir}/repo.tar.gz" do |tar|
|
43
|
-
tar.add_file_simple("templates/#{kind}/template.erb", 644, template_content.length) { |io| io.write(template_content) }
|
44
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) }
|
45
42
|
end
|
46
43
|
|
47
|
-
|
44
|
+
assert_equal default_local_boot_template_content, host.generate_pxe_template(kind)
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
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"
|
56
52
|
|
57
|
-
|
58
|
-
host.generate_pxe_template('PXELinux')
|
53
|
+
assert_nil host.generate_pxe_template(kind)
|
59
54
|
end
|
60
55
|
end
|
61
56
|
end
|
@@ -63,13 +58,14 @@ class TFTPOrchestrationTest < ActiveSupport::TestCase
|
|
63
58
|
end
|
64
59
|
|
65
60
|
describe '#validate_tftp' do
|
66
|
-
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, pxe_loader: 'PXELinux BIOS') }
|
61
|
+
let(:host) { FactoryBot.create(:host, :with_tftp_orchestration, :with_template_url, build: false, pxe_loader: 'PXELinux BIOS') }
|
67
62
|
let(:kind) { 'PXELinux' }
|
68
63
|
let(:template_content) { 'main template content' }
|
69
64
|
let(:default_local_boot_template_content) { 'default local boot template content' }
|
70
65
|
|
71
66
|
context 'host is in build mode' do
|
72
67
|
setup do
|
68
|
+
host.primary_interface.expects(:valid?).returns(true) if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
73
69
|
host.update(build: true)
|
74
70
|
end
|
75
71
|
|
@@ -110,6 +106,7 @@ class TFTPOrchestrationTest < ActiveSupport::TestCase
|
|
110
106
|
|
111
107
|
context 'host is in build mode' do
|
112
108
|
setup do
|
109
|
+
host.primary_interface.expects(:valid?).returns(true) if Gem::Version.new(SETTINGS[:version].notag) >= Gem::Version.new('2.0')
|
113
110
|
host.update(build: true)
|
114
111
|
end
|
115
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.6
|
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-08-13 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.89.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.89.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
|