sprinkle 0.2.6 → 0.3.0
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/.gitignore +5 -0
- data/CREDITS +4 -0
- data/Rakefile +50 -4
- data/TODO +56 -0
- data/VERSION +1 -0
- data/bin/sprinkle +4 -0
- data/examples/rails/deploy.rb +1 -1
- data/lib/sprinkle/actors/ssh.rb +6 -2
- data/lib/sprinkle/installers/binary.rb +46 -0
- data/lib/sprinkle/installers/freebsd_portinstall.rb +36 -0
- data/lib/sprinkle/installers/source.rb +3 -2
- data/lib/sprinkle/package.rb +27 -20
- data/lib/sprinkle/verifiers/rpm.rb +21 -0
- data/script/console +8 -0
- data/spec/sprinkle/installers/freebsd_portinstall_spec.rb +42 -0
- data/spec/sprinkle/installers/noop_spec.rb +23 -0
- data/spec/sprinkle/installers/source_spec.rb +26 -0
- data/spec/sprinkle/installers/transfer_spec.rb +98 -0
- data/spec/sprinkle/package_spec.rb +20 -10
- data/spec/sprinkle/sequence_spec.rb +44 -0
- data/spec/sprinkle/verify_spec.rb +7 -0
- metadata +79 -33
- data/History.txt +0 -4
- data/Manifest.txt +0 -111
- data/config/hoe.rb +0 -70
- data/config/requirements.rb +0 -17
- data/lib/sprinkle/version.rb +0 -9
- data/sprinkle.gemspec +0 -73
- data/tasks/deployment.rake +0 -37
- data/tasks/environment.rake +0 -7
- data/tasks/rspec.rake +0 -21
data/.gitignore
ADDED
data/CREDITS
CHANGED
@@ -25,5 +25,9 @@ Justin Pease (http://jit.nuance9.com)
|
|
25
25
|
Tobias Lütke (http://blog.leetsoft.com)
|
26
26
|
Josh Reynolds (http://github.com/jreynolds)
|
27
27
|
Jan Ulbrich (http://www.ulbrich.net)
|
28
|
+
Chris Gaffney (http://github.com/gaffneyc)
|
29
|
+
Maxmpz (http://github.com/maxmpz)
|
30
|
+
Geoff Garside (http://geoffgarside.co.uk/)
|
31
|
+
Oliver Kiessler (http://inceedo.com)
|
28
32
|
|
29
33
|
The transfer installer contains a piece of exception reporting code copied from the Chef library (http://wiki.opscode.com/display/chef/Home)
|
data/Rakefile
CHANGED
@@ -1,4 +1,50 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sprinkle"
|
8
|
+
gem.summary = "Ruby DSL based software provisioning tool"
|
9
|
+
gem.description = "Ruby DSL based software provisioning tool"
|
10
|
+
gem.email = "crafterm@redartisan.com"
|
11
|
+
gem.rubyforge_project = 'sprinkle'
|
12
|
+
gem.homepage = "http://github.com/crafterm/sprinkle"
|
13
|
+
gem.authors = ["Marcus Crafter"]
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
gem.add_dependency('activesupport', '>= 2.0.2')
|
16
|
+
gem.add_dependency('highline', '>= 1.4.0')
|
17
|
+
gem.add_dependency('capistrano', '>= 2.5.5')
|
18
|
+
|
19
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
end
|
31
|
+
|
32
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
33
|
+
spec.libs << 'lib' << 'spec'
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :spec => :check_dependencies
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "sprinkle #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
Version 0.1 plan
|
2
|
+
================
|
3
|
+
|
4
|
+
INSTALLER
|
5
|
+
* Fix up apt so that we can handle it if it asks questions, or fail? Check with Ben
|
6
|
+
* Support alternate gem package sources - DONE
|
7
|
+
* MD5/SHA1 checking on the installation files?
|
8
|
+
|
9
|
+
MISC
|
10
|
+
* Growl support
|
11
|
+
* Do a merb example
|
12
|
+
* Fix up printing of output so that its nice and a bit more like ports - DONE
|
13
|
+
* print ports style output for stages (installing, configuring, etc...)
|
14
|
+
* Add an option to print the hierarchy tree of packages to be installed only - DONE
|
15
|
+
* BlankSlate - active support has one
|
16
|
+
* CREDITS file - DONE
|
17
|
+
* Get #!/usr/bin/env sprinkle working - DONE
|
18
|
+
|
19
|
+
OPERATING SYSTEM
|
20
|
+
* OS abstraction
|
21
|
+
* build essential on Ubuntu only for example
|
22
|
+
|
23
|
+
TESTING
|
24
|
+
* Test on a base system Ubuntu system - DONE
|
25
|
+
* Multiple runs, check system that's partially installed - DONE
|
26
|
+
* Resuming downloads with wget ok - DONE
|
27
|
+
|
28
|
+
ERRORS
|
29
|
+
* Need to think about handling errors nicely
|
30
|
+
* Recovering from an error, and or successive runs of sprinkle
|
31
|
+
* store installed state on the remote server so we can skip installed packages?
|
32
|
+
* what about self healing things later? need to think about it
|
33
|
+
|
34
|
+
DOCUMENTATION
|
35
|
+
* Document the code somewhat, at least review that its all ok
|
36
|
+
* Wiki
|
37
|
+
* Home page somewhere? point to github
|
38
|
+
* Blog post
|
39
|
+
* Screencast - use that cool screenflow tool?
|
40
|
+
|
41
|
+
Post Version 0.1 plan
|
42
|
+
=====================
|
43
|
+
|
44
|
+
CONFIGURATION
|
45
|
+
* Think about it - talk to Lincoln and Ben
|
46
|
+
* Use cap 2.3 send/download file helpers, might be useful somehow for transporting config files
|
47
|
+
|
48
|
+
ACTOR
|
49
|
+
* Investigate a pure net:ssh/gateway delivery mechanism, ie. without cap?
|
50
|
+
* Generate a cap task file as output? not sure if people would be interested in this?
|
51
|
+
* use ruby2ruby to generate the file, nice :)
|
52
|
+
|
53
|
+
MISC
|
54
|
+
* Slicehost API support for creating a slice on the way
|
55
|
+
* active resource
|
56
|
+
* SSH keys, have to deploy them somehow?
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/bin/sprinkle
CHANGED
data/examples/rails/deploy.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
set :user, 'root'
|
2
|
-
role :app, '
|
2
|
+
role :app, 'sprinkle.redartisan.com', :primary => true
|
data/lib/sprinkle/actors/ssh.rb
CHANGED
@@ -22,7 +22,11 @@ module Sprinkle
|
|
22
22
|
def user(user)
|
23
23
|
@options[:user] = user
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
|
+
def password(password)
|
27
|
+
@options[:password] = password
|
28
|
+
end
|
29
|
+
|
26
30
|
def process(name, commands, roles, suppress_and_return_failures = false)
|
27
31
|
return process_with_gateway(name, commands, roles) if gateway_defined?
|
28
32
|
process_direct(name, commands, roles)
|
@@ -71,7 +75,7 @@ module Sprinkle
|
|
71
75
|
execute_on_connection(commands, ssh)
|
72
76
|
end
|
73
77
|
else # direct SSH connection
|
74
|
-
Net::SSH.start(host, @options[:user]) do |ssh|
|
78
|
+
Net::SSH.start(host, @options[:user], :password => @options[:password]) do |ssh|
|
75
79
|
execute_on_connection(commands, ssh)
|
76
80
|
end
|
77
81
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Binary Installer
|
4
|
+
#
|
5
|
+
# binary "http://some.url.com/archive.tar.gz" do
|
6
|
+
# prefix "/home/user/local"
|
7
|
+
# archives "/home/user/sources"
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
class Binary < Installer
|
11
|
+
def initialize(parent, binary_archive, options = {}, &block) #:nodoc:
|
12
|
+
@binary_archive = binary_archive
|
13
|
+
@options = options
|
14
|
+
super parent, options, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare_commands #:nodoc:
|
18
|
+
raise 'No installation area defined' unless @options[:prefix]
|
19
|
+
raise 'No archive download area defined' unless @options[:archives]
|
20
|
+
|
21
|
+
[ "mkdir -p #{@options[:prefix]}",
|
22
|
+
"mkdir -p #{@options[:archives]}" ]
|
23
|
+
end
|
24
|
+
|
25
|
+
def install_commands #:nodoc:
|
26
|
+
commands = [ "bash -c 'wget -cq --directory-prefix=#{@options[:archives]} #{@binary_archive}'" ]
|
27
|
+
commands << "bash -c 'cd #{@options[:prefix]} && #{extract_command} #{@options[:archives]}/#{@binary_archive.split("/").last}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_command(archive_name = @binary_archive.split("/").last)
|
31
|
+
case archive_name
|
32
|
+
when /(tar.gz)|(tgz)$/
|
33
|
+
'tar xzf'
|
34
|
+
when /(tar.bz2)|(tb2)$/
|
35
|
+
'tar xjf'
|
36
|
+
when /tar$/
|
37
|
+
'tar xf'
|
38
|
+
when /zip$/
|
39
|
+
'unzip'
|
40
|
+
else
|
41
|
+
raise "Unknown binary archive format: #{archive_name}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = FreeBSD Portinstall Installer
|
4
|
+
#
|
5
|
+
# The Portinstall installer installs FreeBSD ports.
|
6
|
+
# It uses the ports-mgmt/portupgrade port to install.
|
7
|
+
# Before usage, the ports system must be installed and
|
8
|
+
# read on the target operating system.
|
9
|
+
# It is recommended to use `portsnap fetch extract` to
|
10
|
+
# install the ports system.
|
11
|
+
#
|
12
|
+
# == Example Usage
|
13
|
+
#
|
14
|
+
# Installing the magic_beans port.
|
15
|
+
#
|
16
|
+
# package :magic_beans do
|
17
|
+
# freebsd_portinstall 'magic/magic_beans'
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class FreebsdPortinstall < Installer
|
21
|
+
attr_accessor :port #:nodoc:
|
22
|
+
|
23
|
+
def initialize(parent, port, &block) #:nodoc:
|
24
|
+
super parent, &block
|
25
|
+
@port = port
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def install_commands #:nodoc:
|
31
|
+
"portinstall --batch #{@port}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -111,7 +111,8 @@ module Sprinkle
|
|
111
111
|
|
112
112
|
extras = {
|
113
113
|
:enable => '--enable', :disable => '--disable',
|
114
|
-
:with => '--with', :without => '--without'
|
114
|
+
:with => '--with', :without => '--without',
|
115
|
+
:option => '-',
|
115
116
|
}
|
116
117
|
|
117
118
|
extras.inject(command) { |m, (k, v)| m << create_options(k, v) if options[k]; m }
|
@@ -178,7 +179,7 @@ module Sprinkle
|
|
178
179
|
end
|
179
180
|
|
180
181
|
def base_dir #:nodoc:
|
181
|
-
if archive_name.split('/').last =~ /(.*)\.(tar\.gz|tgz|tar\.bz2|tar|tb2)/
|
182
|
+
if archive_name.split('/').last =~ /(.*)\.(tar\.gz|tgz|tar\.bz2|tar|tb2|zip)/
|
182
183
|
return $1
|
183
184
|
end
|
184
185
|
raise "Unknown base path for source archive: #{@source}, please update code knowledge"
|
data/lib/sprinkle/package.rb
CHANGED
@@ -107,7 +107,7 @@ module Sprinkle
|
|
107
107
|
|
108
108
|
class Package #:nodoc:
|
109
109
|
include ArbitraryOptions
|
110
|
-
attr_accessor :name, :provides, :
|
110
|
+
attr_accessor :name, :provides, :installers, :dependencies, :recommends, :verifications
|
111
111
|
|
112
112
|
def initialize(name, metadata = {}, &block)
|
113
113
|
raise 'No package name supplied' unless name
|
@@ -118,69 +118,74 @@ module Sprinkle
|
|
118
118
|
@recommends = []
|
119
119
|
@optional = []
|
120
120
|
@verifications = []
|
121
|
+
@installers = []
|
121
122
|
self.instance_eval &block
|
122
123
|
end
|
123
124
|
|
124
125
|
def freebsd_pkg(*names, &block)
|
125
|
-
@
|
126
|
+
@installers << Sprinkle::Installers::FreebsdPkg.new(self, *names, &block)
|
126
127
|
end
|
127
128
|
|
128
129
|
def openbsd_pkg(*names, &block)
|
129
|
-
@
|
130
|
+
@installers << Sprinkle::Installers::OpenbsdPkg.new(self, *names, &block)
|
130
131
|
end
|
131
132
|
|
132
133
|
def opensolaris_pkg(*names, &block)
|
133
|
-
@
|
134
|
+
@installers << Sprinkle::Installers::OpensolarisPkg.new(self, *names, &block)
|
134
135
|
end
|
135
136
|
|
136
137
|
def bsd_port(port, &block)
|
137
|
-
@
|
138
|
+
@installers << Sprinkle::Installers::BsdPort.new(self, port, &block)
|
138
139
|
end
|
139
140
|
|
140
141
|
def mac_port(port, &block)
|
141
|
-
@
|
142
|
+
@installers << Sprinkle::Installers::MacPort.new(self, port, &block)
|
142
143
|
end
|
143
144
|
|
144
145
|
def apt(*names, &block)
|
145
|
-
@
|
146
|
+
@installers << Sprinkle::Installers::Apt.new(self, *names, &block)
|
146
147
|
end
|
147
148
|
|
148
149
|
def deb(*names, &block)
|
149
|
-
@
|
150
|
+
@installers << Sprinkle::Installers::Deb.new(self, *names, &block)
|
150
151
|
end
|
151
152
|
|
152
153
|
def rpm(*names, &block)
|
153
|
-
@
|
154
|
+
@installers << Sprinkle::Installers::Rpm.new(self, *names, &block)
|
154
155
|
end
|
155
156
|
|
156
157
|
def yum(*names, &block)
|
157
|
-
@
|
158
|
+
@installers << Sprinkle::Installers::Yum.new(self, *names, &block)
|
158
159
|
end
|
159
160
|
|
160
161
|
def gem(name, options = {}, &block)
|
161
162
|
@recommends << :rubygems
|
162
|
-
@
|
163
|
+
@installers << Sprinkle::Installers::Gem.new(self, name, options, &block)
|
163
164
|
end
|
164
165
|
|
165
166
|
def source(source, options = {}, &block)
|
166
167
|
@recommends << :build_essential # Ubuntu/Debian
|
167
|
-
@
|
168
|
+
@installers << Sprinkle::Installers::Source.new(self, source, options, &block)
|
169
|
+
end
|
170
|
+
|
171
|
+
def binary(source, options = {}, &block)
|
172
|
+
@installers << Sprinkle::Installers::Binary.new(self, source, options, &block)
|
168
173
|
end
|
169
174
|
|
170
175
|
def rake(name, options = {}, &block)
|
171
|
-
@
|
176
|
+
@installers << Sprinkle::Installers::Rake.new(self, name, options, &block)
|
172
177
|
end
|
173
178
|
|
174
179
|
def noop(&block)
|
175
|
-
@
|
180
|
+
@installers << Sprinkle::Installers::Noop.new(self, name, options, &block)
|
176
181
|
end
|
177
182
|
|
178
183
|
def push_text(text, path, options = {}, &block)
|
179
|
-
@
|
184
|
+
@installers << Sprinkle::Installers::PushText.new(self, text, path, options, &block)
|
180
185
|
end
|
181
186
|
|
182
|
-
|
183
|
-
|
187
|
+
def transfer(source, destination, options = {}, &block)
|
188
|
+
@installers << Sprinkle::Installers::Transfer.new(self, source, destination, options, &block)
|
184
189
|
end
|
185
190
|
|
186
191
|
def verify(description = '', &block)
|
@@ -203,8 +208,10 @@ module Sprinkle
|
|
203
208
|
end
|
204
209
|
end
|
205
210
|
|
206
|
-
@installer
|
207
|
-
|
211
|
+
@installers.each do |installer|
|
212
|
+
installer.defaults(deployment)
|
213
|
+
installer.process(roles)
|
214
|
+
end
|
208
215
|
|
209
216
|
process_verifications(deployment, roles)
|
210
217
|
end
|
@@ -291,7 +298,7 @@ module Sprinkle
|
|
291
298
|
end
|
292
299
|
|
293
300
|
def meta_package?
|
294
|
-
@
|
301
|
+
@installers.blank?
|
295
302
|
end
|
296
303
|
end
|
297
304
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = RPM Verifier
|
4
|
+
#
|
5
|
+
# Contains a verifier to check the existance of an RPM package.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# verify { has_rpm 'ntp' }
|
10
|
+
#
|
11
|
+
module Rpm
|
12
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Rpm)
|
13
|
+
|
14
|
+
# Checks to make sure <tt>package</tt> exists in the rpm installed database on the remote server.
|
15
|
+
def has_rpm(package)
|
16
|
+
@commands << "rpm -qa | grep #{package}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/sprinkle.rb'}"
|
7
|
+
puts "Loading sprinkle gem"
|
8
|
+
exec "#{irb} #{libs} --simple-prompt"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Sprinkle::Installers::FreebsdPortinstall do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@package = mock(Sprinkle::Package, :name => 'package')
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_port(ports, &block)
|
10
|
+
Sprinkle::Installers::FreebsdPortinstall.new(@package, ports, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'when created' do
|
14
|
+
|
15
|
+
it 'should accept a single package to install' do
|
16
|
+
@installer = create_port 'lang/ruby'
|
17
|
+
@installer.port.should == 'lang/ruby'
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'during installation' do
|
23
|
+
|
24
|
+
before do
|
25
|
+
@installer = create_port 'lang/ruby' do
|
26
|
+
pre :install, 'op1'
|
27
|
+
post :install, 'op2'
|
28
|
+
end
|
29
|
+
@install_commands = @installer.send :install_commands
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should invoke the port installer for all specified packages' do
|
33
|
+
@install_commands.should =~ /portinstall --batch lang\/ruby/
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should automatically insert pre/post commands for the specified package' do
|
37
|
+
@installer.send(:install_sequence).should == [ 'op1', 'portinstall --batch lang/ruby', 'op2' ]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|