sprinkle 0.4.2 → 0.5.0.rc1
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 +8 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +54 -0
- data/README.markdown +178 -166
- data/Rakefile +4 -28
- data/bin/sprinkle +14 -1
- data/lib/sprinkle.rb +5 -1
- data/lib/sprinkle/actors/actors.rb +20 -5
- data/lib/sprinkle/actors/capistrano.rb +62 -36
- data/lib/sprinkle/actors/dummy.rb +127 -0
- data/lib/sprinkle/actors/local.rb +59 -17
- data/lib/sprinkle/actors/ssh.rb +189 -107
- data/lib/sprinkle/actors/vlad.rb +51 -32
- data/lib/sprinkle/configurable.rb +2 -1
- data/lib/sprinkle/deployment.rb +22 -2
- data/lib/sprinkle/errors/pretty_failure.rb +41 -0
- data/lib/sprinkle/errors/remote_command_failure.rb +24 -0
- data/lib/sprinkle/errors/transfer_failure.rb +28 -0
- data/lib/sprinkle/installers/apt.rb +17 -16
- data/lib/sprinkle/installers/binary.rb +23 -8
- data/lib/sprinkle/installers/brew.rb +17 -10
- data/lib/sprinkle/installers/bsd_port.rb +10 -6
- data/lib/sprinkle/installers/deb.rb +3 -10
- data/lib/sprinkle/installers/freebsd_pkg.rb +5 -11
- data/lib/sprinkle/installers/freebsd_portinstall.rb +8 -2
- data/lib/sprinkle/installers/gem.rb +9 -3
- data/lib/sprinkle/installers/group.rb +28 -4
- data/lib/sprinkle/installers/installer.rb +58 -7
- data/lib/sprinkle/installers/mac_port.rb +13 -6
- data/lib/sprinkle/installers/npm.rb +42 -0
- data/lib/sprinkle/installers/openbsd_pkg.rb +4 -11
- data/lib/sprinkle/installers/opensolaris_pkg.rb +7 -13
- data/lib/sprinkle/installers/package_installer.rb +33 -0
- data/lib/sprinkle/installers/pacman.rb +5 -13
- data/lib/sprinkle/installers/pear.rb +40 -0
- data/lib/sprinkle/installers/push_text.rb +18 -5
- data/lib/sprinkle/installers/rake.rb +7 -2
- data/lib/sprinkle/installers/reconnect.rb +29 -0
- data/lib/sprinkle/installers/replace_text.rb +11 -2
- data/lib/sprinkle/installers/rpm.rb +8 -6
- data/lib/sprinkle/installers/runner.rb +41 -16
- data/lib/sprinkle/installers/smart.rb +6 -17
- data/lib/sprinkle/installers/source.rb +22 -10
- data/lib/sprinkle/installers/thor.rb +7 -0
- data/lib/sprinkle/installers/transfer.rb +62 -41
- data/lib/sprinkle/installers/user.rb +34 -4
- data/lib/sprinkle/installers/yum.rb +10 -10
- data/lib/sprinkle/installers/zypper.rb +4 -15
- data/lib/sprinkle/package.rb +81 -98
- data/lib/sprinkle/policy.rb +11 -4
- data/lib/sprinkle/utility/log_recorder.rb +33 -0
- data/lib/sprinkle/verifiers/directory.rb +1 -1
- data/lib/sprinkle/verifiers/executable.rb +1 -1
- data/lib/sprinkle/verifiers/file.rb +11 -2
- data/lib/sprinkle/verifiers/package.rb +2 -14
- data/lib/sprinkle/verifiers/permission.rb +40 -0
- data/lib/sprinkle/verifiers/symlink.rb +2 -2
- data/lib/sprinkle/verifiers/test.rb +21 -0
- data/lib/sprinkle/verify.rb +3 -3
- data/lib/sprinkle/version.rb +3 -0
- data/spec/fixtures/my_file.txt +1 -0
- data/spec/sprinkle/actors/capistrano_spec.rb +16 -3
- data/spec/sprinkle/actors/local_spec.rb +24 -6
- data/spec/sprinkle/actors/ssh_spec.rb +38 -0
- data/spec/sprinkle/installers/apt_spec.rb +23 -2
- data/spec/sprinkle/installers/binary_spec.rb +22 -14
- data/spec/sprinkle/installers/brew_spec.rb +4 -4
- data/spec/sprinkle/installers/installer_spec.rb +36 -7
- data/spec/sprinkle/installers/npm_spec.rb +16 -0
- data/spec/sprinkle/installers/pear_spec.rb +16 -0
- data/spec/sprinkle/installers/push_text_spec.rb +23 -1
- data/spec/sprinkle/installers/rpm_spec.rb +5 -0
- data/spec/sprinkle/installers/runner_spec.rb +27 -11
- data/spec/sprinkle/installers/smart_spec.rb +60 -0
- data/spec/sprinkle/installers/source_spec.rb +4 -4
- data/spec/sprinkle/installers/transfer_spec.rb +31 -16
- data/spec/sprinkle/package_spec.rb +10 -2
- data/spec/sprinkle/policy_spec.rb +6 -0
- data/spec/sprinkle/verify_spec.rb +18 -4
- data/sprinkle.gemspec +22 -158
- metadata +178 -96
- data/TODO +0 -56
- data/VERSION +0 -1
- data/lib/sprinkle/verifiers/apt.rb +0 -21
- data/lib/sprinkle/verifiers/brew.rb +0 -21
- data/lib/sprinkle/verifiers/rpm.rb +0 -21
- data/lib/sprinkle/verifiers/users_groups.rb +0 -33
@@ -13,25 +13,14 @@ module Sprinkle
|
|
13
13
|
# zypper 'magic_beans'
|
14
14
|
# end
|
15
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:
|
16
|
+
# You may also specify multiple packages as an argument list or array:
|
23
17
|
#
|
24
18
|
# package :magic_beans do
|
25
19
|
# zypper "magic_beans", "magic_sauce"
|
26
20
|
# end
|
27
|
-
class Zypper <
|
28
|
-
|
29
|
-
|
30
|
-
def initialize(parent, *packages, &block) #:nodoc:
|
31
|
-
packages.flatten!
|
32
|
-
super parent, &block
|
33
|
-
@packages = packages
|
34
|
-
end
|
21
|
+
class Zypper < PackageInstaller
|
22
|
+
|
23
|
+
auto_api
|
35
24
|
|
36
25
|
protected
|
37
26
|
|
data/lib/sprinkle/package.rb
CHANGED
@@ -106,128 +106,84 @@ module Sprinkle
|
|
106
106
|
end
|
107
107
|
|
108
108
|
class Package #:nodoc:
|
109
|
-
include ArbitraryOptions
|
110
|
-
attr_accessor :name, :provides, :installers, :
|
109
|
+
# include ArbitraryOptions
|
110
|
+
attr_accessor :name, :provides, :installers, :verifications
|
111
|
+
attr_accessor :args, :opts
|
111
112
|
|
112
113
|
def initialize(name, metadata = {}, &block)
|
113
114
|
raise 'No package name supplied' unless name
|
114
115
|
|
115
116
|
@name = name
|
117
|
+
@metadata = metadata
|
116
118
|
@provides = metadata[:provides]
|
117
119
|
@dependencies = []
|
118
120
|
@recommends = []
|
119
121
|
@optional = []
|
120
122
|
@verifications = []
|
121
123
|
@installers = []
|
124
|
+
@block = block
|
125
|
+
# this should probably not be done twice
|
122
126
|
self.instance_eval &block
|
123
127
|
end
|
124
|
-
def add_user(username, options={}, &block)
|
125
|
-
@installers << Sprinkle::Installers::User.new(self, username, options, &block)
|
126
|
-
end
|
127
|
-
|
128
|
-
def add_group(group, options={}, &block)
|
129
|
-
@installers << Sprinkle::Installers::Group.new(self, group, options, &block)
|
130
|
-
end
|
131
|
-
|
132
|
-
def freebsd_pkg(*names, &block)
|
133
|
-
@installers << Sprinkle::Installers::FreebsdPkg.new(self, *names, &block)
|
134
|
-
end
|
135
128
|
|
136
|
-
def
|
137
|
-
@
|
138
|
-
end
|
139
|
-
|
140
|
-
def openbsd_pkg(*names, &block)
|
141
|
-
@installers << Sprinkle::Installers::OpenbsdPkg.new(self, *names, &block)
|
129
|
+
def description(s=nil)
|
130
|
+
s ? @description = s : @description
|
142
131
|
end
|
143
132
|
|
144
|
-
def
|
145
|
-
@
|
133
|
+
def version(s=nil)
|
134
|
+
s ? @version = s : @version
|
146
135
|
end
|
147
136
|
|
148
|
-
def
|
149
|
-
|
137
|
+
def instance(*args)
|
138
|
+
p=Package.new(name, @metadata) {}
|
139
|
+
p.opts = args.extract_options!
|
140
|
+
p.args = args
|
141
|
+
p.instance_variable_set("@block", @block)
|
142
|
+
p.instance_eval &@block
|
143
|
+
p
|
150
144
|
end
|
151
145
|
|
152
|
-
def
|
153
|
-
@
|
154
|
-
end
|
155
|
-
|
156
|
-
def apt(*names, &block)
|
157
|
-
@installers << Sprinkle::Installers::Apt.new(self, *names, &block)
|
158
|
-
end
|
159
|
-
|
160
|
-
def deb(*names, &block)
|
161
|
-
@installers << Sprinkle::Installers::Deb.new(self, *names, &block)
|
162
|
-
end
|
163
|
-
|
164
|
-
def rpm(*names, &block)
|
165
|
-
@installers << Sprinkle::Installers::Rpm.new(self, *names, &block)
|
166
|
-
end
|
167
|
-
|
168
|
-
def yum(*names, &block)
|
169
|
-
@installers << Sprinkle::Installers::Yum.new(self, *names, &block)
|
170
|
-
end
|
171
|
-
|
172
|
-
def zypper(*names, &block)
|
173
|
-
@installers << Sprinkle::Installers::Zypper.new(self, *names, &block)
|
146
|
+
def sudo?
|
147
|
+
@use_sudo
|
174
148
|
end
|
175
149
|
|
176
|
-
def
|
177
|
-
@
|
150
|
+
def use_sudo(flag=true)
|
151
|
+
@use_sudo = flag
|
178
152
|
end
|
179
|
-
|
180
|
-
def
|
181
|
-
@
|
182
|
-
@installers << Sprinkle::Installers::Gem.new(self, name, options, &block)
|
183
|
-
end
|
184
|
-
|
185
|
-
def source(source, options = {}, &block)
|
186
|
-
@recommends << :build_essential # Ubuntu/Debian
|
187
|
-
@installers << Sprinkle::Installers::Source.new(self, source, options, &block)
|
153
|
+
|
154
|
+
def args
|
155
|
+
@args || []
|
188
156
|
end
|
189
157
|
|
190
|
-
def
|
191
|
-
@
|
158
|
+
def opts
|
159
|
+
@opts || {}
|
192
160
|
end
|
193
161
|
|
194
|
-
|
195
|
-
@installers << Sprinkle::Installers::Rake.new(self, name, options, &block)
|
196
|
-
end
|
197
|
-
|
198
|
-
def thor(name, options = {}, &block)
|
199
|
-
@installers << Sprinkle::Installers::Thor.new(self, name, options, &block)
|
200
|
-
end
|
201
|
-
|
202
|
-
def noop(&block)
|
203
|
-
@installers << Sprinkle::Installers::Runner.new(self, "echo noop", &block)
|
162
|
+
class ContextError < StandardError #:nodoc:
|
204
163
|
end
|
205
164
|
|
206
|
-
def
|
207
|
-
|
208
|
-
end
|
209
|
-
|
210
|
-
def replace_text(regex, text, path, options={}, &block)
|
211
|
-
@installers << Sprinkle::Installers::ReplaceText.new(self, regex, text, path, options, &block)
|
165
|
+
def get(x)
|
166
|
+
raise ContextError, "Cannot call get inside a package, must be inside an Installer block"
|
212
167
|
end
|
213
168
|
|
214
|
-
def
|
215
|
-
|
169
|
+
def noop(&block)
|
170
|
+
install Sprinkle::Installers::Runner.new(self, "echo noop", &block)
|
216
171
|
end
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
172
|
+
|
173
|
+
# meta installer
|
174
|
+
# TODO - fix to be atomic
|
175
|
+
def push_file(file, options ={}, &block)
|
176
|
+
raise "need content" unless options[:content]
|
177
|
+
runner "#{"sudo " if sudo?}rm -f #{file}"
|
178
|
+
push_text options[:content], file, options, &block
|
179
|
+
end
|
180
|
+
|
222
181
|
def verify(description = '', &block)
|
223
182
|
@verifications << Sprinkle::Verify.new(self, description, &block)
|
224
183
|
end
|
225
|
-
|
226
|
-
def pacman(*names, &block)
|
227
|
-
@installers << Sprinkle::Installers::Pacman.new(self, *names, &block)
|
228
|
-
end
|
229
184
|
|
230
185
|
def process(deployment, roles)
|
186
|
+
logger.info " * #{name}"
|
231
187
|
return if meta_package?
|
232
188
|
|
233
189
|
# Run a pre-test to see if the software is already installed. If so,
|
@@ -236,7 +192,7 @@ module Sprinkle
|
|
236
192
|
begin
|
237
193
|
process_verifications(deployment, roles, true)
|
238
194
|
|
239
|
-
logger.info "-->
|
195
|
+
logger.info " --> already installed for roles: #{roles}"
|
240
196
|
return
|
241
197
|
rescue Sprinkle::VerificationFailed => e
|
242
198
|
# Continue
|
@@ -249,15 +205,16 @@ module Sprinkle
|
|
249
205
|
end
|
250
206
|
|
251
207
|
process_verifications(deployment, roles)
|
208
|
+
logger.info " --> INSTALLED for roles: #{roles}"
|
252
209
|
end
|
253
210
|
|
254
211
|
def process_verifications(deployment, roles, pre = false)
|
255
212
|
return if @verifications.blank?
|
256
213
|
|
257
214
|
if pre
|
258
|
-
logger.
|
215
|
+
logger.debug "--> Checking if #{self.name} is already installed for roles: #{roles}"
|
259
216
|
else
|
260
|
-
logger.
|
217
|
+
logger.debug "--> Verifying #{self.name} was properly installed for roles: #{roles}"
|
261
218
|
end
|
262
219
|
|
263
220
|
@verifications.each do |v|
|
@@ -265,46 +222,61 @@ module Sprinkle
|
|
265
222
|
v.process(roles)
|
266
223
|
end
|
267
224
|
end
|
268
|
-
|
225
|
+
|
226
|
+
def dependencies
|
227
|
+
@dependencies.map {|a,b| a }
|
228
|
+
end
|
229
|
+
|
269
230
|
def requires(*packages)
|
270
|
-
|
271
|
-
|
231
|
+
opts = packages.extract_options!
|
232
|
+
packages.each do |pack|
|
233
|
+
@dependencies << [pack, opts]
|
234
|
+
end
|
272
235
|
end
|
273
236
|
|
274
237
|
def recommends(*packages)
|
275
|
-
|
276
|
-
|
238
|
+
opts = packages.extract_options!
|
239
|
+
packages.each do |pack|
|
240
|
+
@recommends << [pack, opts]
|
241
|
+
end
|
242
|
+
@recommends.map {|a,b| a }
|
277
243
|
end
|
278
244
|
|
279
245
|
def optional(*packages)
|
280
|
-
|
281
|
-
|
246
|
+
opts = packages.extract_options!
|
247
|
+
packages.each do |pack|
|
248
|
+
@optional << [pack, opts]
|
249
|
+
end
|
250
|
+
@optional.map {|a,b| a }
|
282
251
|
end
|
283
252
|
|
284
253
|
def tree(depth = 1, &block)
|
285
254
|
packages = []
|
286
255
|
|
287
|
-
@recommends.each do |dep|
|
256
|
+
@recommends.each do |dep, config|
|
288
257
|
package = PACKAGES[dep]
|
289
258
|
next unless package # skip missing recommended packages as they're allowed to not exist
|
259
|
+
package=package.instance(config)
|
290
260
|
block.call(self, package, depth) if block
|
291
261
|
packages << package.tree(depth + 1, &block)
|
292
262
|
end
|
293
263
|
|
294
|
-
@dependencies.each do |dep|
|
264
|
+
@dependencies.each do |dep, config|
|
295
265
|
package = PACKAGES[dep]
|
296
266
|
package = select_package(dep, package) if package.is_a? Array
|
297
267
|
|
298
268
|
raise "Package definition not found for key: #{dep}" unless package
|
269
|
+
package = package.instance(config)
|
299
270
|
block.call(self, package, depth) if block
|
300
271
|
packages << package.tree(depth + 1, &block)
|
301
272
|
end
|
302
273
|
|
303
274
|
packages << self
|
304
275
|
|
305
|
-
@optional.each do |dep|
|
276
|
+
@optional.each do |dep, config|
|
306
277
|
package = PACKAGES[dep]
|
307
278
|
next unless package # skip missing optional packages as they're allow to not exist
|
279
|
+
package = package.instance(config)
|
308
280
|
block.call(self, package, depth) if block
|
309
281
|
packages << package.tree(depth + 1, &block)
|
310
282
|
end
|
@@ -313,8 +285,19 @@ module Sprinkle
|
|
313
285
|
end
|
314
286
|
|
315
287
|
def to_s; @name; end
|
288
|
+
|
289
|
+
protected
|
290
|
+
|
291
|
+
def install(i)
|
292
|
+
@installers << i
|
293
|
+
i
|
294
|
+
end
|
316
295
|
|
317
296
|
private
|
297
|
+
|
298
|
+
def cloud_info(message)
|
299
|
+
logger.info(message) if Sprinkle::OPTIONS[:cloud] or logger.debug?
|
300
|
+
end
|
318
301
|
|
319
302
|
def select_package(name, packages)
|
320
303
|
if packages.size <= 1
|
data/lib/sprinkle/policy.rb
CHANGED
@@ -51,7 +51,7 @@ module Sprinkle
|
|
51
51
|
end
|
52
52
|
|
53
53
|
class Policy #:nodoc:
|
54
|
-
attr_reader :name, :
|
54
|
+
attr_reader :name, :roles
|
55
55
|
|
56
56
|
def initialize(name, metadata = {}, &block)
|
57
57
|
raise 'No name provided' unless name
|
@@ -63,23 +63,30 @@ module Sprinkle
|
|
63
63
|
self.instance_eval(&block)
|
64
64
|
end
|
65
65
|
|
66
|
-
def requires(package, options = {})
|
67
|
-
|
66
|
+
# def requires(package, options = {})
|
67
|
+
def requires(package, *args)
|
68
|
+
@packages << [package, args]
|
68
69
|
end
|
70
|
+
|
71
|
+
def packages; @packages.map {|x| x.first }; end
|
69
72
|
|
70
73
|
def to_s; name; end
|
71
74
|
|
72
75
|
def process(deployment)
|
73
76
|
all = []
|
77
|
+
|
78
|
+
logger.info "[#{name}]"
|
74
79
|
|
75
80
|
cloud_info "--> Cloud hierarchy for policy #{@name}"
|
76
81
|
|
77
|
-
@packages.each do |p|
|
82
|
+
@packages.each do |p, args|
|
78
83
|
cloud_info "\nPolicy #{@name} requires package #{p}"
|
79
84
|
|
80
85
|
package = Sprinkle::Package::PACKAGES[p]
|
81
86
|
raise "Package definition not found for key: #{p}" unless package
|
82
87
|
package = select_package(p, package) if package.is_a? Array # handle virtual package selection
|
88
|
+
# get an instance of the package and pass our config options
|
89
|
+
package = package.instance(*args)
|
83
90
|
|
84
91
|
tree = package.tree do |parent, child, depth|
|
85
92
|
indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Utility
|
3
|
+
class LogRecorder #:nodoc:
|
4
|
+
|
5
|
+
attr_accessor :err, :out, :command, :code
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
reset
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(stream, data)
|
12
|
+
case stream
|
13
|
+
when :err then @err << data
|
14
|
+
when :out then @out << data
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# hash suitable to pass into a pretty failure details hash
|
19
|
+
def hash
|
20
|
+
{:error => err, :stdout => out, :command => command, :code => code}
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset(cmd=nil)
|
24
|
+
@command=cmd
|
25
|
+
@code=nil
|
26
|
+
@err=""
|
27
|
+
@out=""
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -26,7 +26,7 @@ module Sprinkle
|
|
26
26
|
# Be smart: If the path includes a forward slash, we're checking
|
27
27
|
# an absolute path. Otherwise, we're checking a global executable
|
28
28
|
if path.include?('/')
|
29
|
-
|
29
|
+
test "-x #{path}"
|
30
30
|
else
|
31
31
|
@commands << "[ -n \"`echo \\`which #{path}\\``\" ]"
|
32
32
|
end
|
@@ -15,7 +15,15 @@ module Sprinkle
|
|
15
15
|
|
16
16
|
# Checks to make sure <tt>path</tt> is a file on the remote server.
|
17
17
|
def has_file(path)
|
18
|
-
|
18
|
+
test "-f #{path}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def no_file(path)
|
22
|
+
test "! -f #{path}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def md5_of_file(path, md5)
|
26
|
+
test "\"`md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\""
|
19
27
|
end
|
20
28
|
|
21
29
|
def file_contains(path, text)
|
@@ -26,7 +34,8 @@ module Sprinkle
|
|
26
34
|
end
|
27
35
|
def matches_local(localfile, remotefile, mode=nil)
|
28
36
|
raise "Couldn't find local file #{localfile}" unless ::File.exists?(localfile)
|
29
|
-
|
37
|
+
require 'digest/md5'
|
38
|
+
local = Digest::MD5.hexdigest(::File.read(localfile))
|
30
39
|
@commands << %{[ "X$(md5sum #{remotefile}|cut -d\\ -f 1)" = "X#{local}" ]}
|
31
40
|
end
|
32
41
|
end
|
@@ -4,20 +4,8 @@ module Sprinkle
|
|
4
4
|
Sprinkle::Verify.register(Sprinkle::Verifiers::Package)
|
5
5
|
|
6
6
|
def has_package(*packages)
|
7
|
-
|
8
|
-
|
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
|
7
|
+
puts "has_package and has_packages are depreciated"
|
8
|
+
raise "please use has_yum and friends instead"
|
21
9
|
end
|
22
10
|
|
23
11
|
alias_method :has_packages, :has_package
|