Made a lot of progress

This commit is contained in:
Tristan Ancelet 2024-06-09 21:16:20 -05:00
parent d533104927
commit 7e71d62bce
6 changed files with 298 additions and 0 deletions

83
lib/host.rb Normal file
View 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
View 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
View 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
View 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
View 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
View 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