sprinkle 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.markdown +6 -5
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/bin/sprinkle +5 -0
- data/lib/sprinkle.rb +7 -1
- data/lib/sprinkle/actors/ssh.rb +71 -17
- data/lib/sprinkle/actors/vlad.rb +11 -6
- data/lib/sprinkle/installers/binary.rb +1 -1
- data/lib/sprinkle/installers/deb.rb +4 -1
- data/lib/sprinkle/installers/freebsd_portinstall.rb +1 -1
- data/lib/sprinkle/installers/install_package.rb +79 -0
- data/lib/sprinkle/installers/push_text.rb +1 -1
- data/lib/sprinkle/installers/replace_text.rb +45 -0
- data/lib/sprinkle/installers/runner.rb +18 -0
- data/lib/sprinkle/installers/smart.rb +29 -0
- data/lib/sprinkle/installers/source.rb +10 -6
- data/lib/sprinkle/installers/transfer.rb +18 -4
- data/lib/sprinkle/installers/user.rb +15 -0
- data/lib/sprinkle/installers/zypper.rb +43 -0
- data/lib/sprinkle/package.rb +15 -0
- data/lib/sprinkle/verifiers/apt.rb +21 -0
- data/lib/sprinkle/verifiers/file.rb +9 -1
- data/lib/sprinkle/verifiers/package.rb +26 -0
- data/lib/sprinkle/verifiers/process.rb +2 -2
- data/lib/sprinkle/verifiers/ruby.rb +2 -2
- data/lib/sprinkle/verify.rb +2 -2
- data/spec/sprinkle/installers/push_text_spec.rb +4 -4
- data/spec/sprinkle/installers/replace_text_spec.rb +45 -0
- data/spec/sprinkle/installers/runner_spec.rb +31 -0
- data/spec/sprinkle/installers/source_spec.rb +8 -8
- data/spec/sprinkle/installers/zypper_spec.rb +49 -0
- data/spec/sprinkle/package_spec.rb +8 -0
- data/spec/sprinkle/verify_spec.rb +37 -38
- metadata +72 -21
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
class Runner < Installer
|
4
|
+
attr_accessor :cmd #:nodoc:
|
5
|
+
|
6
|
+
def initialize(parent, cmd) #:nodoc:
|
7
|
+
super parent
|
8
|
+
@cmd = cmd
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def install_commands #:nodoc:
|
14
|
+
@cmd
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
class Smart < Installer
|
4
|
+
attr_accessor :packages #:nodoc:
|
5
|
+
|
6
|
+
def initialize(parent, packages, &block) #:nodoc:
|
7
|
+
super parent, &block
|
8
|
+
packages = [packages] unless packages.is_a? Array
|
9
|
+
@packages = packages
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def install_commands #:nodoc:
|
15
|
+
"smart install #{@packages.join(' ')} -y 2>&1 | tee -a /var/log/smart-sprinkle"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Sprinkle
|
22
|
+
module Package
|
23
|
+
class Package
|
24
|
+
def smart(*names, &block)
|
25
|
+
@installer = Sprinkle::Installers::Smart.new(self, *names, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -3,8 +3,8 @@ module Sprinkle
|
|
3
3
|
# = Source Package Installer
|
4
4
|
#
|
5
5
|
# The source package installer installs software from source.
|
6
|
-
# It handles downloading, extracting, configuring, building,
|
7
|
-
# and installing software.
|
6
|
+
# It handles downloading, extracting, configuring, building,
|
7
|
+
# and installing software.
|
8
8
|
#
|
9
9
|
# == Configuration Options
|
10
10
|
#
|
@@ -22,7 +22,7 @@ module Sprinkle
|
|
22
22
|
# * <b>configure</b> - Configure is the stage which the ./configure script is run.
|
23
23
|
# * <b>build</b> - Build is the stage in which `make` is called.
|
24
24
|
# * <b>install</b> - Install is the stage which `make install` is called.
|
25
|
-
#
|
25
|
+
#
|
26
26
|
# == Example Usage
|
27
27
|
#
|
28
28
|
# First, a simple package, no configuration:
|
@@ -63,7 +63,7 @@ module Sprinkle
|
|
63
63
|
# end
|
64
64
|
#
|
65
65
|
# As you can see, setting options is as simple as creating a
|
66
|
-
# block and calling the option as a method with the value as
|
66
|
+
# block and calling the option as a method with the value as
|
67
67
|
# its parameter.
|
68
68
|
|
69
69
|
class Source < Installer
|
@@ -97,7 +97,11 @@ module Sprinkle
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def download_commands #:nodoc:
|
100
|
-
|
100
|
+
if File.exist? @source
|
101
|
+
[ "cp #{@source} #{@options[:archives]}/#{archive_name}" ]
|
102
|
+
else
|
103
|
+
[ "wget -cq --directory-prefix='#{@options[:archives]}' #{@source}" ]
|
104
|
+
end
|
101
105
|
end
|
102
106
|
|
103
107
|
def extract_commands #:nodoc:
|
@@ -162,7 +166,7 @@ module Sprinkle
|
|
162
166
|
when /tar$/
|
163
167
|
'tar xf'
|
164
168
|
when /zip$/
|
165
|
-
'unzip'
|
169
|
+
'unzip -o'
|
166
170
|
else
|
167
171
|
raise "Unknown source archive format: #{archive_name}"
|
168
172
|
end
|
@@ -72,7 +72,8 @@ module Sprinkle
|
|
72
72
|
#
|
73
73
|
# If you pass the option :render => true, this tells transfer that the source file
|
74
74
|
# is an ERB template to be rendered locally before being transferred (you can declare
|
75
|
-
# variables in the package scope). When render is true, recursive is turned off.
|
75
|
+
# variables in the package scope). When render is true, recursive is turned off. Note
|
76
|
+
# you can also explicitly pass locals in to render with the :locals option.
|
76
77
|
#
|
77
78
|
# package :nginx_conf do
|
78
79
|
# nginx_port = 8080
|
@@ -118,7 +119,7 @@ module Sprinkle
|
|
118
119
|
|
119
120
|
def render_template_file(path, context, prefix)
|
120
121
|
template = File.read(path)
|
121
|
-
tempfile = render_template(template,
|
122
|
+
tempfile = render_template(template, context, @package.name)
|
122
123
|
tempfile
|
123
124
|
end
|
124
125
|
|
@@ -139,8 +140,21 @@ module Sprinkle
|
|
139
140
|
|
140
141
|
recursive = @options[:recursive]
|
141
142
|
|
142
|
-
if options[:render]
|
143
|
-
|
143
|
+
if options[:render]
|
144
|
+
if options[:locals]
|
145
|
+
context = {}
|
146
|
+
options[:locals].each_pair do |k,v|
|
147
|
+
if v.respond_to?(:call)
|
148
|
+
context[k] = v.call
|
149
|
+
else
|
150
|
+
context[k] = v
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
context = binding()
|
155
|
+
end
|
156
|
+
|
157
|
+
tempfile = render_template_file(@source, context, @package.name)
|
144
158
|
sourcepath = tempfile.path
|
145
159
|
logger.info "Rendering template #{@source} to temporary file #{sourcepath}"
|
146
160
|
recursive = false
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
class User < Installer
|
4
|
+
def initialize(package, username, options, &block)
|
5
|
+
super package, &block
|
6
|
+
@username=username
|
7
|
+
@options =options
|
8
|
+
end
|
9
|
+
protected
|
10
|
+
def install_commands
|
11
|
+
"adduser #{@options[:flags]} #{@username}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Zypper Installer
|
4
|
+
#
|
5
|
+
# Zypper is a command-line interface to ZYpp system management library.
|
6
|
+
# It mostly be used on Suse or OpenSuse.
|
7
|
+
#
|
8
|
+
# == Example Usage
|
9
|
+
#
|
10
|
+
# Installing the magic_beans package via Zypper. Its all the craze these days.
|
11
|
+
#
|
12
|
+
# package :magic_beans do
|
13
|
+
# zypper 'magic_beans'
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# You may also specify multiple packages as an array:
|
17
|
+
#
|
18
|
+
# package :magic_beans do
|
19
|
+
# zypper %w(magic_beans magic_sauce)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# or an argument list:
|
23
|
+
#
|
24
|
+
# package :magic_beans do
|
25
|
+
# zypper "magic_beans", "magic_sauce"
|
26
|
+
# end
|
27
|
+
class Zypper < Installer
|
28
|
+
attr_accessor :packages #:nodoc:
|
29
|
+
|
30
|
+
def initialize(parent, *packages, &block) #:nodoc:
|
31
|
+
packages.flatten!
|
32
|
+
super parent, &block
|
33
|
+
@packages = packages
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def install_commands #:nodoc:
|
39
|
+
"zypper -n install -l -R #{@packages.join(' ')}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/sprinkle/package.rb
CHANGED
@@ -121,6 +121,9 @@ module Sprinkle
|
|
121
121
|
@installers = []
|
122
122
|
self.instance_eval &block
|
123
123
|
end
|
124
|
+
def add_user(username, options={}, &block)
|
125
|
+
@installers<<Sprinkle::Installers::User.new(self, username, options, &block)
|
126
|
+
end
|
124
127
|
|
125
128
|
def freebsd_pkg(*names, &block)
|
126
129
|
@installers << Sprinkle::Installers::FreebsdPkg.new(self, *names, &block)
|
@@ -162,6 +165,10 @@ module Sprinkle
|
|
162
165
|
@installers << Sprinkle::Installers::Yum.new(self, *names, &block)
|
163
166
|
end
|
164
167
|
|
168
|
+
def zypper(*names, &block)
|
169
|
+
@installers << Sprinkle::Installers::Zypper.new(self, *names, &block)
|
170
|
+
end
|
171
|
+
|
165
172
|
def gem(name, options = {}, &block)
|
166
173
|
@recommends << :rubygems
|
167
174
|
@installers << Sprinkle::Installers::Gem.new(self, name, options, &block)
|
@@ -188,10 +195,18 @@ module Sprinkle
|
|
188
195
|
@installers << Sprinkle::Installers::PushText.new(self, text, path, options, &block)
|
189
196
|
end
|
190
197
|
|
198
|
+
def replace_text(regex, text, path, options={}, &block)
|
199
|
+
@installers << Sprinkle::Installers::ReplaceText.new(self, regex, text, path, options, &block)
|
200
|
+
end
|
201
|
+
|
191
202
|
def transfer(source, destination, options = {}, &block)
|
192
203
|
@installers << Sprinkle::Installers::Transfer.new(self, source, destination, options, &block)
|
193
204
|
end
|
194
205
|
|
206
|
+
def runner(cmd)
|
207
|
+
@installers << Sprinkle::Installers::Runner.new(self, cmd)
|
208
|
+
end
|
209
|
+
|
195
210
|
def verify(description = '', &block)
|
196
211
|
@verifications << Sprinkle::Verify.new(self, description, &block)
|
197
212
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
# = Apt package Verifier
|
4
|
+
#
|
5
|
+
# Contains a verifier to check the existance of an Apt package.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# verify { has_apt 'ntp' }
|
10
|
+
#
|
11
|
+
module Apt
|
12
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Apt)
|
13
|
+
|
14
|
+
# Checks to make sure the apt <tt>package</tt> exists on the remote server.
|
15
|
+
def has_apt(package)
|
16
|
+
@commands << "dpkg --status #{package} | grep \"ok installed\""
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -21,6 +21,14 @@ module Sprinkle
|
|
21
21
|
def file_contains(path, text)
|
22
22
|
@commands << "grep '#{text}' #{path}"
|
23
23
|
end
|
24
|
+
def user_present(username)
|
25
|
+
@commands << %Q{grep -q -e \'^#{username}:x\' /etc/passwd && test -d ~#{username}}
|
26
|
+
end
|
27
|
+
def matches_local(localfile, remotefile, mode=nil)
|
28
|
+
raise "Couldn't find local file #{localfile}" unless ::File.exists?(localfile)
|
29
|
+
local = `md5 #{localfile}`.split.last
|
30
|
+
@commands << %{[ "X$(md5sum #{remotefile}|cut -d\\ -f 1)" = "X#{local}" ]}
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
|
-
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Verifiers
|
3
|
+
module Package
|
4
|
+
Sprinkle::Verify.register(Sprinkle::Verifiers::Package)
|
5
|
+
|
6
|
+
def has_package(*packages)
|
7
|
+
if packages.is_a?(Array) && packages.first.is_a?(Array)
|
8
|
+
packages = packages.first
|
9
|
+
else
|
10
|
+
packages = [packages] unless packages.is_a? Array
|
11
|
+
end
|
12
|
+
|
13
|
+
packages.each do |pak|
|
14
|
+
case Sprinkle::Installers::InstallPackage.installer
|
15
|
+
when :yum
|
16
|
+
@commands << "[ -n \"`yum list installed #{pak} 2> /dev/null | egrep -e \\\"#{pak}\\\"`\" ]"
|
17
|
+
else
|
18
|
+
raise "Unknown InstallPackage.installer"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :has_packages, :has_package
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -14,8 +14,8 @@ module Sprinkle
|
|
14
14
|
# Checks to make sure <tt>process</tt> is a process running
|
15
15
|
# on the remote server.
|
16
16
|
def has_process(process)
|
17
|
-
@commands << "ps
|
17
|
+
@commands << "ps -C #{process}"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
@@ -17,8 +17,8 @@ module Sprinkle
|
|
17
17
|
|
18
18
|
# Checks if a gem exists by calling "sudo gem list" and grepping against it.
|
19
19
|
def has_gem(name, version=nil)
|
20
|
-
version = version.nil? ? '' : version
|
21
|
-
@commands << "sudo gem list
|
20
|
+
version = version.nil? ? '' : "--version '#{version}'"
|
21
|
+
@commands << "sudo gem list '#{name}' --installed #{version} > /dev/null"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/sprinkle/verify.rb
CHANGED
@@ -6,7 +6,7 @@ module Sprinkle
|
|
6
6
|
# block fails, Sprinkle will stop the script gracefully, raising the error.
|
7
7
|
#
|
8
8
|
# In addition to checking post install if it was successfully, verification
|
9
|
-
# blocks are also
|
9
|
+
# blocks are also run before an install to see if a package is <em>already</em>
|
10
10
|
# installed. If this is the case, the package is skipped and Sprinkle continues
|
11
11
|
# with the next package. This behavior can be overriden by setting the -f flag on
|
12
12
|
# the sprinkle script or setting Sprinkle::OPTIONS[:force] to true if you're
|
@@ -111,4 +111,4 @@ module Sprinkle
|
|
111
111
|
@description = description
|
112
112
|
end
|
113
113
|
end
|
114
|
-
end
|
114
|
+
end
|
@@ -32,11 +32,11 @@ describe Sprinkle::Installers::PushText do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should invoke the push text installer for all specified packages' do
|
35
|
-
@install_commands.should == %q[echo -e 'another-hair-brained-idea' |tee -a /dev/mind/late-night]
|
35
|
+
@install_commands.should == %q[/bin/echo -e 'another-hair-brained-idea' |tee -a /dev/mind/late-night]
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'should automatically insert pre/post commands for the specified package' do
|
39
|
-
@installer.send(:install_sequence).should == [ 'op1', "echo -e 'another-hair-brained-idea' |tee -a /dev/mind/late-night", 'op2' ]
|
39
|
+
@installer.send(:install_sequence).should == [ 'op1', "/bin/echo -e 'another-hair-brained-idea' |tee -a /dev/mind/late-night", 'op2' ]
|
40
40
|
end
|
41
41
|
|
42
42
|
end
|
@@ -48,7 +48,7 @@ describe Sprinkle::Installers::PushText do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should invoke the push installer with sudo" do
|
51
|
-
@install_commands.should == %q[echo -e 'a special user' |sudo tee -a /dev/mind/the-day-after]
|
51
|
+
@install_commands.should == %q[/bin/echo -e 'a special user' |sudo tee -a /dev/mind/the-day-after]
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -59,7 +59,7 @@ describe Sprinkle::Installers::PushText do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should correctly encode the single quote character" do
|
62
|
-
@install_commands.should == %q[echo -e 'I'\''m a string with a single quote' |tee -a /dev/mind/the-day-after]
|
62
|
+
@install_commands.should == %q[/bin/echo -e 'I'\''m a string with a single quote' |tee -a /dev/mind/the-day-after]
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Sprinkle::Installers::ReplaceText do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@package = mock(Sprinkle::Package, :name => 'package')
|
7
|
+
@options = {:sudo => true}
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_replacement_text(regex, text, path, options={}, &block)
|
11
|
+
Sprinkle::Installers::ReplaceText.new(@package, regex, text, path, options, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'when created' do
|
15
|
+
|
16
|
+
it 'should accept text to replace, replacement, and path' do
|
17
|
+
@installer = create_replacement_text 'text_to_replace', 'new_text', '/etc/example/foo.conf'
|
18
|
+
@installer.regex.should == 'text_to_replace'
|
19
|
+
@installer.text.should == 'new_text'
|
20
|
+
@installer.path.should == '/etc/example/foo.conf'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'during installation' do
|
26
|
+
|
27
|
+
before do
|
28
|
+
@installer = create_replacement_text 'bad option', 'super option', '/etc/brand/new.conf' do
|
29
|
+
pre :install, 'op1'
|
30
|
+
post :install, 'op2'
|
31
|
+
end
|
32
|
+
@install_commands = @installer.send :install_commands
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should invoke the replace text installer for all specified packages' do
|
36
|
+
@install_commands.should == %q[sed -i 's/bad option/super option/g' /etc/brand/new.conf]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should automatically insert pre/post commands for the specified package' do
|
40
|
+
@installer.send(:install_sequence).should == [ 'op1', "sed -i 's/bad option/super option/g' /etc/brand/new.conf", 'op2' ]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Sprinkle::Installers::Runner do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@package = mock(Sprinkle::Package, :name => 'package')
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_runner(cmd)
|
10
|
+
Sprinkle::Installers::Runner.new(@package, cmd)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'when created' do
|
14
|
+
it 'should accept a single cmd to run' do
|
15
|
+
@installer = create_runner 'teste'
|
16
|
+
@installer.cmd.should == 'teste'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'during execution' do
|
21
|
+
|
22
|
+
before do
|
23
|
+
@installer = create_runner 'teste'
|
24
|
+
@install_commands = @installer.send :install_commands
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should run the given command for all specified packages' do
|
28
|
+
@install_commands.should == 'teste'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|