sprinkle 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|