Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Testing Ansibile with Vagrant and RSpec
require 'net/ssh'
require "#{File.dirname(__FILE__)}/utils/gems.rb"
require "#{File.dirname(__FILE__)}/utils/multi_logger.rb"
require "#{File.dirname(__FILE__)}/utils/subprocess.rb"
class SpecHelper
class << self
@@booted = false
def ensure_booted
if @@booted
logger.write "test cluster already booted..."
else
boot
end
end
def ssh_config
return @config unless @config.nil?
@config = {}
lines = `vagrant ssh-config`.split("\n")
current_host = nil
lines.each do |line|
words = line.split(" ")
if words.length < 2
next
elsif words.first == 'Host'
current_host = words.last
@config[current_host] = {}
else
@config[current_host][words.first] = words.last
end
end
@config
end
def logger
MultiLogger.new(STDOUT, log_file)
end
def log_file
File.expand_path("#{File.dirname(__FILE__)}/../log/test.log")
end
def boot
logger.write "[[ BOOT ]]", :purple
Utils::SubprocessWithLog.new("vagrant up --parallel --no-provision", "vagrant-boot", logger)
end
def provision
logger.write "[[ PROVISION ]]", :purple
# We only define 1 server to provision here, but the ansible inventory lists all nodes
Utils::SubprocessWithLog.new("vagrant provision", '*', logger)
end
def vagrant_ssh_key
"#{ENV['HOME']}/.vagrant.d/insecure_private_key"
end
def ssh_username
'vagrant'
end
def ssh_host
'127.0.0.1'
end
def ips
return @remote_ips unless @remote_ips.nil?
@remote_ips = []
ssh_config.each do |name, data|
port = data['Port'].to_i
Net::SSH.start(ssh_host, ssh_username, {
port: port,
keys: [vagrant_ssh_key],
:paranoid => Net::SSH::Verifiers::Null.new
}) do |session|
remote_data = session.exec!('ifconfig -a')
possible_ips = remote_data.scan(/.*inet addr:(\S*)/)
possible_ips.each do |ip|
ip = ip.first
parts = ip.split(".")
next if parts.first == '127'
next if parts.first == '10'
@remote_ips << ip
end
end
end
@remote_ips
end
def remote_command(ip, command)
remote_data = nil
Net::SSH.start(ip, ssh_username, {
keys: [vagrant_ssh_key],
:paranoid => Net::SSH::Verifiers::Null.new
}) do |session|
remote_data = session.exec!(command)
end
remote_data
end
def remote_file(ip, path)
command = "sudo cat #{path}" #TODO: unsafe... but this is a test suite!
remote_command(ip, command)
end
end
end
RSpec.configure do |config|
config.before(:suite) do
SpecHelper.ensure_booted
end
end
require 'rubygems'
require 'bundler'
Bundler.require(:default)
require 'fileutils'
class MultiLogger
def initialize(*targets)
@targets = targets
ensure_files
end
def ensure_files
@targets.each do |t|
if t.class != IO
FileUtils.mkdir_p File.dirname(t)
FileUtils.touch t
end
end
end
def write(lines, color=:normal, to_clock=true)
date_string = Time.new.strftime('%Y-%m-%d %l:%M:%S')
lines.split("\n").each do |line|
@targets.each do |t|
formatted_line = ""
if t.class == IO
formatted_line = "[#{color}]" + line + "[/]"
formatted_line = "[light_cyan][#{date_string}][/] " + formatted_line if to_clock
# t.write(formatted_line)
Formatador.display_line(formatted_line)
else
formatted_line = line + "\r\n"
formatted_line = "[#{date_string}] " + formatted_line if to_clock
File.open(t,"a+") {|f| f.write(formatted_line) }
end
end
end
end
end
require 'open3'
module Utils
class Subprocess
def initialize(cmd, &block)
# see: http://stackoverflow.com/a/1162850/83386
Open3.popen3(ENV, cmd) do |stdin, stdout, stderr, thread|
{ :out => stdout, :err => stderr }.each do |key, stream|
Thread.new do
until (line = stream.gets).nil? do
if key == :out
yield line, nil, thread if block_given?
else
yield nil, line, thread if block_given?
end
end
end
end
thread.join # don't exit until the external process is done
end
end
end
class SubprocessWithLog
def initialize(cmd, name=nil, logger)
Utils::Subprocess.new(cmd) do |stdout, stderr, thread|
logger.write("[#{name}] #{stdout.to_s.strip}") if stdout
logger.write("[#{name}] #{stderr.to_s.strip}", :red) if stderr
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment