Revision ee647b4c
Added by Eric Helms about 10 years ago
Puppetfile.lock | ||
---|---|---|
GIT
|
||
remote: https://github.com/Katello/puppet-katello
|
||
ref: master
|
||
sha: ab9e13d49d1985cd7c2bb26a38b2859b1761691c
|
||
sha: 844c9d13e43fe9a4376bbadb3dedef566627a197
|
||
specs:
|
||
katello/katello (0.0.1)
|
||
|
||
... | ... | |
GIT
|
||
remote: https://github.com/theforeman/puppet-foreman
|
||
ref: master
|
||
sha: 67b713743d44a639e3d5a2d021dd9be42a3cb5ca
|
||
sha: 12aa4ab590028e3f3e01b253190e3c92c475b0c3
|
||
specs:
|
||
theforeman/foreman (2.0.1)
|
||
puppetlabs/apache (~> 1.0)
|
modules/foreman/manifests/install/repos/apt.pp | ||
---|---|---|
# Install an apt repo
|
||
define foreman::install::repos::apt ($repo) {
|
||
file { "/etc/apt/sources.list.d/${name}.list":
|
||
content => "deb http://deb.theforeman.org/ ${::lsbdistcodename} ${repo}\ndeb http://deb.theforeman.org/ plugins main\n"
|
||
content => "deb http://deb.theforeman.org/ ${::lsbdistcodename} ${repo}\ndeb http://deb.theforeman.org/ plugins ${repo}\n"
|
||
} ~>
|
||
exec { "foreman-key-${name}":
|
||
command => '/usr/bin/wget -q http://deb.theforeman.org/foreman.asc -O- | /usr/bin/apt-key add -',
|
modules/foreman/spec/defines/foreman_install_repos_apt_spec.rb | ||
---|---|---|
|
||
it 'should add the stable repo' do
|
||
should contain_file('/etc/apt/sources.list.d/foreman.list') \
|
||
.with_content("deb http://deb.theforeman.org/ squeeze stable\ndeb http://deb.theforeman.org/ plugins main\n")
|
||
.with_content("deb http://deb.theforeman.org/ squeeze stable\ndeb http://deb.theforeman.org/ plugins stable\n")
|
||
end
|
||
end
|
||
|
||
... | ... | |
|
||
it 'should add the rc repo' do
|
||
should contain_file('/etc/apt/sources.list.d/foreman.list') \
|
||
.with_content("deb http://deb.theforeman.org/ squeeze rc\ndeb http://deb.theforeman.org/ plugins main\n")
|
||
.with_content("deb http://deb.theforeman.org/ squeeze rc\ndeb http://deb.theforeman.org/ plugins rc\n")
|
||
end
|
||
end
|
||
|
||
... | ... | |
|
||
it 'should add the nightly repo' do
|
||
should contain_file('/etc/apt/sources.list.d/foreman.list') \
|
||
.with_content("deb http://deb.theforeman.org/ squeeze nightly\ndeb http://deb.theforeman.org/ plugins main\n")
|
||
.with_content("deb http://deb.theforeman.org/ squeeze nightly\ndeb http://deb.theforeman.org/ plugins nightly\n")
|
||
end
|
||
end
|
||
|
modules/foreman/spec/unit/foreman_external_node_spec.rb | ||
---|---|---|
File.stubs(:stat).returns(stub(:mtime => Time.now.utc))
|
||
enc.stubs(:build_body).returns({'fake' => 'data'})
|
||
|
||
enc.upload_facts('fake.host.fqdn.com',"#{static_fixture_path}/fake.host.fqdn.com.yaml")
|
||
req = enc.generate_fact_request('fake.host.fqdn.com',"#{static_fixture_path}/fake.host.fqdn.com.yaml")
|
||
enc.upload_facts('fake.host.fqdn.com',req)
|
||
webstub.should have_been_requested
|
||
|
||
# test pushing facts async
|
||
http_fact_requests = []
|
||
http_fact_requests << ['fake.host.fqdn.com', req]
|
||
enc.upload_facts_parallel(http_fact_requests)
|
||
|
||
webstub.should have_been_requested.times(2)
|
||
|
||
http_fact_requests << ['fake.host.fqdn.com', req]
|
||
http_fact_requests << ['fake.host.fqdn.com', req]
|
||
enc.upload_facts_parallel(http_fact_requests)
|
||
|
||
webstub.should have_been_requested.times(4)
|
||
end
|
||
|
||
it "should have the correct certname and hostname" do
|
modules/foreman/templates/external_node_v2.rb.erb | ||
---|---|---|
:puppetuser => "<%= @puppet_user %>", # e.g. puppet
|
||
:facts => <%= @facts %>, # true/false to upload facts
|
||
:timeout => 10,
|
||
:threads => nil,
|
||
# if CA is specified, remote Foreman host will be verified
|
||
:ssl_ca => "<%= @ssl_ca -%>", # e.g. /var/lib/puppet/ssl/certs/ca.pem
|
||
# ssl_cert and key are required if require_ssl_puppetmasters is enabled in Foreman
|
||
... | ... | |
SETTINGS[:timeout] || 3
|
||
end
|
||
|
||
def thread_count
|
||
return SETTINGS[:threads].to_i if not SETTINGS[:threads].nil? and SETTINGS[:threads].to_i > 0
|
||
require 'facter'
|
||
processors = Facter.value(:processorcount).to_i
|
||
processors > 0 ? processors : 1
|
||
end
|
||
|
||
class Http_Fact_Requests
|
||
include Enumerable
|
||
|
||
def initialize
|
||
@results_array = []
|
||
end
|
||
|
||
def <<(val)
|
||
@results_array << val
|
||
end
|
||
|
||
def each(&block)
|
||
@results_array.each(&block)
|
||
end
|
||
|
||
def pop
|
||
@results_array.pop
|
||
end
|
||
end
|
||
|
||
require 'etc'
|
||
require 'net/http'
|
||
require 'net/https'
|
||
... | ... | |
end
|
||
end
|
||
|
||
def upload_all_facts
|
||
def process_all_facts(http_requests)
|
||
Dir["#{puppetdir}/yaml/facts/*.yaml"].each do |f|
|
||
certname = File.basename(f, ".yaml")
|
||
# Skip empty host fact yaml files
|
||
if File.size(f) != 0
|
||
upload_facts(certname, f)
|
||
req = generate_fact_request(certname, f)
|
||
if http_requests
|
||
http_requests << [certname, req]
|
||
elsif req
|
||
upload_facts(certname, req)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
... | ... | |
{'facts' => puppet_facts['values'], 'name' => hostname, 'certname' => certname}
|
||
end
|
||
|
||
def upload_facts(certname, filename)
|
||
def initialize_http(uri)
|
||
res = Net::HTTP.new(uri.host, uri.port)
|
||
res.use_ssl = uri.scheme == 'https'
|
||
if res.use_ssl?
|
||
if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?
|
||
res.ca_file = SETTINGS[:ssl_ca]
|
||
res.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||
else
|
||
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||
end
|
||
if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
|
||
res.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
|
||
res.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
|
||
end
|
||
end
|
||
res
|
||
end
|
||
|
||
def generate_fact_request(certname, filename)
|
||
# Temp file keeping the last run time
|
||
stat = stat_file("#{certname}-push-facts")
|
||
last_run = File.exists?(stat) ? File.stat(stat).mtime.utc : Time.now - 365*24*60*60
|
||
... | ... | |
req.add_field('Accept', 'application/json,version=2' )
|
||
req.content_type = 'application/json'
|
||
req.body = build_body(certname, filename).to_json
|
||
res = Net::HTTP.new(uri.host, uri.port)
|
||
res.use_ssl = uri.scheme == 'https'
|
||
if res.use_ssl?
|
||
if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?
|
||
res.ca_file = SETTINGS[:ssl_ca]
|
||
res.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||
else
|
||
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||
end
|
||
if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
|
||
res.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
|
||
res.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
|
||
end
|
||
end
|
||
res.start { |http| http.request(req) }
|
||
cache("#{certname}-push-facts", "Facts from this host were last pushed to #{uri} at #{Time.now}\n")
|
||
req
|
||
rescue => e
|
||
raise "Could not send facts to Foreman: #{e}"
|
||
raise "Could not generate facts for Foreman: #{e}"
|
||
end
|
||
end
|
||
end
|
||
... | ... | |
end
|
||
res = http.start { |http| http.request(req) }
|
||
|
||
raise "Error retrieving node #{certname}: #{res.class}" unless res.code == "200"
|
||
raise "Error retrieving node #{certname}: #{res.class}\nCheck Foreman's /var/log/foreman/production.log for more information." unless res.code == "200"
|
||
res.body
|
||
end
|
||
|
||
def upload_facts(certname, req)
|
||
return nil if req.nil?
|
||
uri = URI.parse("#{url}/api/hosts/facts")
|
||
begin
|
||
res = initialize_http(uri)
|
||
res.start { |http| http.request(req) }
|
||
cache("#{certname}-push-facts", "Facts from this host were last pushed to #{uri} at #{Time.now}\n")
|
||
rescue => e
|
||
raise "Could not send facts to Foreman: #{e}"
|
||
end
|
||
end
|
||
|
||
def upload_facts_parallel(http_fact_requests, wait = true)
|
||
t = thread_count.times.map {
|
||
Thread.new(http_fact_requests) do |fact_requests|
|
||
while factref = fact_requests.pop
|
||
certname = factref[0]
|
||
httpobj = factref[1]
|
||
if httpobj
|
||
upload_facts(certname, httpobj)
|
||
end
|
||
end
|
||
end
|
||
}
|
||
if wait
|
||
t.each(&:join)
|
||
end
|
||
end
|
||
|
||
def watch_and_send_facts(parallel)
|
||
begin
|
||
require 'inotify'
|
||
rescue LoadError
|
||
puts "You need the `ruby-inotify` (not inotify!) gem to watch for fact updates"
|
||
exit 2
|
||
end
|
||
|
||
watch_descriptors = []
|
||
pending = []
|
||
threads = thread_count
|
||
last_send = Time.now
|
||
|
||
inotify_limit = `sysctl fs.inotify.max_user_watches`.gsub(/[^\d]/, '').to_i
|
||
|
||
inotify = Inotify.new
|
||
|
||
inotify.add_watch("#{puppetdir}/yaml/facts", Inotify::CREATE)
|
||
|
||
yamls = Dir["#{puppetdir}/yaml/facts/*.yaml"]
|
||
|
||
if yamls.length > inotify_limit
|
||
puts "Looks like your inotify watch limit is #{inotify_limit} but you are asking to watch at least #{yamls.length} fact files."
|
||
puts "Increase the watch limit via the system tunable fs.inotify.max_user_watches, exiting."
|
||
exit 2
|
||
end
|
||
|
||
yamls.each do |f|
|
||
begin
|
||
watch_descriptors[inotify.add_watch(f, Inotify::CLOSE_WRITE)] = f
|
||
end
|
||
end
|
||
|
||
inotify.each_event do |ev|
|
||
fn = watch_descriptors[ev.wd]
|
||
add_watch = false
|
||
|
||
if !fn
|
||
fn = ev.name
|
||
add_watch = true
|
||
end
|
||
|
||
if File.extname(fn) != ".yaml"
|
||
next
|
||
end
|
||
|
||
if add_watch || (ev.mask & Inotify::ONESHOT)
|
||
watch_descriptors[inotify.add_watch(fn, Inotify::CLOSE_WRITE)] = fn
|
||
end
|
||
|
||
if fn
|
||
certname = File.basename(fn, ".yaml")
|
||
req = generate_fact_request certname, fn
|
||
if parallel
|
||
pending << [certname,req]
|
||
else
|
||
upload_facts(certname,req)
|
||
end
|
||
end
|
||
if parallel && (pending.length >= threads || ((last_send + 5) < Time.now))
|
||
if pending.length > 0
|
||
upload_facts_parallel(pending, false)
|
||
pending = []
|
||
end
|
||
last_send = Time.now
|
||
end
|
||
end
|
||
end
|
||
|
||
# Actual code starts here
|
||
|
||
if __FILE__ == $0 then
|
||
... | ... | |
begin
|
||
Process::GID.change_privilege(Etc.getgrnam(puppetuser).gid) unless Etc.getpwuid.name == puppetuser
|
||
Process::UID.change_privilege(Etc.getpwnam(puppetuser).uid) unless Etc.getpwuid.name == puppetuser
|
||
# Facter (in thread_count) tries to read from $HOME, which is still /root after the UID change
|
||
ENV['HOME'] = Etc.getpwnam(puppetuser).dir
|
||
rescue
|
||
$stderr.puts "cannot switch to user #{puppetuser}, continuing as '#{Etc.getpwuid.name}'"
|
||
end
|
||
|
||
begin
|
||
no_env = ARGV.delete("--no-environment")
|
||
if ARGV.delete("--push-facts")
|
||
watch = ARGV.delete("--watch-facts")
|
||
push_facts_parallel = ARGV.delete("--push-facts-parallel")
|
||
push_facts = ARGV.delete("--push-facts")
|
||
if watch && ! ( push_facts || push_facts_parallel )
|
||
raise "Cannot watch for facts without specifying --push-facts or --push-facts-parallel"
|
||
end
|
||
if push_facts
|
||
# push all facts files to Foreman and don't act as an ENC
|
||
upload_all_facts
|
||
process_all_facts(false)
|
||
elsif push_facts_parallel
|
||
http_fact_requests = Http_Fact_Requests.new
|
||
process_all_facts(http_fact_requests)
|
||
upload_facts_parallel(http_fact_requests)
|
||
else
|
||
certname = ARGV[0] || raise("Must provide certname as an argument")
|
||
# send facts to Foreman - enable 'facts' setting to activate
|
||
# if you use this option below, make sure that you don't send facts to foreman via the rake task or push facts alternatives.
|
||
#
|
||
if SETTINGS[:facts]
|
||
upload_facts certname, "#{puppetdir}/yaml/facts/#{certname}.yaml"
|
||
req = generate_fact_request certname, "#{puppetdir}/yaml/facts/#{certname}.yaml"
|
||
upload_facts(certname, req)
|
||
end
|
||
#
|
||
# query External node
|
||
... | ... | |
rescue TimeoutError, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED
|
||
# Read from cache, we got some sort of an error.
|
||
result = read_cache(certname)
|
||
ensure
|
||
end
|
||
|
||
if no_env
|
||
require 'yaml'
|
||
yaml = YAML.load(result)
|
||
if no_env
|
||
yaml.delete('environment')
|
||
end
|
||
yaml.delete('environment')
|
||
# Always reset the result to back to clean yaml on our end
|
||
puts yaml.to_yaml
|
||
else
|
||
puts result
|
||
end
|
||
end
|
||
rescue => e
|
||
warn e
|
||
exit 1
|
||
end
|
||
if watch
|
||
watch_and_send_facts(push_facts_parallel)
|
||
end
|
||
end
|
modules/katello/manifests/init.pp | ||
---|---|---|
# === Parameters:
|
||
#
|
||
# $user:: The Katello system user name;
|
||
# default 'katello'
|
||
# default 'foreman'
|
||
#
|
||
# $group:: The Katello system user group;
|
||
# default 'katello'
|
||
# default 'foreman'
|
||
#
|
||
# $user_groups:: Extra user groups the Katello user is a part of;
|
||
# default 'foreman
|
modules/katello/manifests/params.pp | ||
---|---|---|
$proxy_pass = 'NONE'
|
||
|
||
# system settings
|
||
$user = 'foreman'
|
||
$group = 'foreman'
|
||
$user_groups = 'foreman'
|
||
$config_dir = '/etc/foreman/plugins'
|
||
$log_dir = '/var/log/foreman/plugins'
|
modules/katello/templates/etc/httpd/conf.d/05-foreman-ssl.d/katello.conf.erb | ||
---|---|---|
# CHANGES WILL LIKELY BE OVERWRITTEN.
|
||
#
|
||
|
||
SSLOptions +StdEnvVars +ExportCertData +FakeBasicAuth
|
||
|
||
Alias /pub /var/www/html/pub
|
||
<Location /pub>
|
||
PassengerEnabled off
|
||
... | ... | |
SSLVerifyDepth 2
|
||
</Location>
|
||
|
||
SSLOptions +StdEnvVars +ExportCertData +FakeBasicAuth
|
||
<Location /katello/api>
|
||
# client certs support (old rhsm clients)
|
||
RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
|
||
SSLVerifyClient optional
|
||
SSLRenegBufferSize 16777216
|
||
SSLVerifyDepth 2
|
||
|
||
# report to CLI and RHSM nicely when Katello is down
|
||
ErrorDocument 500 '{"displayMessage": "Internal error, contact administrator", "errors": ["Internal error, contact administrator"], "status": "500" }'
|
||
ErrorDocument 503 '{"displayMessage": "Service unavailable or restarting, try later", "errors": ["Service unavailable or restarting, try later"], "status": "503" }'
|
||
</Location>
|
Also available in: Unified diff
Update puppet modules