Made a lot of progress
This commit is contained in:
parent
d533104927
commit
7e71d62bce
83
lib/host.rb
Normal file
83
lib/host.rb
Normal file
@ -0,0 +1,83 @@
|
||||
module RubyQA
|
||||
require 'net/ssh'
|
||||
class Host
|
||||
DEFAULT_HOSTDATA={
|
||||
:hostname => "",
|
||||
:ip => "",
|
||||
:port => 22,
|
||||
:user => "",
|
||||
:password => "",
|
||||
:site => "",
|
||||
:cluster => false,
|
||||
:sudo_password => "",
|
||||
}
|
||||
|
||||
attr_accessor *DEFAULT_HOSTDATA.keys
|
||||
attr_reader :client, :data, :resources
|
||||
|
||||
def initialize( data = {} )
|
||||
@resources = Hash.new
|
||||
|
||||
@data = DEFAULT_HOSTDATA.merge data
|
||||
|
||||
## Verifying the (Needed) variables are set to valid values (and/or can be resolved to valid values)
|
||||
verify_data
|
||||
|
||||
## initialize client for usage tests
|
||||
init_client
|
||||
end
|
||||
|
||||
def init_client
|
||||
@client = Net::SSH.start(@data[:ip], @data[:user])
|
||||
end
|
||||
|
||||
def exec (command)
|
||||
@client.exec!(command)
|
||||
end
|
||||
|
||||
def [](key)
|
||||
@data[key]
|
||||
end
|
||||
|
||||
def name
|
||||
if @data[:hostname] != ""
|
||||
return @data[:hostname]
|
||||
elsif @resources['facts'].data['networking']['hostname'] != ""
|
||||
return @resources['facts'].data['networking']['hostname']
|
||||
else
|
||||
return @data[:ip]
|
||||
end
|
||||
end
|
||||
|
||||
def add_resource (object)
|
||||
## If the requirements are met by the host, add the resource
|
||||
if object::REQUIREMENTS.all?{|key,val| @data[key] == val}
|
||||
resource = object.new(self)
|
||||
@resources[resource.name]=resource
|
||||
end
|
||||
end
|
||||
|
||||
def update_resources
|
||||
@resources.each_value(&:gather)
|
||||
end
|
||||
|
||||
def verify_data
|
||||
if @data[:ip].empty?
|
||||
if not @data[:hostname].empty?
|
||||
begin
|
||||
@data[:ip] = Resolv.getaddress(@data[:hostname])
|
||||
rescue Resolv::ResolvError => error
|
||||
raise "Host: Hostname provided, but did not resolve to IP"
|
||||
end
|
||||
else
|
||||
raise "Host: No hostname or IP provided"
|
||||
end
|
||||
end
|
||||
|
||||
if @data[:user].empty?
|
||||
raise ArgumentError, "Host: User not provided"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
43
lib/manager.rb
Normal file
43
lib/manager.rb
Normal file
@ -0,0 +1,43 @@
|
||||
module RubyQA
|
||||
class Manager
|
||||
attr_reader :resources
|
||||
@@tests = Array.new
|
||||
|
||||
def initialize
|
||||
@hosts = Array.new
|
||||
end
|
||||
|
||||
def add_host(host)
|
||||
@hosts << host
|
||||
register_resources(host)
|
||||
update_resources(host)
|
||||
end
|
||||
|
||||
def register_resources (host)
|
||||
Resource.all_resources.each do |resource|
|
||||
host.add_resource(resource)
|
||||
end
|
||||
end
|
||||
|
||||
def update_resources (host)
|
||||
host.update_resources
|
||||
end
|
||||
|
||||
def self.new_test(name, options={}, &test_proc)
|
||||
@@tests << Test.new(name, **options, &test_proc)
|
||||
end
|
||||
|
||||
def run_tests
|
||||
@hosts.each do |host|
|
||||
tests = @@tests.select{|test| test.valid_host(host)}
|
||||
tests.each do |test|
|
||||
test.run(host)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def report
|
||||
puts @@tests.map(&:report).join("\n")
|
||||
end
|
||||
end
|
||||
end
|
65
lib/resource.rb
Normal file
65
lib/resource.rb
Normal file
@ -0,0 +1,65 @@
|
||||
module RubyQA
|
||||
class Resource
|
||||
attr_reader :name, :data
|
||||
REQUIREMENTS = {}
|
||||
|
||||
def initialize (host)
|
||||
@host = host
|
||||
@data = Hash.new
|
||||
@gather_command = ""
|
||||
end
|
||||
|
||||
def gather
|
||||
if not @gather_command.empty?
|
||||
output = @host.exec(@gather_command)
|
||||
parse(output)
|
||||
else
|
||||
raise "@gather_command was not defined on Resource[#{@name}]"
|
||||
end
|
||||
end
|
||||
|
||||
def parse(output)
|
||||
raise "parse not yet implemented on Resource[#{@name}]"
|
||||
end
|
||||
|
||||
## This will allow me to iterate through all subclasses without
|
||||
## having to manually define them elsewhere
|
||||
def self.all_resources
|
||||
ObjectSpace.each_object(Class).select{|klass| klass < self}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
## Gathers the facts from the remote machine via the facter utility
|
||||
require 'json'
|
||||
class Facts < Resource
|
||||
REQUIREMENTS = {}
|
||||
def initialize (host)
|
||||
super host
|
||||
@name = 'facts'
|
||||
@gather_command = "facter -j"
|
||||
end
|
||||
|
||||
def parse (output)
|
||||
@data = JSON.load(output)
|
||||
end
|
||||
end
|
||||
|
||||
class DRDB < Resource
|
||||
REQUIREMENTS = {
|
||||
:cluster => true
|
||||
}
|
||||
|
||||
def initialize (host)
|
||||
super host
|
||||
@name = 'facts'
|
||||
@gather_command = "sudo drbdadm"
|
||||
end
|
||||
|
||||
def parse (output)
|
||||
@data = output
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
7
lib/rubyqa.rb
Normal file
7
lib/rubyqa.rb
Normal file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
$LOAD_PATH << __dir__
|
||||
require 'manager.rb'
|
||||
require 'resource.rb'
|
||||
require 'host.rb'
|
||||
require 'test.rb'
|
29
lib/test
Normal file
29
lib/test
Normal file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require './rubyqa'
|
||||
|
||||
include RubyQA
|
||||
$Manager = Manager.new
|
||||
|
||||
host = Host.new(
|
||||
:ip => '127.0.0.1',
|
||||
:user => 'tristan',
|
||||
:cluster => true
|
||||
)
|
||||
|
||||
Manager.new_test("hostname in /etc/hostname") {|host|
|
||||
hostname = host.exec('cat /etc/hostname').strip
|
||||
facts = host.resources['facts'].data
|
||||
facts['networking']['hostname'] == hostname
|
||||
}
|
||||
|
||||
Manager.new_test("hostname in /etc/hosts", :cluster => true ) {|host|
|
||||
facts = host.resources['facts'].data
|
||||
hostname = facts['networking']['hostname']
|
||||
hosts = host.exec('cat /etc/hosts')
|
||||
match_regex = /127\.0\.0\.1.+#{hostname.downcase}/
|
||||
hosts.match? match_regex
|
||||
}
|
||||
$Manager.add_host(host)
|
||||
$Manager.run_tests
|
||||
$Manager.report
|
71
lib/test.rb
Normal file
71
lib/test.rb
Normal file
@ -0,0 +1,71 @@
|
||||
module RubyQA
|
||||
require 'erb'
|
||||
class Test
|
||||
DEFAULT_OPTIONS={
|
||||
:site => "",
|
||||
:cluster => false,
|
||||
:has_key => "",
|
||||
}.freeze
|
||||
|
||||
attr_reader :name, :options, :proc
|
||||
|
||||
def initialize (name, options ={}, &test_block)
|
||||
@tests = Hash.new
|
||||
@name = name
|
||||
@options = DEFAULT_OPTIONS.merge(options)
|
||||
@test = test_block
|
||||
@description = ""
|
||||
if options[:description]
|
||||
@description=options[:description]
|
||||
end
|
||||
end
|
||||
|
||||
def valid_host(host)
|
||||
## By default if options weren't changed, then
|
||||
## we just assume it is to be tested against all
|
||||
## provided hosts
|
||||
is_valid = 0
|
||||
if @options == DEFAULT_OPTIONS
|
||||
return true
|
||||
end
|
||||
|
||||
DEFAULT_OPTIONS.each do |key,value|
|
||||
if @options[key] != value and host[key] != @options[key]
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def run (host)
|
||||
test_status = "N/A"
|
||||
if @test.call(host)
|
||||
test_status = "PASSED"
|
||||
else
|
||||
test_status = "FAILED"
|
||||
end
|
||||
@tests[host.name]=test_status
|
||||
end
|
||||
|
||||
def report
|
||||
if @tests.count == 0
|
||||
return
|
||||
end
|
||||
template = ERB.new <<EOF, :trim_mode => '-'
|
||||
==============================================
|
||||
Test : "<%= @name %>"
|
||||
<% if not @description.empty? -%>
|
||||
Description : "<%= @description %>
|
||||
<% end -%>
|
||||
==============================================
|
||||
<% @tests.each do |key,val| -%>
|
||||
<%= key %> : <%= val %>
|
||||
<% end -%>
|
||||
|
||||
EOF
|
||||
template.result(binding)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user