jsierles-sprinkle 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CREDITS +19 -0
- data/History.txt +4 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +87 -0
- data/README.txt +238 -0
- data/Rakefile +4 -0
- data/bin/sprinkle +86 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/examples/packages/build_essential.rb +9 -0
- data/examples/packages/databases/mysql.rb +13 -0
- data/examples/packages/databases/sqlite3.rb +16 -0
- data/examples/packages/phusion.rb +55 -0
- data/examples/packages/ruby/rails.rb +9 -0
- data/examples/packages/ruby/ruby.rb +17 -0
- data/examples/packages/ruby/rubygems.rb +17 -0
- data/examples/packages/scm/git.rb +11 -0
- data/examples/packages/scm/subversion.rb +4 -0
- data/examples/packages/servers/apache.rb +15 -0
- data/examples/rails/README +15 -0
- data/examples/rails/deploy.rb +2 -0
- data/examples/rails/packages/database.rb +9 -0
- data/examples/rails/packages/essential.rb +9 -0
- data/examples/rails/packages/rails.rb +28 -0
- data/examples/rails/packages/scm.rb +11 -0
- data/examples/rails/packages/search.rb +11 -0
- data/examples/rails/packages/server.rb +28 -0
- data/examples/rails/rails.rb +73 -0
- data/examples/sprinkle/sprinkle.rb +38 -0
- data/lib/sprinkle.rb +32 -0
- data/lib/sprinkle/actors/actors.rb +17 -0
- data/lib/sprinkle/actors/capistrano.rb +117 -0
- data/lib/sprinkle/actors/local.rb +26 -0
- data/lib/sprinkle/actors/ssh.rb +81 -0
- data/lib/sprinkle/actors/vlad.rb +65 -0
- data/lib/sprinkle/configurable.rb +31 -0
- data/lib/sprinkle/deployment.rb +73 -0
- data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
- data/lib/sprinkle/extensions/array.rb +5 -0
- data/lib/sprinkle/extensions/blank_slate.rb +5 -0
- data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
- data/lib/sprinkle/extensions/string.rb +10 -0
- data/lib/sprinkle/extensions/symbol.rb +7 -0
- data/lib/sprinkle/installers/apt.rb +52 -0
- data/lib/sprinkle/installers/deb.rb +38 -0
- data/lib/sprinkle/installers/gem.rb +62 -0
- data/lib/sprinkle/installers/installer.rb +120 -0
- data/lib/sprinkle/installers/rake.rb +37 -0
- data/lib/sprinkle/installers/rpm.rb +37 -0
- data/lib/sprinkle/installers/source.rb +179 -0
- data/lib/sprinkle/installers/yum.rb +37 -0
- data/lib/sprinkle/package.rb +233 -0
- data/lib/sprinkle/policy.rb +125 -0
- data/lib/sprinkle/script.rb +23 -0
- data/lib/sprinkle/verifiers/directory.rb +16 -0
- data/lib/sprinkle/verifiers/executable.rb +36 -0
- data/lib/sprinkle/verifiers/file.rb +20 -0
- data/lib/sprinkle/verifiers/process.rb +21 -0
- data/lib/sprinkle/verifiers/ruby.rb +25 -0
- data/lib/sprinkle/verifiers/symlink.rb +30 -0
- data/lib/sprinkle/verify.rb +114 -0
- data/lib/sprinkle/version.rb +9 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/sprinkle/actors/capistrano_spec.rb +170 -0
- data/spec/sprinkle/actors/local_spec.rb +29 -0
- data/spec/sprinkle/configurable_spec.rb +46 -0
- data/spec/sprinkle/deployment_spec.rb +80 -0
- data/spec/sprinkle/extensions/array_spec.rb +19 -0
- data/spec/sprinkle/extensions/string_spec.rb +21 -0
- data/spec/sprinkle/installers/apt_spec.rb +70 -0
- data/spec/sprinkle/installers/gem_spec.rb +75 -0
- data/spec/sprinkle/installers/installer_spec.rb +151 -0
- data/spec/sprinkle/installers/rake_spec.rb +29 -0
- data/spec/sprinkle/installers/rpm_spec.rb +50 -0
- data/spec/sprinkle/installers/source_spec.rb +331 -0
- data/spec/sprinkle/installers/yum_spec.rb +49 -0
- data/spec/sprinkle/package_spec.rb +422 -0
- data/spec/sprinkle/policy_spec.rb +126 -0
- data/spec/sprinkle/script_spec.rb +51 -0
- data/spec/sprinkle/sprinkle_spec.rb +25 -0
- data/spec/sprinkle/verify_spec.rb +160 -0
- data/sprinkle.gemspec +70 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- metadata +180 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = File Verifier
|
4
|
+
#
|
5
|
+
# Contains a verifier to check the existance of a file.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# verify { has_file '/etc/apache2/apache2.conf' }
|
10
|
+
#
|
11
|
+
module File
|
12
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::File)
|
13
|
+
|
14
|
+
# Checks to make sure <tt>path</tt> is a file on the remote server.
|
15
|
+
def has_file(path)
|
16
|
+
@commands << "test -f #{path}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = Process Verifier
|
4
|
+
#
|
5
|
+
# Contains a verifier to check that a process is running.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# verify { has_process 'httpd' }
|
10
|
+
#
|
11
|
+
module Process
|
12
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Process)
|
13
|
+
|
14
|
+
# Checks to make sure <tt>process</tt> is a process running
|
15
|
+
# on the remote server.
|
16
|
+
def has_process(process)
|
17
|
+
@commands << "ps aux | grep '#{process}' | grep -v grep"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = Ruby Verifiers
|
4
|
+
#
|
5
|
+
# The verifiers in this module are ruby specific.
|
6
|
+
module Ruby
|
7
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Ruby)
|
8
|
+
|
9
|
+
# Checks if ruby can require the <tt>files</tt> given. <tt>rubygems</tt>
|
10
|
+
# is always included first.
|
11
|
+
def ruby_can_load(*files)
|
12
|
+
# Always include rubygems first
|
13
|
+
files = files.unshift('rubygems').collect { |x| "require '#{x}'" }
|
14
|
+
|
15
|
+
@commands << "ruby -e \"#{files.join(';')}\""
|
16
|
+
end
|
17
|
+
|
18
|
+
# Checks if a gem exists by calling "sudo gem list" and grepping against it.
|
19
|
+
def has_gem(name, version=nil)
|
20
|
+
version = version.nil? ? '' : version.gsub('.', '\.')
|
21
|
+
@commands << "sudo gem list | grep -e '^#{name} (.*#{version}.*)$'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = Symlink Verifier
|
4
|
+
#
|
5
|
+
# Contains a verifier to check the existance of a symbolic link.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# First, checking for the existence of a symlink:
|
10
|
+
#
|
11
|
+
# verify { has_symlink '/usr/special/secret/pointer' }
|
12
|
+
#
|
13
|
+
# Second, checking that the symlink points to a specific place:
|
14
|
+
#
|
15
|
+
# verify { has_symlink '/usr/special/secret/pointer', '/usr/local/realfile' }
|
16
|
+
module Symlink
|
17
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Symlink)
|
18
|
+
|
19
|
+
# Checks that <tt>symlink</tt> is a symbolic link. If <tt>file</tt> is
|
20
|
+
# given, it checks that <tt>symlink</tt> points to <tt>file</tt>
|
21
|
+
def has_symlink(symlink, file = nil)
|
22
|
+
if file.nil?
|
23
|
+
@commands << "test -L #{symlink}"
|
24
|
+
else
|
25
|
+
@commands << "test '#{file}' = `readlink #{symlink}`"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
# = Verification Methods
|
3
|
+
#
|
4
|
+
# As documented in Sprinkle::Package, you may define a block on a package
|
5
|
+
# which verifies that a package was installed correctly. If this verification
|
6
|
+
# block fails, Sprinkle will stop the script gracefully, raising the error.
|
7
|
+
#
|
8
|
+
# In addition to checking post install if it was successfully, verification
|
9
|
+
# blocks are also ran before an install to see if a package is <em>already</em>
|
10
|
+
# installed. If this is the case, the package is skipped and Sprinkle continues
|
11
|
+
# with the next package. This behavior can be overriden by setting the -f flag on
|
12
|
+
# the sprinkle script or setting Sprinkle::OPTIONS[:force] to true if you're
|
13
|
+
# using sprinkle programmatically.
|
14
|
+
#
|
15
|
+
# == An Example
|
16
|
+
#
|
17
|
+
# The following verifies that rails was installed correctly be checking to see
|
18
|
+
# if the 'rails' command is available on the command line:
|
19
|
+
#
|
20
|
+
# package :rails do
|
21
|
+
# gem 'rails'
|
22
|
+
#
|
23
|
+
# verify do
|
24
|
+
# has_executable 'rails'
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# == Available Verifiers
|
29
|
+
#
|
30
|
+
# There are a variety of available methods for use in the verification block.
|
31
|
+
# The standard methods are defined in the Sprinkle::Verifiers module, so see
|
32
|
+
# their corresponding documentation.
|
33
|
+
#
|
34
|
+
# == Custom Verifiers
|
35
|
+
#
|
36
|
+
# If you feel that the built-in verifiers do not offer a certain aspect of
|
37
|
+
# verification which you need, you may create your own verifier! Simply wrap
|
38
|
+
# any method in a module which you want to use:
|
39
|
+
#
|
40
|
+
# module MagicBeansVerifier
|
41
|
+
# def has_magic_beans(sauce)
|
42
|
+
# @commands << '[ -z "`echo $' + sauce + '`"]'
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# The method can append as many commands as it wishes to the @commands array.
|
47
|
+
# These commands will be run on the remote server and <b>MUST</b> give an
|
48
|
+
# exit status of 0 if successful or other if unsuccessful.
|
49
|
+
#
|
50
|
+
# To register your verifier, call the register method on Sprinkle::Verify:
|
51
|
+
#
|
52
|
+
# Sprinle::Verify.register(MagicBeansVerifier)
|
53
|
+
#
|
54
|
+
# And now you may use it like any other verifier:
|
55
|
+
#
|
56
|
+
# package :magic_beans do
|
57
|
+
# gem 'magic_beans'
|
58
|
+
#
|
59
|
+
# verify { has_magic_beans('ranch') }
|
60
|
+
# end
|
61
|
+
class Verify
|
62
|
+
include Sprinkle::Configurable
|
63
|
+
attr_accessor :package, :description, :commands #:nodoc:
|
64
|
+
|
65
|
+
class <<self
|
66
|
+
# Register a verification module
|
67
|
+
def register(new_module)
|
68
|
+
class_eval { include new_module }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(package, description = '', &block) #:nodoc:
|
73
|
+
raise 'Verify requires a block.' unless block
|
74
|
+
|
75
|
+
@package = package
|
76
|
+
@description = description
|
77
|
+
@commands = []
|
78
|
+
@options ||= {}
|
79
|
+
@options[:padding] = 4
|
80
|
+
|
81
|
+
self.instance_eval(&block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def process(roles, pre = false) #:nodoc:
|
85
|
+
assert_delivery
|
86
|
+
|
87
|
+
description = @description.empty? ? @package.name : @description
|
88
|
+
|
89
|
+
if logger.debug?
|
90
|
+
logger.debug "#{@package.name}#{description} verification sequence: #{@commands.join('; ')} for roles: #{roles}\n"
|
91
|
+
end
|
92
|
+
|
93
|
+
unless Sprinkle::OPTIONS[:testing]
|
94
|
+
logger.info "#{" " * @options[:padding]}--> Verifying #{description}..."
|
95
|
+
|
96
|
+
unless @delivery.process(@package.name, @commands, roles, true)
|
97
|
+
# Verification failed, halt sprinkling gracefully.
|
98
|
+
raise Sprinkle::VerificationFailed.new(@package, description)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class VerificationFailed < Exception #:nodoc:
|
105
|
+
attr_accessor :package, :description
|
106
|
+
|
107
|
+
def initialize(package, description)
|
108
|
+
super("Verifying #{package.name}#{description} failed.")
|
109
|
+
|
110
|
+
@package = package
|
111
|
+
@description = description
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
+
require 'sprinkle'
|
11
|
+
|
12
|
+
module Kernel
|
13
|
+
def logger
|
14
|
+
@@__log_file__ ||= StringIO.new
|
15
|
+
@@__log__ = ActiveSupport::BufferedLogger.new @@__log_file__
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Sprinkle::Actors::Capistrano do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@recipes = 'deploy'
|
7
|
+
@cap = ::Capistrano::Configuration.new
|
8
|
+
::Capistrano::Configuration.stub!(:new).and_return(@cap)
|
9
|
+
@cap.stub!(:load).and_return
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_cap(&block)
|
13
|
+
Sprinkle::Actors::Capistrano.new &block
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'when created' do
|
17
|
+
|
18
|
+
it 'should create a new capistrano object' do
|
19
|
+
::Capistrano::Configuration.should_receive(:new).and_return(@cap)
|
20
|
+
create_cap
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'when verbose' do
|
24
|
+
|
25
|
+
before do
|
26
|
+
Sprinkle::OPTIONS[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should set verbose logging on the capistrano object' do
|
30
|
+
@cap = create_cap
|
31
|
+
@cap.config.logger.level.should == ::Capistrano::Logger::INFO
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'when not verbose' do
|
37
|
+
|
38
|
+
before do
|
39
|
+
Sprinkle::OPTIONS[:verbose] = false
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should set quiet logging on the capistrano object' do
|
43
|
+
@cap = create_cap
|
44
|
+
@cap.config.logger.level.should == ::Capistrano::Logger::IMPORTANT
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'with a block' do
|
50
|
+
|
51
|
+
before do
|
52
|
+
@actor = create_cap do
|
53
|
+
recipes 'cool gear' # default is deploy
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should evaluate the block against the actor instance' do
|
58
|
+
@actor.loaded_recipes.should include('cool gear')
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'without a block' do
|
64
|
+
|
65
|
+
it 'should automatically load the default capistrano configuration' do
|
66
|
+
@cap.should_receive(:load).with('deploy').and_return
|
67
|
+
end
|
68
|
+
|
69
|
+
after do
|
70
|
+
@actor = create_cap
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'recipes' do
|
78
|
+
|
79
|
+
it 'should add the recipe location to an internal store' do
|
80
|
+
@cap = create_cap do
|
81
|
+
recipes 'deploy'
|
82
|
+
end
|
83
|
+
@cap.loaded_recipes.should == [ @recipes ]
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should load the given recipe' do
|
87
|
+
@cap.should_receive(:load).with(@recipes).and_return
|
88
|
+
create_cap
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'processing commands' do
|
94
|
+
|
95
|
+
before do
|
96
|
+
@commands = %w( op1 op2 )
|
97
|
+
@roles = %w( app )
|
98
|
+
@name = 'name'
|
99
|
+
|
100
|
+
@cap = create_cap do; recipes 'deploy'; end
|
101
|
+
@cap.stub!(:run).and_return
|
102
|
+
|
103
|
+
@testing_errors = false
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should dynamically create a capistrano task containing the commands' do
|
107
|
+
@cap.config.should_receive(:task).and_return
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should invoke capistrano task after creation' do
|
111
|
+
@cap.should_receive(:run).with(@name).and_return
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should raise capistrano errors when suppressing parameter is not set' do
|
115
|
+
@testing_errors = true
|
116
|
+
|
117
|
+
@cap.should_receive(:run).and_raise(::Capistrano::CommandError)
|
118
|
+
lambda { @cap.process @name, @commands, @roles }.should raise_error(::Capistrano::CommandError)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should not raise errors and instead return false when suppressing parameter is set' do
|
122
|
+
@testing_errors = true
|
123
|
+
|
124
|
+
@cap.should_receive(:run).and_raise(::Capistrano::CommandError)
|
125
|
+
|
126
|
+
value = nil
|
127
|
+
lambda { value = @cap.process(@name, @commands, @roles, true) }.should_not raise_error(::Capistrano::CommandError)
|
128
|
+
|
129
|
+
value.should_not be
|
130
|
+
end
|
131
|
+
|
132
|
+
after do
|
133
|
+
@cap.process @name, @commands, @roles unless @testing_errors
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'generated task' do
|
139
|
+
|
140
|
+
before do
|
141
|
+
@commands = %w( op1 op2 )
|
142
|
+
@roles = %w( app )
|
143
|
+
@name = 'name'
|
144
|
+
|
145
|
+
@cap = create_cap do; recipes 'deploy'; end
|
146
|
+
@cap.config.stub!(:fetch).and_return(:sudo)
|
147
|
+
@cap.config.stub!(:invoke_command).and_return
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should use sudo to invoke commands when so configured' do
|
151
|
+
@cap.config.should_receive(:fetch).with(:run_method, :sudo).and_return(:sudo)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should run the supplied commands' do
|
155
|
+
@cap.config.should_receive(:invoke_command).with('op1', :via => :sudo).ordered.and_return
|
156
|
+
@cap.config.should_receive(:invoke_command).with('op2', :via => :sudo).ordered.and_return
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should be applicable for the supplied roles' do
|
160
|
+
@cap.stub!(:run).and_return
|
161
|
+
@cap.config.should_receive(:task).with(:install_name, :roles => @roles).and_return
|
162
|
+
end
|
163
|
+
|
164
|
+
after do
|
165
|
+
@cap.process @name, @commands, @roles
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|