foreman_discovery 15.0.2 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/api/v2/discovery_rules_controller.rb +1 -1
- data/app/controllers/concerns/foreman/controller/discovered_extensions.rb +4 -0
- data/app/controllers/discovered_hosts_controller.rb +6 -3
- data/app/controllers/discovery_rules_controller.rb +1 -1
- data/app/models/discovery_rule.rb +1 -1
- data/app/models/host/discovered.rb +49 -31
- data/app/models/host/managed_extensions.rb +2 -2
- data/app/models/setting/discovered.rb +28 -33
- data/app/services/foreman_discovery/fact_parser.rb +1 -1
- data/app/services/foreman_discovery/host_converter.rb +38 -2
- data/app/services/foreman_discovery/host_fact_importer.rb +10 -0
- data/app/services/foreman_discovery/import_hooks/subnet_and_taxonomy.rb +6 -14
- data/app/services/foreman_discovery/node_api/node_resource.rb +1 -0
- data/app/services/foreman_discovery/subnet_suggestion.rb +26 -0
- data/app/views/foreman_discovery/debian_kexec.erb +3 -2
- data/app/views/foreman_discovery/redhat_kexec.erb +2 -1
- data/config/routes.rb +2 -0
- data/db/migrate/20150512150432_remove_old_discovery_reader_permissions.rb +1 -1
- data/db/migrate/20151023144501_regenerate_red_hat_kexec.rb +1 -1
- data/db/migrate/20180412124505_add_priority_score_to_discovery_rules.rb +1 -1
- data/extra/discover-host +34 -14
- data/lib/foreman_discovery/engine.rb +4 -4
- data/lib/foreman_discovery/version.rb +1 -1
- data/locale/ca/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/ca/foreman_discovery.edit.po +122 -93
- data/locale/ca/foreman_discovery.po +31 -8
- data/locale/de/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/de/foreman_discovery.edit.po +125 -96
- data/locale/de/foreman_discovery.po +34 -11
- data/locale/en/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/en/foreman_discovery.edit.po +118 -88
- data/locale/en/foreman_discovery.po +27 -4
- data/locale/en_GB/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/en_GB/foreman_discovery.edit.po +125 -96
- data/locale/en_GB/foreman_discovery.po +34 -11
- data/locale/es/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/es/foreman_discovery.edit.po +124 -95
- data/locale/es/foreman_discovery.po +33 -10
- data/locale/foreman_discovery.pot +119 -89
- data/locale/fr/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/fr/foreman_discovery.edit.po +122 -93
- data/locale/fr/foreman_discovery.po +31 -8
- data/locale/gl/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/gl/foreman_discovery.edit.po +120 -91
- data/locale/gl/foreman_discovery.po +29 -6
- data/locale/it/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/it/foreman_discovery.edit.po +120 -91
- data/locale/it/foreman_discovery.po +29 -6
- data/locale/ja/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/ja/foreman_discovery.edit.po +123 -94
- data/locale/ja/foreman_discovery.po +32 -9
- data/locale/ko/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/ko/foreman_discovery.edit.po +122 -93
- data/locale/ko/foreman_discovery.po +31 -8
- data/locale/pt_BR/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/pt_BR/foreman_discovery.edit.po +123 -94
- data/locale/pt_BR/foreman_discovery.po +32 -9
- data/locale/ru/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/ru/foreman_discovery.edit.po +123 -94
- data/locale/ru/foreman_discovery.po +32 -9
- data/locale/sv_SE/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/sv_SE/foreman_discovery.edit.po +121 -92
- data/locale/sv_SE/foreman_discovery.po +30 -7
- data/locale/zh_CN/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/zh_CN/foreman_discovery.edit.po +122 -93
- data/locale/zh_CN/foreman_discovery.po +31 -8
- data/locale/zh_TW/LC_MESSAGES/foreman_discovery.mo +0 -0
- data/locale/zh_TW/foreman_discovery.edit.po +120 -91
- data/locale/zh_TW/foreman_discovery.po +29 -6
- data/test/facts/bond0-eth0-eth1-active-passive.json +128 -0
- data/test/facts/facts_with_lldp_bond_candidate.json +2 -9
- data/test/facts/only-ipv6.json +205 -0
- data/test/facts/skylake-ipv6.json +223 -0
- data/test/functional/api/v2/discovered_hosts_controller_test.rb +1 -0
- data/test/functional/api/v2/settings_controller_test.rb +2 -2
- data/test/functional/discovered_hosts_controller_test.rb +15 -6
- data/test/integration/discovered_hosts_test.rb +6 -11
- data/test/test_helper_discovery.rb +12 -0
- data/test/unit/discovered_extensions_test.rb +54 -0
- data/test/unit/discovery_attribute_set_test.rb +13 -10
- data/test/unit/discovery_rule_test.rb +1 -0
- data/test/unit/host_discovered_test.rb +32 -29
- data/test/unit/managed_extensions_test.rb +2 -0
- metadata +39 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: accf12de8ae1253e5023ba98c65da7c3af14aa8da4691fe67dd7f18bc5717518
|
4
|
+
data.tar.gz: 0dd4c83a875917ccf3933679a31a747d8f559e5195415fab619cc0220bcd97c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8fd61670a325106898043ab9533f7512835394a6141139580436e9c8fdd0027ff0aee02c0a53f6d92b5b4535d5bcbcabfb1cd91ddc0fd85ce8a0a54d2cde27e
|
7
|
+
data.tar.gz: 90263e8535e3d338ee335a280ff89dafd188d7e92c8f7becb340bc6ede0884bbf4ee915ad158de546c84058240c7338d1d4a736f3124e8c6c57f935862073f83
|
@@ -55,7 +55,7 @@ module Api
|
|
55
55
|
param_group :discovery_rule, :as => :update
|
56
56
|
|
57
57
|
def update
|
58
|
-
process_response @discovery_rule.
|
58
|
+
process_response @discovery_rule.update(discovery_rule_params)
|
59
59
|
end
|
60
60
|
|
61
61
|
api :DELETE, "/discovery_rules/:id/", N_("Delete a rule")
|
@@ -41,6 +41,8 @@ module Foreman::Controller::DiscoveredExtensions
|
|
41
41
|
# trigger the provisioning
|
42
42
|
def perform_auto_provision original_host, rule
|
43
43
|
raise(::Foreman::Exception.new(N_("No hostgroup associated with rule '%s'"), rule)) if rule.hostgroup.nil?
|
44
|
+
|
45
|
+
logger.debug "Auto-provisioning via rule #{rule} hostgroup #{rule.hostgroup} subnet #{rule.hostgroup.subnet}"
|
44
46
|
host = ::ForemanDiscovery::HostConverter.to_managed(original_host)
|
45
47
|
host.hostgroup_id = rule.hostgroup_id
|
46
48
|
host.comment = "Auto-discovered and provisioned via rule '#{rule.name}'"
|
@@ -55,6 +57,8 @@ module Foreman::Controller::DiscoveredExtensions
|
|
55
57
|
# explicitly set all inheritable attributes from hostgroup
|
56
58
|
host.attributes = host.apply_inherited_attributes(hostgroup_id: rule.hostgroup_id)
|
57
59
|
host.set_hostgroup_defaults
|
60
|
+
# change subnet and fetch unused IPs
|
61
|
+
::ForemanDiscovery::HostConverter.unused_ip_for_host(host, rule.hostgroup.subnet, rule.hostgroup.subnet6)
|
58
62
|
# save! does not work here
|
59
63
|
if host.save
|
60
64
|
host
|
@@ -78,6 +78,7 @@ class DiscoveredHostsController < ::ApplicationController
|
|
78
78
|
def perform_update(host, success_message = nil)
|
79
79
|
Taxonomy.no_taxonomy_scope do
|
80
80
|
::ForemanDiscovery::HostConverter.set_build_clean_facts(host)
|
81
|
+
::ForemanDiscovery::HostConverter.unused_ip_for_host(host)
|
81
82
|
if host.save
|
82
83
|
success_options = { :success_redirect => host_path(host), :redirect_xhr => request.xhr? }
|
83
84
|
success_options[:success_msg] = success_message if success_message
|
@@ -198,15 +199,17 @@ class DiscoveredHostsController < ::ApplicationController
|
|
198
199
|
|
199
200
|
def setup_host_class_variables
|
200
201
|
if @host.hostgroup
|
202
|
+
subnet = @host.hostgroup.subnet || @host.subnet
|
203
|
+
subnet6 = @host.hostgroup.subnet6 || @host.subnet6
|
201
204
|
@architecture = @host.hostgroup.architecture
|
202
205
|
@operatingsystem = @host.hostgroup.operatingsystem
|
203
206
|
@environment = @host.hostgroup.environment
|
204
207
|
@domain = @host.hostgroup.domain
|
205
|
-
@subnet =
|
208
|
+
@subnet = subnet
|
209
|
+
@subnet6 = subnet6
|
206
210
|
@compute_profile = @host.hostgroup.compute_profile
|
207
211
|
@realm = @host.hostgroup.realm
|
208
|
-
@host.interfaces.first.assign_attributes(subnet:
|
209
|
-
domain: @domain)
|
212
|
+
@host.interfaces.first.assign_attributes(subnet: subnet, subnet6: subnet6, domain: @domain)
|
210
213
|
@host.environment = @environment
|
211
214
|
end
|
212
215
|
end
|
@@ -22,7 +22,7 @@ class DiscoveryRule < ApplicationRecord
|
|
22
22
|
before_validation :enforce_taxonomy
|
23
23
|
|
24
24
|
belongs_to :hostgroup
|
25
|
-
|
25
|
+
has_many_hosts :dependent => :nullify
|
26
26
|
|
27
27
|
scoped_search :on => :name, :complete_value => :true
|
28
28
|
scoped_search :on => :priority, :only_explicit => true
|
@@ -44,9 +44,13 @@ class Host::Discovered < ::Host::Base
|
|
44
44
|
|
45
45
|
# Discovery import workflow:
|
46
46
|
# discovered#import_host ->
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
47
|
+
# ForemanDiscovery::HostFactImporter#import_facts ->
|
48
|
+
# ::HostFactImporter#import_facts ->
|
49
|
+
# ::HostFactImporter#parse_facts ->
|
50
|
+
# discovered#populate_fields_from_facts ->
|
51
|
+
# base#populate_fields_from_facts ->
|
52
|
+
# base#set_interfaces ->
|
53
|
+
# discovered#populate_discovery_fields_from_facts
|
50
54
|
def self.import_host facts
|
51
55
|
raise(::Foreman::Exception.new(N_("Invalid facts, must be a Hash"))) unless facts.is_a?(Hash) || facts.is_a?(ActionController::Parameters)
|
52
56
|
|
@@ -92,19 +96,11 @@ class Host::Discovered < ::Host::Base
|
|
92
96
|
|
93
97
|
# and save (interfaces are created via puppet parser extension)
|
94
98
|
host.save(:validate => false) if host.new_record?
|
95
|
-
|
99
|
+
importer = ForemanDiscovery::HostFactImporter.new(host)
|
100
|
+
raise ::Foreman::Exception.new(N_("Facts could not be imported")) unless importer.import_facts(facts)
|
96
101
|
host
|
97
102
|
end
|
98
103
|
|
99
|
-
def import_facts(facts)
|
100
|
-
# Discovered Hosts won't report in via puppet, so we can use that field to
|
101
|
-
# record the last time it sent facts...
|
102
|
-
self.last_report = Time.now
|
103
|
-
# Set the correct facts type for new foreman facts importing code.
|
104
|
-
facts[:_type] = :foreman_discovery
|
105
|
-
super(facts)
|
106
|
-
end
|
107
|
-
|
108
104
|
def setup_clone
|
109
105
|
# Nic::Managed needs this method but Discovered hosts shouldn't
|
110
106
|
# be doing orchestration anyway...
|
@@ -137,33 +133,55 @@ class Host::Discovered < ::Host::Base
|
|
137
133
|
subnet.present? && subnet.discovery.present?
|
138
134
|
end
|
139
135
|
|
140
|
-
def proxy_url
|
141
|
-
proxied? ? subnet.discovery.url + "/discovery/#{
|
136
|
+
def proxy_url(node_ip)
|
137
|
+
proxied? ? subnet.discovery.url + "/discovery/#{node_ip}" : "https://#{node_ip}:8443"
|
142
138
|
end
|
143
139
|
|
144
140
|
def refresh_facts
|
145
|
-
facts = ::ForemanDiscovery::NodeAPI::Inventory.new(:url => proxy_url).facter
|
141
|
+
facts = ::ForemanDiscovery::NodeAPI::Inventory.new(:url => proxy_url(self.ip)).facter
|
146
142
|
self.class.import_host facts
|
147
|
-
import_facts facts
|
143
|
+
::ForemanDiscovery::HostFactImporter.new(self).import_facts facts
|
148
144
|
rescue => e
|
149
145
|
::Foreman::Logging.exception("Unable to get facts from proxy", e)
|
150
146
|
raise ::Foreman::WrappedException.new(e, N_("Could not get facts from proxy %{url}: %{error}"), :url => proxy_url, :error => e)
|
151
147
|
end
|
152
148
|
|
153
|
-
def reboot
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
149
|
+
def reboot(old_ip = nil, new_ip = nil)
|
150
|
+
# perform the action against the original lease as well as the new reservation
|
151
|
+
ips = [old_ip, new_ip, self.ip].compact.uniq
|
152
|
+
logger.debug "Performing reboot calls against #{ips.to_sentence}, facts left #{facts.count}"
|
153
|
+
ips.each do |next_ip|
|
154
|
+
begin
|
155
|
+
node_url = proxy_url(next_ip)
|
156
|
+
logger.debug "Performing reboot call against #{node_url}"
|
157
|
+
resource = ::ForemanDiscovery::NodeAPI::Power.service(:url => node_url)
|
158
|
+
return true if resource.reboot
|
159
|
+
rescue => e
|
160
|
+
msg = N_("Unable to perform reboot on %{name} (%{url}): %{msg}")
|
161
|
+
::Foreman::Logging.exception(msg % { :name => name, :url => node_url, :msg => e.to_s }, e)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
msg = N_("Unable to perform %{action} on %{ips}")
|
165
|
+
raise ::Foreman::Exception.new(msg, action: "reboot", ips: ips.to_sentence)
|
166
|
+
end
|
167
|
+
|
168
|
+
def kexec(json, old_ip = nil, new_ip = nil)
|
169
|
+
# perform the action against the original lease as well as the new reservation
|
170
|
+
ips = [old_ip, new_ip, self.ip].compact.uniq
|
171
|
+
logger.debug "Performing kexec calls against #{ips.to_sentence}, #{facts.count} facts left"
|
172
|
+
ips.each do |next_ip|
|
173
|
+
begin
|
174
|
+
node_url = proxy_url(next_ip)
|
175
|
+
logger.debug "Performing kexec call against #{node_url}"
|
176
|
+
resource = ::ForemanDiscovery::NodeAPI::Power.service(:url => node_url)
|
177
|
+
return true if resource.kexec(json)
|
178
|
+
rescue => e
|
179
|
+
msg = N_("Unable to perform kexec on %{name} (%{url}): %{msg}")
|
180
|
+
::Foreman::Logging.exception(msg % { :name => name, :url => node_url, :msg => e.to_s }, e)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
msg = N_("Unable to perform %{action} on %{ips}")
|
184
|
+
raise ::Foreman::Exception.new(msg, action: "kexec", ips: ips.to_sentence)
|
167
185
|
end
|
168
186
|
|
169
187
|
def self.model_name
|
@@ -27,7 +27,7 @@ module Host::ManagedExtensions
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def setReboot
|
30
|
-
old.becomes(Host::Discovered).reboot
|
30
|
+
old.becomes(Host::Discovered).reboot(old.ip, ip)
|
31
31
|
# It is too late to report error in the post_queue, we catch them and
|
32
32
|
# continue. If flash is implemented for new hosts (http://projects.theforeman.org/issues/10559)
|
33
33
|
# we can report the error to the user perhaps.
|
@@ -55,7 +55,7 @@ module Host::ManagedExtensions
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def setKexec
|
58
|
-
old.becomes(Host::Discovered).kexec(render_kexec_template.to_json)
|
58
|
+
old.becomes(Host::Discovered).kexec(render_kexec_template.to_json, old.ip, ip)
|
59
59
|
true
|
60
60
|
rescue ::Foreman::Exception => e
|
61
61
|
Foreman::Logging.exception("Unable to kexec", e)
|
@@ -8,41 +8,36 @@ class Setting::Discovered < ::Setting
|
|
8
8
|
BLANK_ATTRS << 'discovery_facts_hardware'
|
9
9
|
BLANK_ATTRS << 'discovery_facts_network'
|
10
10
|
BLANK_ATTRS << 'discovery_facts_ipmi'
|
11
|
-
BLANK_ATTRS << 'discovery_prefix'
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
return unless super
|
12
|
+
STRING_PRESENCE_ATTRS = ['discovery_hostname', 'discovery_prefix']
|
13
|
+
validates :value, :presence => true, :if => proc { |s| STRING_PRESENCE_ATTRS.include?(s.name) }
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
true
|
15
|
+
def self.default_settings
|
16
|
+
[
|
17
|
+
self.set('discovery_location', N_("The default location to place discovered hosts in"), "", N_("Discovery location"), nil, { :collection => Proc.new {Hash[Location.all.map{|loc| [loc[:title], loc[:title]]}]} }),
|
18
|
+
self.set('discovery_organization', N_("The default organization to place discovered hosts in"), "", N_("Discovery organization"), nil, { :collection => Proc.new {Hash[Organization.all.map{|org| [org[:title], org[:title]]}]} }),
|
19
|
+
self.set('discovery_fact', N_("Fact name to use for primary interface detection"), "discovery_bootif", N_("Interface fact")),
|
20
|
+
self.set('discovery_auto_bond', N_("Automatic bond interface (if another interface is detected on the same VLAN via LLDP)"), false, N_("Create bond interfaces")),
|
21
|
+
self.set('discovery_clean_facts', N_("Clean all reported facts during provisioning (except discovery facts)"), false, N_("Clean all facts")),
|
22
|
+
self.set('discovery_hostname', N_("List of facts to use for the hostname (separated by comma, first wins)"), "discovery_bootif", N_("Hostname facts")),
|
23
|
+
self.set('discovery_auto', N_("Automatically provision newly discovered hosts, according to the provisioning rules"), false, N_("Auto provisioning")),
|
24
|
+
self.set('discovery_reboot', N_("Automatically reboot or kexec discovered host during provisioning"), true, N_("Reboot")),
|
25
|
+
self.set('discovery_prefix', N_("The default prefix to use for the host name, must start with a letter"), "mac", N_("Hostname prefix")),
|
26
|
+
self.set('discovery_fact_column', N_("Extra facter columns to show in host lists (separate by comma)"), "", N_("Fact columns")),
|
27
|
+
self.set('discovery_facts_highlights', N_("Regex to organize facts for highlights section - e.g. ^(abc|cde)$"), "", N_("Highlighted facts")),
|
28
|
+
self.set('discovery_facts_storage', N_("Regex to organize facts for storage section"), "", N_("Storage facts")),
|
29
|
+
self.set('discovery_facts_software', N_("Regex to organize facts for software section"), "", N_("Software facts")),
|
30
|
+
self.set('discovery_facts_hardware', N_("Regex to organize facts for hardware section"), "", N_("Hardware facts")),
|
31
|
+
self.set('discovery_facts_network', N_("Regex to organize facts for network section"), "", N_("Network facts")),
|
32
|
+
self.set('discovery_facts_ipmi', N_("Regex to organize facts for ipmi section"), "", N_("IPMI facts")),
|
33
|
+
self.set('discovery_lock', N_("Automatically generate PXE configuration to pin a newly discovered host to discovery"), false, N_("Lock PXE")),
|
34
|
+
self.set('discovery_pxelinux_lock_template', N_("PXELinux template to be used when pinning a host to discovery"), 'pxelinux_discovery', N_("Locked PXELinux template name"), nil, { :collection => Proc.new {Hash[ProvisioningTemplate.where(:template_kind => TemplateKind.find_by_name(:snippet)).map{|template| [template[:name], template[:name]]}]} }),
|
35
|
+
self.set('discovery_pxegrub_lock_template', N_("PXEGrub template to be used when pinning a host to discovery"), 'pxegrub_discovery', N_("Locked PXEGrub template name"), nil, { :collection => Proc.new {Hash[ProvisioningTemplate.where(:template_kind => TemplateKind.find_by_name(:snippet)).map{|template| [template[:name], template[:name]]}]} }),
|
36
|
+
self.set('discovery_pxegrub2_lock_template', N_("PXEGrub2 template to be used when pinning a host to discovery"), 'pxegrub2_discovery', N_("Locked PXEGrub2 template name"), nil, { :collection => Proc.new {Hash[ProvisioningTemplate.where(:template_kind => TemplateKind.find_by_name(:snippet)).map{|template| [template[:name], template[:name]]}]} }),
|
37
|
+
self.set('discovery_always_rebuild_dns', N_("Force DNS entries creation when provisioning discovered host"), true, N_("Force DNS")),
|
38
|
+
self.set('discovery_error_on_existing', N_("Do not allow to discover existing managed host matching MAC of a provisioning NIC (errors out early)"), false, N_("Error on existing NIC")),
|
39
|
+
self.set('discovery_naming', N_("Discovery hostname naming pattern"), 'Fact', N_("Type of name generator"), nil, {:collection => Proc.new {::Host::Discovered::NAMING_PATTERNS} }),
|
40
|
+
]
|
46
41
|
end
|
47
42
|
|
48
43
|
def self.discovery_fact_column_array
|
@@ -6,7 +6,7 @@ module ForemanDiscovery
|
|
6
6
|
raise(::Foreman::Exception.new(N_("Discovered host '%{host}' has all NICs filtered out, filter: %{filter}") %
|
7
7
|
{:host => host, :filter => Setting[:ignored_interface_identifiers]})) if interfaces.size == 0
|
8
8
|
bootif_mac = FacterUtils::bootif_mac(facts).try(:downcase)
|
9
|
-
detected = interfaces.detect { |_, values| values[:macaddress].try(:downcase) == bootif_mac && values[:ipaddress].present? }
|
9
|
+
detected = interfaces.detect { |_, values| values[:macaddress].try(:downcase) == bootif_mac && (values[:ipaddress].present? || values[:ipaddress6].present?) }
|
10
10
|
Rails.logger.debug "Discovery fact parser detected primary interface: #{detected}"
|
11
11
|
# return the detected interface as array [name, facts]
|
12
12
|
detected || raise(::Foreman::Exception.new(N_("Unable to find primary NIC with %{mac} specified via '%{fact}', NIC filter: %{filter}") %
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class ForemanDiscovery::HostConverter
|
2
|
-
|
3
2
|
# Converts discovered host to managed host without uptading the database.
|
4
|
-
# Record must be saved explicitly (using save! or
|
3
|
+
# Record must be saved explicitly (using save! or update! or similar).
|
5
4
|
# Creates shallow copy.
|
6
5
|
def self.to_managed(original_host, set_managed = true, set_build = true, added_attributes = {})
|
7
6
|
host = original_host.becomes(::Host::Managed)
|
@@ -35,4 +34,41 @@ class ForemanDiscovery::HostConverter
|
|
35
34
|
host.build = true
|
36
35
|
end
|
37
36
|
|
37
|
+
def self.unused_ip_for_subnet(subnet, mac, existing_ip)
|
38
|
+
# prefer existing reservation to prevent conflicts
|
39
|
+
existing_rec = subnet&.dhcp_proxy&.record(subnet.network, mac)
|
40
|
+
|
41
|
+
if existing_rec && existing_rec.type == "reservation"
|
42
|
+
# reuse the reservation
|
43
|
+
existing_rec.ip
|
44
|
+
else
|
45
|
+
# no reservation - find new unused IP
|
46
|
+
ipam = subnet.unused_ip(mac)
|
47
|
+
raise(::Foreman::Exception.new(N_("IPAM must be configured for subnet '%s'"), subnet)) unless ipam.present?
|
48
|
+
|
49
|
+
# None IPAM returns nil - in that case keep the current address
|
50
|
+
suggested_ip = ipam.suggest_ip
|
51
|
+
suggested_ip.nil? ? existing_ip : suggested_ip
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.unused_ip_for_host(host, new_subnet = nil, new_subnet6 = nil)
|
56
|
+
host.interfaces.each do |interface|
|
57
|
+
next unless interface.managed?
|
58
|
+
|
59
|
+
interface.subnet = new_subnet if new_subnet
|
60
|
+
interface.subnet6 = new_subnet6 if new_subnet6
|
61
|
+
interface.ip = unused_ip_for_subnet(interface.subnet, interface.mac, interface.ip) if interface.subnet
|
62
|
+
interface.ip6 = unused_ip_for_subnet(interface.subnet6, interface.mac, interface.ip6) if interface.subnet6
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.change_subnet_and_unused_ip(host, hostgroup)
|
67
|
+
if host.subnet != hostgroup.subnet || host.subnet6 != hostgroup.subnet6
|
68
|
+
Rails.logger.debug "Discovered host subnets #{[host.subnet, host.subnet6]} do not match hostgroup subnets #{[hostgroup.subnet, hostgroup.subnet6]}"
|
69
|
+
unused_ip_for_host(host, host.hostgroup.subnet, host.hostgroup.subnet6)
|
70
|
+
else
|
71
|
+
Rails.logger.debug "Discovered host subnets #{[host.subnet, host.subnet6]} match hostgroup subnets"
|
72
|
+
end
|
73
|
+
end
|
38
74
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ForemanDiscovery::HostFactImporter < ::HostFactImporter
|
2
|
+
def import_facts(facts)
|
3
|
+
# Discovered Hosts won't report in via puppet, so we can use that field to
|
4
|
+
# record the last time it sent facts...
|
5
|
+
host.last_report = Time.now
|
6
|
+
# Set the correct facts type for new foreman facts importing code.
|
7
|
+
facts[:_type] = :foreman_discovery
|
8
|
+
super(facts)
|
9
|
+
end
|
10
|
+
end
|
@@ -4,14 +4,15 @@ module ForemanDiscovery
|
|
4
4
|
class SubnetAndTaxonomy < ImportHook
|
5
5
|
def after_populate
|
6
6
|
primary_ip = host.primary_interface.ip
|
7
|
+
primary_ip6 = host.primary_interface.ip6
|
7
8
|
|
8
|
-
unless primary_ip
|
9
|
+
unless primary_ip || primary_ip6
|
9
10
|
logger.warn "Unable to assign subnet - reboot trigger may not be possible, primary interface is missing IP address"
|
10
11
|
return
|
11
12
|
end
|
12
13
|
|
13
14
|
# set subnet
|
14
|
-
|
15
|
+
set_subnets(primary_ip, primary_ip6)
|
15
16
|
# set location and organization
|
16
17
|
set_location
|
17
18
|
set_organization
|
@@ -19,18 +20,9 @@ module ForemanDiscovery
|
|
19
20
|
|
20
21
|
private
|
21
22
|
|
22
|
-
def
|
23
|
-
host.primary_interface.subnet =
|
24
|
-
|
25
|
-
|
26
|
-
def suggested_subnet(ip)
|
27
|
-
subnet = Subnet.subnet_for(ip)
|
28
|
-
if subnet
|
29
|
-
logger.info "Detected subnet: #{subnet} with taxonomy #{subnet.organizations.collect(&:name)}/#{subnet.locations.collect(&:name)}"
|
30
|
-
else
|
31
|
-
logger.warn "Subnet could not be detected for #{ip}"
|
32
|
-
end
|
33
|
-
subnet
|
23
|
+
def set_subnets(ip, ip6)
|
24
|
+
host.primary_interface.subnet = ForemanDiscovery::SubnetSuggestion.for(ip: ip, kind: 'IPv4') if ip
|
25
|
+
host.primary_interface.subnet6 = ForemanDiscovery::SubnetSuggestion.for(ip: ip6, kind: 'IPv6') if ip6
|
34
26
|
end
|
35
27
|
|
36
28
|
def set_location
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ForemanDiscovery
|
2
|
+
class SubnetSuggestion
|
3
|
+
attr_accessor :ip, :kind
|
4
|
+
|
5
|
+
def self.for(ip:, kind:)
|
6
|
+
new(ip: ip, kind: kind).()
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(ip:, kind:)
|
10
|
+
self.ip = ip
|
11
|
+
self.kind = kind
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
return unless ip
|
16
|
+
|
17
|
+
subnet = Subnet.unscoped.subnet_for(ip)
|
18
|
+
if subnet
|
19
|
+
Rails.logger.info "Detected #{kind} subnet: #{subnet} with taxonomy #{subnet.organizations.collect(&:name)}/#{subnet.locations.collect(&:name)}"
|
20
|
+
else
|
21
|
+
Rails.logger.info "#{kind} subnet could not be detected for #{ip}"
|
22
|
+
end
|
23
|
+
subnet
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -12,9 +12,10 @@ environments. The template must generate JSON format with the following items
|
|
12
12
|
"kernel", "initram", "append" and "extra". The kexec command is composed in
|
13
13
|
the following way:
|
14
14
|
|
15
|
-
kexec --force --
|
15
|
+
kexec --force --debug --append=$append --initrd=$initram $extra $kernel
|
16
16
|
|
17
17
|
Please read kexec(8) man page for more information about semantics.
|
18
|
+
Extra options like --reset-vga can be set via "extra" array.
|
18
19
|
-%>
|
19
20
|
<%
|
20
21
|
mac = @host.facts['discovery_bootif']
|
@@ -28,7 +29,7 @@ Please read kexec(8) man page for more information about semantics.
|
|
28
29
|
options << @host.facts['append']
|
29
30
|
options << "domain=#{@host.domain}"
|
30
31
|
options << 'console-setup/ask_detect=false console-setup/layout=USA console-setup/variant=USA keyboard-configuration/layoutcode=us localechooser/translation/warn-light=true localechooser/translation/warn-severe=true'
|
31
|
-
options << "locale=#{
|
32
|
+
options << "locale=#{host_param('lang') || 'en_US'}"
|
32
33
|
options << "inst.stage2=#{@host.operatingsystem.medium_uri(@host)}" if @host.operatingsystem.name.match(/Atomic/i)
|
33
34
|
-%>
|
34
35
|
{
|