summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rwxr-xr-xbin/puppet_command75
-rwxr-xr-xbin/run_tests236
2 files changed, 101 insertions, 210 deletions
diff --git a/bin/puppet_command b/bin/puppet_command
index a6cd5a69..cdb0b027 100755
--- a/bin/puppet_command
+++ b/bin/puppet_command
@@ -7,12 +7,17 @@
# (exit codes, lockfile, multiple manifests, etc)
#
+require 'pty'
+require 'yaml'
+
PUPPET_BIN = '/usr/bin/puppet'
PUPPET_DIRECTORY = '/srv/leap'
PUPPET_PARAMETERS = '--color=false --detailed-exitcodes --libdir=puppet/lib --confdir=puppet'
SITE_MANIFEST = 'puppet/manifests/site.pp'
-SETUP_MANIFEST = 'puppet/manifests/setup.pp'
+SITE_MODULES = 'puppet/modules'
+CUSTOM_MODULES = ':files/puppet/modules'
DEFAULT_TAGS = 'leap_base,leap_service'
+HIERA_FILE = '/etc/leap/hiera.yaml'
def main
process_command_line_arguments
@@ -54,21 +59,33 @@ def apply
end
def set_hostname
- exit_code = puppet_apply(:manifest => SETUP_MANIFEST, :tags => '') do |line|
- # todo: replace setup.pp with https://github.com/lutter/ruby-augeas
- # or try this: http://www.puppetcookbook.com/posts/override-a-facter-fact.html
- if (line !~ /Finished catalog run/ || @verbosity > 2) &&
- (line !~ /dnsdomainname: Name or service not known/) &&
- (line !~ /warning: Could not retrieve fact fqdn/)
- puts line
+ hostname = hiera_file['name']
+ if hostname.nil? || hostname.empty?
+ puts('ERROR: "name" missing from hiera file')
+ exit(1)
+ end
+ current_hostname_file = File.read('/etc/hostname') rescue nil
+ current_hostname = `/bin/hostname`.strip
+
+ # set /etc/hostname
+ if current_hostname_file != hostname
+ File.open('/etc/hostname', 'w', 0611, :encoding => 'ascii') do |f|
+ f.write hostname
+ end
+ if File.read('/etc/hostname') == hostname
+ puts "Changed /etc/hostname to #{hostname}"
+ else
+ puts "ERROR: failed to update /etc/hostname"
end
end
- if exit_code == 2
- puts "Hostname updated."
- elsif exit_code == 4 || exit_code == 6
- puts "ERROR: could not update hostname."
- elsif exit_code == 0 && @verbosity > 1
- puts "No change to hostname."
+
+ # call /bin/hostname
+ if current_hostname != hostname
+ if run("/bin/hostname #{hostname}") == 0
+ puts "Changed hostname to #{hostname}"
+ else
+ puts "ERROR: call to `/bin/hostname #{hostname}` returned an error."
+ end
end
end
@@ -78,11 +95,29 @@ end
def puppet_apply(options={}, &block)
options = {:verbosity => @verbosity, :tags => @tags}.merge(options)
manifest = options[:manifest] || SITE_MANIFEST
+ modulepath = options[:module_path] || SITE_MODULES + CUSTOM_MODULES
+ fqdn = hiera_file['domain']['name']
+ domain = hiera_file['domain']['full_suffix']
Dir.chdir(PUPPET_DIRECTORY) do
- return run("#{PUPPET_BIN} apply #{custom_parameters(options)} #{PUPPET_PARAMETERS} #{manifest}", &block)
+ return run("FACTER_fqdn='#{fqdn}' FACTER_domain='#{domain}' #{PUPPET_BIN} apply #{custom_parameters(options)} --modulepath='#{modulepath}' #{PUPPET_PARAMETERS} #{manifest}", &block)
end
end
+#
+# Return a ruby object representing the contents of the hiera yaml file.
+#
+def hiera_file
+ unless File.exists?(HIERA_FILE)
+ puts("ERROR: hiera file '#{HIERA_FILE}' does not exist.")
+ exit(1)
+ end
+ $hiera_contents ||= YAML.load_file(HIERA_FILE)
+ return $hiera_contents
+rescue Exception => exc
+ puts("ERROR: problem reading hiera file '#{HIERA_FILE}' (#{exc})")
+ exit(1)
+end
+
def custom_parameters(options)
params = []
if options[:tags] && options[:tags].chars.any?
@@ -157,24 +192,18 @@ end
## this only works under ruby 1.9
##
-require "pty"
-
def run(cmd)
puts cmd if @verbosity >= 3
PTY.spawn("#{cmd}") do |output, input, pid|
begin
while line = output.gets do
yield line
- #$stdout.puts line
- #$stdout.flush
end
rescue Errno::EIO
end
Process.wait(pid) # only works in ruby 1.9, required to capture the exit status.
end
- status = $?.exitstatus
- #yield status if block_given?
- return status
+ return $?.exitstatus
rescue PTY::ChildExited
end
@@ -188,4 +217,4 @@ Signal.trap("EXIT") do
# but only after the child puppet process is also dead (I think).
end
-main() \ No newline at end of file
+main()
diff --git a/bin/run_tests b/bin/run_tests
index 526aa83a..44384379 100755
--- a/bin/run_tests
+++ b/bin/run_tests
@@ -14,7 +14,6 @@
require 'minitest/unit'
require 'yaml'
require 'tsort'
-require 'net/http'
##
## EXIT CODES
@@ -37,19 +36,28 @@ def bail(code, msg=nil)
end
##
+## UTILITY
+##
+
+def service?(service)
+ $node["services"].include?(service.to_s)
+end
+
+##
## EXCEPTIONS
##
# this class is raised if a test file wants to be skipped entirely.
-class SkipTest < Exception
+# (to skip an individual test, MiniTest::Skip is used instead)
+class SkipTest < StandardError
end
# raised if --no-continue and there is an error
-class TestError < Exception
+class TestError < StandardError
end
# raised if --no-continue and there is a failure
-class TestFailure < Exception
+class TestFailure < StandardError
end
##
@@ -62,6 +70,8 @@ end
class LeapTest < MiniTest::Unit::TestCase
class Pass < MiniTest::Assertion
end
+ class Ignore < MiniTest::Assertion
+ end
def initialize(name)
super(name)
@@ -101,10 +111,20 @@ class LeapTest < MiniTest::Unit::TestCase
end
#
+ # Called when the test should be silently ignored.
+ #
+ def ignore
+ raise LeapTest::Ignore
+ end
+
+ #
# the default fail() is part of the kernel and it just throws a runtime exception. for tests,
# we want the same behavior as assert(false)
#
- def fail(msg=nil)
+ def fail(msg=nil, exception=nil)
+ if DEBUG && exception && exception.respond_to?(:backtrace)
+ msg += MiniTest::filter_backtrace(exception.backtrace).join "\n"
+ end
assert(false, msg)
end
@@ -119,182 +139,6 @@ class LeapTest < MiniTest::Unit::TestCase
:alpha
end
- #
- # attempts a http GET on the url, yields |body, response, error|
- #
- def get(url, params=nil)
- uri = URI(url)
- if params
- uri.query = URI.encode_www_form(params)
- end
- response = Net::HTTP.get_response(uri)
- if response.is_a?(Net::HTTPSuccess)
- yield response.body, response, nil
- else
- yield nil, response, nil
- end
- rescue => exc
- yield nil, nil, exc
- end
-
- def assert_get(url, params=nil, options=nil)
- options ||= {}
- get(url, params) do |body, response, error|
- if body
- yield body if block_given?
- elsif response
- fail ["Expected a 200 status code from #{url}, but got #{response.code} instead.", options[:error_msg]].compact.join("\n")
- else
- fail ["Expected a response from #{url}, but got \"#{error}\" instead.", options[:error_msg]].compact.join("\n")
- end
- end
- end
-
- #
- # test if a socket can be connected to
- #
-
- #
- # tcp connection helper with timeout
- #
- def try_tcp_connect(host, port, timeout = 5)
- addr = Socket.getaddrinfo(host, nil)
- sockaddr = Socket.pack_sockaddr_in(port, addr[0][3])
-
- Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0).tap do |socket|
- socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
- begin
- socket.connect_nonblock(sockaddr)
- rescue IO::WaitReadable
- if IO.select([socket], nil, nil, timeout) == nil
- raise "Connection timeout"
- else
- socket.connect_nonblock(sockaddr)
- end
- rescue IO::WaitWritable
- if IO.select(nil, [socket], nil, timeout) == nil
- raise "Connection timeout"
- else
- socket.connect_nonblock(sockaddr)
- end
- end
- return socket
- end
- end
-
- def try_tcp_write(socket, timeout = 5)
- begin
- socket.write_nonblock("\0")
- rescue IO::WaitReadable
- if IO.select([socket], nil, nil, timeout) == nil
- raise "Write timeout"
- else
- retry
- end
- rescue IO::WaitWritable
- if IO.select(nil, [socket], nil, timeout) == nil
- raise "Write timeout"
- else
- retry
- end
- end
- end
-
- def try_tcp_read(socket, timeout = 5)
- begin
- socket.read_nonblock(1)
- rescue IO::WaitReadable
- if IO.select([socket], nil, nil, timeout) == nil
- raise "Read timeout"
- else
- retry
- end
- rescue IO::WaitWritable
- if IO.select(nil, [socket], nil, timeout) == nil
- raise "Read timeout"
- else
- retry
- end
- end
- end
-
- def assert_tcp_socket(host, port, msg=nil)
- begin
- socket = try_tcp_connect(host, port, 1)
- #try_tcp_write(socket,1)
- #try_tcp_read(socket,1)
- rescue StandardError => exc
- fail ["Failed to open socket #{host}:#{port}", exc].join("\n")
- ensure
- socket.close if socket
- end
- end
-
- #
- # Matches the regexp in the file, and returns the first matched string (or fails if no match).
- #
- def file_match(filename, regexp)
- if match = File.read(filename).match(regexp)
- match.captures.first
- else
- fail "Regexp #{regexp.inspect} not found in file #{filename.inspect}."
- end
- end
-
- #
- # Matches the regexp in the file, and returns array of matched strings (or fails if no match).
- #
- def file_matches(filename, regexp)
- if match = File.read(filename).match(regexp)
- match.captures
- else
- fail "Regexp #{regexp.inspect} not found in file #{filename.inspect}."
- end
- end
-
- #
- # checks to make sure the given property path exists in $node (e.g. hiera.yaml)
- # and returns the value
- #
- def assert_property(property)
- latest = $node
- property.split('.').each do |segment|
- latest = latest[segment]
- fail "Required node property `#{property}` is missing." if latest.nil?
- end
- return latest
- end
-
- #
- # works like pgrep command line
- # return an array of hashes like so [{:pid => "1234", :process => "ls"}]
- #
- def pgrep(match)
- output = `pgrep --full --list-name '#{match}'`
- output.each_line.map{|line|
- pid = line.split(' ')[0]
- process = line.gsub(/(#{pid} |\n)/, '')
- if process =~ /pgrep --full --list-name/
- nil
- else
- {:pid => pid, :process => process}
- end
- }.compact
- end
-end
-
-def assert_running(process)
- assert pgrep(process).any?, "No running process for #{process}"
-end
-
-#
-# runs the specified command, failing on a non-zero exit status.
-#
-def assert_run(command)
- output = `#{command}`
- if $?.exitstatus != 0
- fail "Error running `#{command}`:\n#{output}"
- end
end
#
@@ -307,6 +151,7 @@ class LeapRunner < MiniTest::Unit
def initialize
@passes = 0
@warnings = 0
+ @ignores = 0
super
end
@@ -347,9 +192,12 @@ class LeapRunner < MiniTest::Unit
case e
when MiniTest::Skip then
@skips += 1
- #if @verbose
- report_line("SKIP", klass, meth, e, e.message)
- #end
+ report_line("SKIP", klass, meth, e, e.message)
+ when LeapTest::Ignore then
+ @ignores += 1
+ if @verbose
+ report_line("IGNORE", klass, meth, e, e.message)
+ end
when LeapTest::Pass then
@passes += 1
report_line("PASS", klass, meth)
@@ -389,7 +237,8 @@ class LeapRunner < MiniTest::Unit
elsif @failures > 0
:failure
elsif @warnings > 0
- :warning
+ # :warning << warnings don't warrant a non-zero exit code.
+ :success
else
:success
end
@@ -401,7 +250,7 @@ class LeapRunner < MiniTest::Unit
def report_line(prefix, klass, meth, e=nil, message=nil)
msg_txt = nil
if message
- message = message.sub(/http:\/\/([a-z_]+):([a-zA-Z0-9_]+)@/, "http://\\1:password@")
+ message = message.sub(/http:\/\/([a-z_]+):([a-zA-Z0-9_]+)@/, "http://\\1:REDACTED@")
if $output_format == :human
indent = "\n "
msg_txt = indent + message.split("\n").join(indent)
@@ -516,7 +365,8 @@ def print_help
" --test TEST Run only the test with name TEST.",
" --list-tests Prints the names of all available tests and exit.",
" --retry COUNT If the tests don't pass, retry COUNT additional times (default is zero)",
- " --wait SECONDS Wait for SECONDS between retries (default is 5)"].join("\n")
+ " --wait SECONDS Wait for SECONDS between retries (default is 5)",
+ " --debug Print out full stack trace on errors"].join("\n")
exit(0)
end
@@ -575,6 +425,9 @@ def main
# load all test classes
this_file = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
+ Dir[File.expand_path('../../tests/helpers/*.rb', this_file)].each do |helper|
+ require helper
+ end
Dir[File.expand_path('../../tests/white-box/*.rb', this_file)].each do |test_file|
begin
require test_file
@@ -596,10 +449,19 @@ def main
when '--list-tests' then list_tests
when '--retry' then ARGV.shift; $retry = ARGV.shift.to_i
when '--wait' then ARGV.shift; $wait = ARGV.shift.to_i
+ when '--debug' then ARGV.shift
+ when '-d' then ARGV.shift
else break
end
end
run_tests
end
+if ARGV.include?('--debug') || ARGV.include?('-d')
+ DEBUG=true
+ require 'debugger'
+else
+ DEBUG=false
+end
+
main()