Move the concept of a Livery around to denote an actual class with more "structure"

This effectively breaks the crap out of existing Blimpfiles with a `ship.livery
= :cwd` line, or something similar. I think it's worth it at this point.

Liveries will have some access to the box object itself, so that API will need
to remain consistent for some time. It's expected that every Livery will have
at least:

    * setup_on(box)
    * preflight(box)
    * flight(box)
    * postflight(box)

This should be enough for just about every livery to do what it needs to do
with the created box. This should also allow (in the future) a Livery to
express variables or other configuration information "outward" for the
consumption of other Liveries.
This commit is contained in:
R. Tyler Croy 2012-08-22 22:08:33 -07:00
parent 8964005338
commit 9ed4d3ac99
10 changed files with 225 additions and 44 deletions

View File

@ -4,6 +4,34 @@ Feature: Craft machines based on a livery
When I specify a specific livery then that livery should provision
the host the way I would expect it to.
@wip
Scenario: Using a configuration-less livery
Given the following Blimpfile contents:
"""
Blimpy.fleet do |fleet|
fleet.add(:aws) do |ship|
ship.name = 'cucumber-livery'
ship.livery = Blimpy::Livery::CWD
end
end
"""
When I evaluate the Blimpfile
Then the "CWD" livery should be set up
@slow @destroy @wip
Scenario: freebsd_puppet
@wip
Scenario: Configuration-less liveries
Given the following Blimpfile contents:
"""
Blimpy.fleet do |fleet|
fleet.add(:aws) do |ship|
ship.name = 'cucumber-livery'
ship.livery = Blimpy::Livery::Puppet.configure do |p|
p.module_path = './modules'
p.manifest_path = './test/site.pp'
p.options = '--verbose'
end
end
end
"""
When I evaluate the Blimpfile
Then the Puppet livery should be correctly configured

View File

@ -0,0 +1,14 @@
Given /^the following Blimpfile contents:$/ do |buffer|
@blimpfile = buffer
end
When /^I evaluate the Blimpfile$/ do
@blimpfile.should_not be_nil
@fleet = eval(@blimpfile)
@fleet.should_not be_nil
end
Then /^the "([^"]*)" livery should be set up$/ do |arg1|
pending # express the regexp above with the code you wish you had
end

View File

@ -46,4 +46,5 @@ module Blimpy
end
class UnsupportedFeatureException < Exception
end
class InvalidLiveryException < Exception; end;
end

View File

@ -75,10 +75,16 @@ module Blimpy
def bootstrap
@exec_commands = false
unless livery.nil?
wait_for_sshd
bootstrap_livery
if @livery.nil?
return
end
if @livery.respond_to? :new
@livery = @livery.new
end
wait_for_sshd
bootstrap_livery
end
def stop
@ -204,46 +210,14 @@ module Blimpy
end
def bootstrap_livery
script = File.expand_path(File.dirname(__FILE__) + "/../../scripts/#{livery}.sh")
if livery == :cwd
script = File.join(Dir.pwd, '/bootstrap.sh')
if @livery.kind_of? Symbol
raise Blimpy::InvalidLiveryException, 'Symbol liveries are unsupported!'
end
unless File.exists?(script)
puts "Could not find `#{script}` which is needed to kick-start the machine"
return
end
unpack_command = 'true'
dir_name = File.basename(Dir.pwd)
if can_rsync?
unpack_command = "cd #{dir_name}"
run_command('rsync', '-avL',
'-e',
'ssh -o StrictHostKeyChecking=no',
'--exclude=.git',
'--exclude=.svn',
'--exclude=.blimpy.d',
'.',
"#{username}@#{dns}:#{dir_name}/")
else
puts "Remote host has no rsync(1), falling back to copying a full tarball over"
tarball = Blimpy::Livery.tarball_directory(Dir.pwd)
scp_file(tarball)
# HAXX
basename = File.basename(tarball)
ssh_into("tar -zxf #{basename} && cd #{dir_name}")
end
puts 'Bootstrapping the livery'
run_sudo = 'sudo'
if username == 'root'
run_sudo = ''
end
scp_file(script, dir_name)
ssh_into("cd #{dir_name} && #{run_sudo} ./#{File.basename(script)}")
@livery.setup_on(self)
@livery.preflight(self)
@livery.flight(self)
@livery.postflight(self)
end
def wait_for_sshd

View File

@ -2,8 +2,10 @@ require 'rubygems'
require 'zlib'
require 'archive/tar/minitar'
require 'blimpy/livery/cwd'
module Blimpy
class Livery
module Livery
def self.tarball_directory(directory)
if directory.nil? || !(File.directory? directory)
raise ArgumentError, "The argument '#{directory}' doesn't appear to be a directory"

55
lib/blimpy/livery/base.rb Normal file
View File

@ -0,0 +1,55 @@
module Blimpy
module Livery
class Base
def preflight(*args)
end
def flight(*args)
raise NotImplementedError
end
def postflight(*args)
end
def rsync_excludes
['.git', '.svn', '.blimpy.d']
end
def rsync_command
excludes = rsync_excludes.map { |x| "--exclude=#{x}" }
['rsync',
'-avL',
'-e',
'ssh -o StrictHostKeyChecking=no'] + excludes
end
def sync_to(box)
if can_rsync?
command = rsync_command + ['.', "#{box.username}@#{box.dns}:#{dir_name}/"]
box.run_command(*command)
else
puts "Remote host has no rsync(1), falling back to copying a full tarball over"
tarball = Blimpy::Livery.tarball_directory(livery_root)
box.scp_file(tarball)
# HAXX
basename = File.basename(tarball)
box.ssh_into("tar -zxf #{basename} && cd #{dir_name}")
end
end
def livery_root
Dir.pwd
end
def dir_name
File.basename(livery_root)
end
def setup_on(box)
sync_to(box)
end
end
end
end

29
lib/blimpy/livery/cwd.rb Normal file
View File

@ -0,0 +1,29 @@
require 'blimpy/livery/base'
module Blimpy
module Livery
class CWD < Base
def script
'bootstrap.sh'
end
def preflight(box)
box.scp_file(bootstrap_script, dir_name)
end
def flight(box)
run_sudo = 'sudo'
if box.username == 'root'
run_sudo = ''
end
box.ssh_into("cd #{dir_name} && #{run_sudo} ./#{script}")
end
def bootstrap_script
File.join(livery_root, script)
end
end
end
end

View File

@ -144,5 +144,55 @@ describe Blimpy::Box do
end
end
end
describe '#bootstrap_livery' do
let(:livery) { double('Mock-livery') }
it 'should raise an error if the livery is a symbol (old style)' do
subject.livery = :deprecated
expect {
subject.bootstrap_livery
}.to raise_error(Blimpy::InvalidLiveryException)
end
it 'should invoke the correct livery methods' do
subject.livery = livery
livery.should_receive(:setup_on).with(subject)
livery.should_receive(:preflight).with(subject)
livery.should_receive(:flight).with(subject)
livery.should_receive(:postflight).with(subject)
subject.bootstrap_livery
end
end
describe '#bootstrap' do
context 'when livery is not defined' do
before :each do
subject.livery = nil
end
it 'should not call any of the bootstrap methods' do
subject.should_receive(:wait_for_sshd).never
subject.should_receive(:bootstrap_livery).never
subject.bootstrap
end
end
context 'when a livery is defined' do
before :each do
subject.should_receive(:wait_for_sshd)
subject.should_receive(:bootstrap_livery)
end
context 'as a class object' do
it 'should instantiate the livery' do
subject.livery = Blimpy::Livery::CWD
subject.livery.should_receive(:new)
subject.bootstrap
end
end
end
end
end
end

View File

@ -0,0 +1,21 @@
require 'spec_helper'
require 'blimpy/livery/base'
describe Blimpy::Livery::Base do
describe '#rsync_excludes' do
it { subject.rsync_excludes.should be_instance_of Array }
end
describe '#rsync_command' do
subject { described_class.new.rsync_command }
it { expect(subject.first).to eql('rsync') }
it { should include('--exclude=.git') }
end
describe '#livery_root' do
it { expect(subject.livery_root).to eql(Dir.pwd) }
end
end

View File

@ -0,0 +1,7 @@
require 'spec_helper'
require 'blimpy/livery/cwd'
describe Blimpy::Livery::CWD do
end