This repository has been archived by the owner on Nov 9, 2022. It is now read-only.
/
discover-host.rb.in
executable file
·221 lines (194 loc) · 5.98 KB
/
discover-host.rb.in
1
2
3
4
5
6
7
8
9
10
11
12
13
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/usr/bin/env ruby
#
# vim: ts=2:sw=2:et
#
# Copyright (C) 2012-2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA. A copy of the GNU General Public License is
# also available at http://www.gnu.org/copyleft/gpl.html.
PACKAGE_NAME = '@PACKAGE_NAME@'
PACKAGE_VERSION = '@PACKAGE_VERSION@'
ENGINE_NAME = '@ENGINENAME@'
DEBUG = ('@PLUGIN_DEBUG@'.to_i == 1) rescue false
PROXY_CACHE = '/tmp/proxy_cache'
require 'fileutils'
require 'net/http'
require 'net/https'
require 'uri'
require 'socket'
require 'resolv'
# For comparison
require 'rubygems'
require 'facter'
require 'yaml'
require 'json'
BANNER = <<'EOS'
_____
| ___|__ _ __ ___ _ __ ___ __ _ _ __
| |_ / _ \| '__/ _ \ '_ ` _ \ / _` | '_ \
| _| (_) | | | __/ | | | | | (_| | | | |
|_|__\___/|_| \___|_| |_| |_|\__,_|_| |_|
| _ \(_)___ ___ _____ _____ _ __ _ _
| | | | / __|/ __/ _ \ \ / / _ \ '__| | | |
| |_| | \__ \ (_| (_) \ V / __/ | | |_| |
|____/|_|___/\___\___/ \_/ \___|_| \__, |
|___/
EOS
$start_time = Time.now
def time_prefix
Time.at(Time.now - $start_time).strftime("[%_4s]")
rescue
"[ ? ]"
end
def println msg
puts "#{time_prefix} #{msg}\n"
end
def debug msg
if DEBUG
println msg
end
end
def error msg
$stderr.puts "#{time_prefix} #{msg}"
end
def cmdline option=nil, default=nil
line = File.open("/proc/cmdline", 'r') { |f| f.read }
if option
result = line.split.map { |x| $1 if x.match(/^#{option}=(.*)/)}.compact
result.size == 1 ? result.first : default
else
line
end
end
def discover_server
debug "Parsing kernel line: #{cmdline}"
discover_by_url or discover_by_ip or
discover_by_server or discover_by_dns_srv
end
# kept for backward compatibility
def discover_by_ip
ip = cmdline 'foreman.ip'
println "Discovered by PXE: #{ip}" if ip
URI.parse("http://#{ip}")
rescue
return nil
end
# kept for backward compatibility
def discover_by_server
server = cmdline 'foreman.server'
println "Discovered by SERVER: #{server}" if server
URI.parse("http://#{server}")
rescue
return nil
end
def discover_by_url
url = cmdline 'foreman.url'
println "Discovered by URL: #{url}" if url
URI.parse(url)
rescue
return nil
end
# SRV discovery will work only if DHCP returns valid search domain
def discover_by_dns_srv
resolver = Resolv::DNS.new
type = Resolv::DNS::Resource::IN::SRV
result = resolver.getresources("_x-foreman._tcp", type).first
hostname = result.target.to_s
if result.port == 443
scheme = 'https'
else
scheme = 'http'
end
uri = "#{scheme}://#{hostname}:#{result.port}"
println "Discovered by SRV: #{uri}"
URI.parse(uri)
rescue
return nil
end
def upload
uri = discover_server
error "Could not determine Foreman instance, add kernel command option" unless uri
println "Registering host with Foreman (#{uri})"
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https' then
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
req = Net::HTTP::Post.new("#{uri.path}/api/v2/discovered_hosts/facts", initheader = {'Content-Type' =>'application/json'})
req.body = {'facts' => Facter.to_hash }.to_json
response = http.request(req)
if ['200','201'].include? response.code
debug "Response from Foreman #{response.code}: #{response.body}"
return true
else
error "Response from Foreman #{response.code}: #{response.body}"
# <FIXME> - remove for Foreman 1.6
# For backward compatibility reasons try to upload facts with the old API on /discovers
ip = Facter.value('ipaddress')
debug "Triggering import of facts from Foreman using old API (#{uri}, ip=#{ip})"
req = Net::HTTP::Post.new("#{uri.path}/discovers")
data = ip.nil? ? {} : {'ip' => ip}
req.set_form_data(data)
response = http.request(req)
debug "Response from Foreman #{response.code}: #{response.body}"
if response.code == "200"
return true
else
return false
end
# </FIXME>
return false
end
rescue => e
error "Could not send facts to Foreman: #{e}"
return false
end
def write_cache(data)
File.open(PROXY_CACHE, 'w') {|f| f.write(data) }
end
def read_cache
File.read(PROXY_CACHE)
rescue => e
"empty cache"
end
# Main
$stdout.reopen("/dev/tty1", "w")
$stderr.reopen("/dev/tty1", "w")
# Script was (re)started - delete old data
File.unlink(PROXY_CACHE) if File.exists?(PROXY_CACHE)
puts "\e[H\e[2J"
println BANNER
TAG = DEBUG ? 'D' : 'P'
println "This is Foreman Discovery #{PACKAGE_VERSION}-#{TAG}, tty1 is reserved for logs."
println "Hold on until all network interfaces are configured."
if DEBUG
println "The image was build with debug support, you can switch over to tty2+ "
println "and login as root/redhat or use ssh (password auth enabled)."
end
sleep DEBUG ? 10 : 30
println "Some interesting facts about this system:"
facts = Hash[Facter.to_hash.select {|k,v| k =~ /address|hardware|manufacturer|productname|memorytotal/}]
facts.keys.sort.each {|k| println " #{k}: #{facts[k]}"}
println "Logs from discovery services now follows:"
# loop, but only upload on changes
while true do
uninteresting_facts=/kernel|operatingsystem|osfamily|ruby|path|time|swap|free|filesystem|version|selinux/i
facts = Facter.to_hash.reject! {|k,v| k =~ uninteresting_facts }
unless YAML.load(read_cache) == facts
debug "Fact cache invalid, reloading to foreman"
write_cache(YAML.dump(facts)) if upload
end
sleep DEBUG ? 30 : 120
end