foreman_discovery 15.0.2 → 16.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 +1 -0
- data/app/controllers/discovery_rules_controller.rb +1 -1
- data/app/models/discovery_rule.rb +1 -1
- data/app/models/host/discovered.rb +39 -17
- data/app/models/host/managed_extensions.rb +2 -2
- data/app/models/setting/discovered.rb +26 -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/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/discovered_hosts/_discovered_host_modal.html.erb +2 -0
- data/app/views/foreman_discovery/debian_kexec.erb +1 -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 +21 -7
- 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 +28 -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 +31 -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 +24 -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 +31 -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 +30 -10
- data/locale/foreman_discovery.pot +110 -84
- 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 +28 -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 +26 -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 +26 -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 +29 -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 +28 -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 +29 -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 +29 -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 +27 -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 +28 -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 +26 -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/functional/api/v2/discovered_hosts_controller_test.rb +1 -0
- 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 -13
- data/test/unit/managed_extensions_test.rb +2 -0
- metadata +34 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef6a4731f46b5f34f372a87f8da770e0510504664852ef61253677bb587c8842
|
4
|
+
data.tar.gz: 75715ed1dae928289c3189443f8f290c6fa95a681678610c0aca980b18825aa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5882e04be01b4d3f213acf4b751a0a4784436cd97558ab1e9448f8976e89f86db047c986923da5d62f72757c86430790590c942f0579ba62224f7ce458ef9c9d
|
7
|
+
data.tar.gz: 154d39a5d013b431ce6367d5a0f87e06521df092c36a4d95da0114062f4aef569ddd80600ac077db7639b9628739056e66d619de7604e026e45f57406a069c3c
|
@@ -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
|
@@ -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
|
@@ -137,12 +137,12 @@ class Host::Discovered < ::Host::Base
|
|
137
137
|
subnet.present? && subnet.discovery.present?
|
138
138
|
end
|
139
139
|
|
140
|
-
def proxy_url
|
141
|
-
proxied? ? subnet.discovery.url + "/discovery/#{
|
140
|
+
def proxy_url(node_ip)
|
141
|
+
proxied? ? subnet.discovery.url + "/discovery/#{node_ip}" : "https://#{node_ip}:8443"
|
142
142
|
end
|
143
143
|
|
144
144
|
def refresh_facts
|
145
|
-
facts = ::ForemanDiscovery::NodeAPI::Inventory.new(:url => proxy_url).facter
|
145
|
+
facts = ::ForemanDiscovery::NodeAPI::Inventory.new(:url => proxy_url(self.ip)).facter
|
146
146
|
self.class.import_host facts
|
147
147
|
import_facts facts
|
148
148
|
rescue => e
|
@@ -150,20 +150,42 @@ class Host::Discovered < ::Host::Base
|
|
150
150
|
raise ::Foreman::WrappedException.new(e, N_("Could not get facts from proxy %{url}: %{error}"), :url => proxy_url, :error => e)
|
151
151
|
end
|
152
152
|
|
153
|
-
def reboot
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
153
|
+
def reboot(old_ip = nil, new_ip = nil)
|
154
|
+
# perform the action against the original lease as well as the new reservation
|
155
|
+
ips = [old_ip, new_ip, self.ip].compact.uniq
|
156
|
+
logger.debug "Performing reboot calls against #{ips.to_sentence}, facts left #{facts.count}"
|
157
|
+
ips.each do |next_ip|
|
158
|
+
begin
|
159
|
+
node_url = proxy_url(next_ip)
|
160
|
+
logger.debug "Performing reboot call against #{node_url}"
|
161
|
+
resource = ::ForemanDiscovery::NodeAPI::Power.service(:url => node_url)
|
162
|
+
return true if resource.reboot
|
163
|
+
rescue => e
|
164
|
+
msg = N_("Unable to perform reboot on %{name} (%{url}): %{msg}")
|
165
|
+
::Foreman::Logging.exception(msg % { :name => name, :url => node_url, :msg => e.to_s }, e)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
msg = N_("Unable to perform %{action} on %{ips}")
|
169
|
+
raise ::Foreman::Exception.new(msg, action: "reboot", ips: ips.to_sentence)
|
170
|
+
end
|
171
|
+
|
172
|
+
def kexec(json, old_ip = nil, new_ip = nil)
|
173
|
+
# perform the action against the original lease as well as the new reservation
|
174
|
+
ips = [old_ip, new_ip, self.ip].compact.uniq
|
175
|
+
logger.debug "Performing kexec calls against #{ips.to_sentence}, #{facts.count} facts left"
|
176
|
+
ips.each do |next_ip|
|
177
|
+
begin
|
178
|
+
node_url = proxy_url(next_ip)
|
179
|
+
logger.debug "Performing kexec call against #{node_url}"
|
180
|
+
resource = ::ForemanDiscovery::NodeAPI::Power.service(:url => node_url)
|
181
|
+
return true if resource.kexec(json)
|
182
|
+
rescue => e
|
183
|
+
msg = N_("Unable to perform kexec on %{name} (%{url}): %{msg}")
|
184
|
+
::Foreman::Logging.exception(msg % { :name => name, :url => node_url, :msg => e.to_s }, e)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
msg = N_("Unable to perform %{action} on %{ips}")
|
188
|
+
raise ::Foreman::Exception.new(msg, action: "kexec", ips: ips.to_sentence)
|
167
189
|
end
|
168
190
|
|
169
191
|
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)
|
@@ -10,39 +10,32 @@ class Setting::Discovered < ::Setting
|
|
10
10
|
BLANK_ATTRS << 'discovery_facts_ipmi'
|
11
11
|
BLANK_ATTRS << 'discovery_prefix'
|
12
12
|
|
13
|
-
def self.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
self.set('discovery_always_rebuild_dns', N_("Force DNS entries creation when provisioning discovered host"), true, N_("Force DNS")),
|
40
|
-
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")),
|
41
|
-
self.set('discovery_naming', N_("Discovery hostname naming pattern"), 'Fact', N_("Type of name generator"), nil, {:collection => Proc.new {::Host::Discovered::NAMING_PATTERNS} }),
|
42
|
-
].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
|
43
|
-
end
|
44
|
-
|
45
|
-
true
|
13
|
+
def self.default_settings
|
14
|
+
[
|
15
|
+
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]]}]} }),
|
16
|
+
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]]}]} }),
|
17
|
+
self.set('discovery_fact', N_("Fact name to use for primary interface detection"), "discovery_bootif", N_("Interface fact")),
|
18
|
+
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")),
|
19
|
+
self.set('discovery_clean_facts', N_("Clean all reported facts during provisioning (except discovery facts)"), false, N_("Clean all facts")),
|
20
|
+
self.set('discovery_hostname', N_("List of facts to use for the hostname (separated by comma, first wins)"), "discovery_bootif", N_("Hostname facts")),
|
21
|
+
self.set('discovery_auto', N_("Automatically provision newly discovered hosts, according to the provisioning rules"), false, N_("Auto provisioning")),
|
22
|
+
self.set('discovery_reboot', N_("Automatically reboot or kexec discovered host during provisioning"), true, N_("Reboot")),
|
23
|
+
self.set('discovery_prefix', N_("The default prefix to use for the host name, must start with a letter"), "mac", N_("Hostname prefix")),
|
24
|
+
self.set('discovery_fact_column', N_("Extra facter columns to show in host lists (separate by comma)"), "", N_("Fact columns")),
|
25
|
+
self.set('discovery_facts_highlights', N_("Regex to organize facts for highlights section - e.g. ^(abc|cde)$"), "", N_("Highlighted facts")),
|
26
|
+
self.set('discovery_facts_storage', N_("Regex to organize facts for storage section"), "", N_("Storage facts")),
|
27
|
+
self.set('discovery_facts_software', N_("Regex to organize facts for software section"), "", N_("Software facts")),
|
28
|
+
self.set('discovery_facts_hardware', N_("Regex to organize facts for hardware section"), "", N_("Hardware facts")),
|
29
|
+
self.set('discovery_facts_network', N_("Regex to organize facts for network section"), "", N_("Network facts")),
|
30
|
+
self.set('discovery_facts_ipmi', N_("Regex to organize facts for ipmi section"), "", N_("IPMI facts")),
|
31
|
+
self.set('discovery_lock', N_("Automatically generate PXE configuration to pin a newly discovered host to discovery"), false, N_("Lock PXE")),
|
32
|
+
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]]}]} }),
|
33
|
+
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]]}]} }),
|
34
|
+
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]]}]} }),
|
35
|
+
self.set('discovery_always_rebuild_dns', N_("Force DNS entries creation when provisioning discovered host"), true, N_("Force DNS")),
|
36
|
+
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")),
|
37
|
+
self.set('discovery_naming', N_("Discovery hostname naming pattern"), 'Fact', N_("Type of name generator"), nil, {:collection => Proc.new {::Host::Discovered::NAMING_PATTERNS} }),
|
38
|
+
]
|
46
39
|
end
|
47
40
|
|
48
41
|
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
|
@@ -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
|
@@ -17,6 +17,8 @@
|
|
17
17
|
<% if show_location_tab? %>
|
18
18
|
<%= select_f f, :location_id, Location.my_locations, :id, :to_label, {}, {:size => 'col-md-10'} %>
|
19
19
|
<% end %>
|
20
|
+
|
21
|
+
<div>Changing the Host's Subnet is not possible via Customize Host form, use Create Host or Auto provisioning and set the desired Subnet in the Hostgroup.</div>
|
20
22
|
</div>
|
21
23
|
<div class="modal-footer">
|
22
24
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
@@ -28,7 +28,7 @@ Please read kexec(8) man page for more information about semantics.
|
|
28
28
|
options << @host.facts['append']
|
29
29
|
options << "domain=#{@host.domain}"
|
30
30
|
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=#{
|
31
|
+
options << "locale=#{host_param('lang') || 'en_US'}"
|
32
32
|
options << "inst.stage2=#{@host.operatingsystem.medium_uri(@host)}" if @host.operatingsystem.name.match(/Atomic/i)
|
33
33
|
-%>
|
34
34
|
{
|
data/config/routes.rb
CHANGED
@@ -6,6 +6,8 @@ Rails.application.routes.draw do
|
|
6
6
|
post 'os_selected_discovered_hosts' => 'hosts#os_selected'
|
7
7
|
post 'medium_selected_discovered_hosts' => 'hosts#medium_selected'
|
8
8
|
|
9
|
+
get 'discovered_hosts/help', :action => :welcome, :controller => 'discovered_hosts'
|
10
|
+
|
9
11
|
constraints(:id => /[^\/]+/) do
|
10
12
|
resources :discovered_hosts, :except => [:new, :create] do
|
11
13
|
member do
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class RemoveOldDiscoveryReaderPermissions < ActiveRecord::Migration[4.2]
|
2
2
|
def up
|
3
3
|
Permission.where("name like '%_discovery_rules' and resource_type is null").each do |permission|
|
4
|
-
permission.
|
4
|
+
permission.update(:resource_type => 'DiscoveryRule')
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class RegenerateRedHatKexec < ActiveRecord::Migration[4.2]
|
2
2
|
def up
|
3
3
|
t = ProvisioningTemplate.find_by_name("Discovery Red Hat kexec")
|
4
|
-
t.
|
4
|
+
t.update(:template => t.template.sub(/rescue ''$/, 'if mac')) if t
|
5
5
|
end
|
6
6
|
|
7
7
|
def down
|
@@ -9,7 +9,7 @@
|
|
9
9
|
# and makes sure there are no two entities with the same priority.
|
10
10
|
DiscoveryRules.reset_column_information
|
11
11
|
DiscoveryRules.unscoped.reorder(:priority, :created_at).find_each do |rule|
|
12
|
-
rule.
|
12
|
+
rule.update!(:priority => score)
|
13
13
|
score += delta
|
14
14
|
end
|
15
15
|
change_column :discovery_rules, :priority, :integer, null: false
|
data/extra/discover-host
CHANGED
@@ -3,10 +3,12 @@ require 'optparse'
|
|
3
3
|
require 'json'
|
4
4
|
require 'rest-client'
|
5
5
|
|
6
|
-
def find_base name="default"
|
7
|
-
return name if File.
|
6
|
+
def find_base name = "default"
|
7
|
+
return name if File.exist?(name)
|
8
|
+
|
8
9
|
file = File.absolute_path(File.dirname(__FILE__) + "../../test/facts/#{name}.json")
|
9
|
-
raise "Unable to find file #{file}" unless File.
|
10
|
+
raise "Unable to find file #{file}" unless File.exist?(file)
|
11
|
+
|
10
12
|
file
|
11
13
|
end
|
12
14
|
|
@@ -14,6 +16,7 @@ base = find_base
|
|
14
16
|
version = "3.4.0"
|
15
17
|
interfaces = []
|
16
18
|
preserve_interfaces = false
|
19
|
+
use_facts_endpoint = false
|
17
20
|
primary = nil
|
18
21
|
bootif = nil
|
19
22
|
url = "http://admin:changeme@localhost:3000"
|
@@ -38,6 +41,10 @@ OptionParser.new do |opts|
|
|
38
41
|
preserve_interfaces = true
|
39
42
|
end
|
40
43
|
|
44
|
+
opts.on("-a", "--facts", "Use host facts endpoint") do |v|
|
45
|
+
use_facts_endpoint = true
|
46
|
+
end
|
47
|
+
|
41
48
|
opts.on("-pNAME", "--primary=NAME", "Interface to use as primary (defaults to the first one)") do |v|
|
42
49
|
primary = v
|
43
50
|
end
|
@@ -70,8 +77,8 @@ unless preserve_interfaces
|
|
70
77
|
json["interfaces"] = interfaces.map{|i| i.first}.join(',')
|
71
78
|
interfaces.each do |iface|
|
72
79
|
name, subnet, ipo, mac = iface
|
73
|
-
mac
|
74
|
-
ipo
|
80
|
+
mac ||= (["52"] + 5.times.map { '%02x' % rand(0..255) }).join(':')
|
81
|
+
ipo ||= rand(1..253)
|
75
82
|
ip = "192.168.#{subnet}.#{ipo}"
|
76
83
|
json["macaddress_#{name}"] = mac
|
77
84
|
json["ipaddress_#{name}"] = ip
|
@@ -83,7 +90,14 @@ unless preserve_interfaces
|
|
83
90
|
end
|
84
91
|
end
|
85
92
|
puts JSON.pretty_generate(json)
|
86
|
-
|
87
|
-
|
93
|
+
if use_facts_endpoint
|
94
|
+
endpoint = url + "/api/v2/hosts/facts"
|
95
|
+
payload = {"facts" => json, "name" => json["hostname"] || json["networking"]["fqdn"]}
|
96
|
+
else
|
97
|
+
endpoint = url + "/api/v2/discovered_hosts/facts"
|
98
|
+
payload = {"facts" => json}
|
99
|
+
end
|
100
|
+
resource = RestClient::Resource.new(endpoint, verify_ssl: OpenSSL::SSL::VERIFY_NONE)
|
101
|
+
response = resource.post(payload.to_json, {content_type: :json, accept: :json})
|
88
102
|
puts response.code
|
89
103
|
puts response.body
|