sprinkle 0.3.1 → 0.3.2
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 +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
|