sprinkle 0.7.1.1 → 0.7.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/.tm_properties +7 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +46 -4
- data/Rakefile +38 -1
- data/examples/rails/packages/database.rb +7 -0
- data/examples/rails/templates/mysql.cnf.erb +3 -0
- data/lib/sprinkle.rb +8 -13
- data/lib/sprinkle/actors/actor.rb +17 -17
- data/lib/sprinkle/actors/capistrano.rb +3 -3
- data/lib/sprinkle/actors/local.rb +10 -6
- data/lib/sprinkle/actors/ssh.rb +8 -8
- data/lib/sprinkle/actors/vlad.rb +7 -7
- data/lib/sprinkle/core.rb +16 -0
- data/lib/sprinkle/deployment.rb +8 -6
- data/lib/sprinkle/errors/pretty_failure.rb +1 -1
- data/lib/sprinkle/errors/template_error.rb +1 -1
- data/lib/sprinkle/installers/brew.rb +0 -2
- data/lib/sprinkle/installers/deb.rb +6 -2
- data/lib/sprinkle/installers/file.rb +38 -39
- data/lib/sprinkle/installers/freebsd_pkg.rb +4 -0
- data/lib/sprinkle/installers/group.rb +11 -12
- data/lib/sprinkle/installers/install_package.rb +5 -5
- data/lib/sprinkle/installers/openbsd_pkg.rb +5 -1
- data/lib/sprinkle/installers/opensolaris_pkg.rb +5 -1
- data/lib/sprinkle/installers/package_installer.rb +7 -3
- data/lib/sprinkle/installers/pacman.rb +4 -0
- data/lib/sprinkle/installers/push_text.rb +1 -1
- data/lib/sprinkle/installers/rake.rb +14 -6
- data/lib/sprinkle/installers/rpm.rb +5 -0
- data/lib/sprinkle/installers/runner.rb +3 -2
- data/lib/sprinkle/installers/thor.rb +14 -15
- data/lib/sprinkle/installers/transfer.rb +0 -1
- data/lib/sprinkle/installers/user.rb +2 -2
- data/lib/sprinkle/installers/yum.rb +9 -8
- data/lib/sprinkle/installers/zypper.rb +5 -1
- data/lib/sprinkle/package.rb +31 -8
- data/lib/sprinkle/package/chooser.rb +1 -1
- data/lib/sprinkle/package/package_repository.rb +1 -1
- data/lib/sprinkle/package/rendering.rb +13 -10
- data/lib/sprinkle/policy.rb +71 -74
- data/lib/sprinkle/script.rb +2 -2
- data/lib/sprinkle/utility/log_recorder.rb +1 -1
- data/lib/sprinkle/verifiers/file.rb +17 -1
- data/lib/sprinkle/verifiers/package.rb +2 -2
- data/lib/sprinkle/verify.rb +2 -2
- data/lib/sprinkle/version.rb +1 -1
- data/spec/sprinkle/deployment_spec.rb +5 -3
- data/spec/sprinkle/extensions/rendering_spec.rb +29 -14
- data/spec/sprinkle/installers/file_spec.rb +1 -1
- data/spec/sprinkle/installers/installer_spec.rb +1 -1
- data/spec/sprinkle/installers/opensolaris_pkg_spec.rb +0 -4
- data/spec/sprinkle/installers/transfer_spec.rb +1 -1
- data/spec/sprinkle/package_spec.rb +31 -0
- data/spec/sprinkle/policy_spec.rb +5 -5
- data/spec/sprinkle/verify_spec.rb +0 -7
- data/spec/templates/locals.erb +1 -0
- data/spec/templates/test.erb +1 -0
- data/templates/test.erb +1 -0
- metadata +10 -4
- data/lib/sprinkle/verifiers/directory.rb +0 -16
- data/lib/sprinkle/verifiers/symlink.rb +0 -30
@@ -1,6 +1,6 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
# The user installer
|
3
|
+
# The user installer add users. You may pass :flags as an option.
|
4
4
|
#
|
5
5
|
# == Example Usage
|
6
6
|
#
|
@@ -8,7 +8,7 @@ module Sprinkle
|
|
8
8
|
# add_user 'admin', :flags => "--disabled-password"
|
9
9
|
#
|
10
10
|
# verify do
|
11
|
-
# has_user 'admin', :in_group
|
11
|
+
# has_user 'admin', :in_group => "root"
|
12
12
|
# end
|
13
13
|
# end
|
14
14
|
|
@@ -7,14 +7,11 @@ module Sprinkle
|
|
7
7
|
# Installing the magic_beans RPM via Yum. Its all the craze these days.
|
8
8
|
#
|
9
9
|
# package :magic_beans do
|
10
|
-
# yum 'magic_beans'
|
11
|
-
# verify
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# package :magic_beans do
|
17
|
-
# yum "magic_beans", "magic_sauce"
|
10
|
+
# yum 'magic_beans', 'magic_corn'
|
11
|
+
# verify do
|
12
|
+
# has_yum 'magic_beans'
|
13
|
+
# has_yum 'magic_corn'
|
14
|
+
# end
|
18
15
|
# end
|
19
16
|
#
|
20
17
|
# To install a specific version just add that version after the name
|
@@ -24,6 +21,10 @@ module Sprinkle
|
|
24
21
|
# end
|
25
22
|
class Yum < PackageInstaller
|
26
23
|
|
24
|
+
##
|
25
|
+
# installs the RPM packages passed
|
26
|
+
# :method: yum
|
27
|
+
# :call-seq: yum(*packages)
|
27
28
|
auto_api
|
28
29
|
|
29
30
|
verify_api do
|
data/lib/sprinkle/package.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
module Sprinkle
|
2
3
|
# = Packages
|
3
4
|
#
|
@@ -36,6 +37,20 @@ module Sprinkle
|
|
36
37
|
# provision the server with Ruby to make sure the requirements are met.
|
37
38
|
# In turn, if ruby has requirements, it installs those first, and so on.
|
38
39
|
#
|
40
|
+
# == Defaults
|
41
|
+
#
|
42
|
+
# Packages can be given defaults.
|
43
|
+
# These default options are available as a hash in opts.
|
44
|
+
#
|
45
|
+
# package :deploy_user do
|
46
|
+
# defaults :username => 'deploy'
|
47
|
+
# add_user opts[:username]
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Options given when requiring a package are merged over the defaults
|
51
|
+
#
|
52
|
+
# requires :deploy_user, :username => 'deployer'
|
53
|
+
#
|
39
54
|
# == Verifications
|
40
55
|
#
|
41
56
|
# Most of the time its important to know whether the software you're
|
@@ -142,7 +157,7 @@ module Sprinkle
|
|
142
157
|
|
143
158
|
def instance(*args)
|
144
159
|
p=Package.new(name, @metadata) {}
|
145
|
-
p.opts = args.extract_options!
|
160
|
+
p.opts = defaults.merge(args.extract_options!)
|
146
161
|
p.args = args
|
147
162
|
p.instance_variable_set("@block", @block)
|
148
163
|
p.instance_eval &@block
|
@@ -156,13 +171,17 @@ module Sprinkle
|
|
156
171
|
def use_sudo(flag=true)
|
157
172
|
@use_sudo = flag
|
158
173
|
end
|
159
|
-
|
174
|
+
|
175
|
+
def defaults(s=nil)
|
176
|
+
s ? @defaults = s : @defaults ||= Hash.new
|
177
|
+
end
|
178
|
+
|
160
179
|
def args
|
161
|
-
@args
|
180
|
+
@args ||= []
|
162
181
|
end
|
163
182
|
|
164
183
|
def opts
|
165
|
-
@opts
|
184
|
+
@opts ||= defaults.clone
|
166
185
|
end
|
167
186
|
|
168
187
|
class ContextError < StandardError #:nodoc:
|
@@ -172,9 +191,9 @@ module Sprinkle
|
|
172
191
|
raise ContextError, "Cannot call get inside a package, must be inside an Installer block"
|
173
192
|
end
|
174
193
|
|
175
|
-
#
|
176
|
-
# TODO - fix to be atomic
|
194
|
+
# TODO - remove
|
177
195
|
def push_file(file, options ={}, &block)
|
196
|
+
ActiveSupport::Deprecation.warn("push_file is depreciated and will be removed in v0.9. Use the new `file` installer instead.")
|
178
197
|
raise "need content" unless options[:content]
|
179
198
|
runner "#{"sudo " if sudo?}rm -f #{file}"
|
180
199
|
push_text options[:content], file, options, &block
|
@@ -182,11 +201,15 @@ module Sprinkle
|
|
182
201
|
|
183
202
|
def verify(description = '', &block)
|
184
203
|
@verifications << Sprinkle::Verify.new(self, description, &block)
|
185
|
-
end
|
204
|
+
end
|
186
205
|
|
187
206
|
def process(deployment, roles)
|
188
207
|
logger.info " * #{name}"
|
189
208
|
return if meta_package?
|
209
|
+
opts.each_with_index do |(k, v), index|
|
210
|
+
branch = (index == opts.size - 1) ? "└" : "├"
|
211
|
+
logger.debug " #{branch}─ #{k}: #{v}"
|
212
|
+
end
|
190
213
|
|
191
214
|
# Run a pre-test to see if the software is already installed. If so,
|
192
215
|
# we can skip it, unless we have the force option turned on!
|
@@ -224,7 +247,7 @@ module Sprinkle
|
|
224
247
|
v.process(roles)
|
225
248
|
end
|
226
249
|
end
|
227
|
-
|
250
|
+
|
228
251
|
def requires(*packages)
|
229
252
|
add_dependencies packages, :dependencies
|
230
253
|
end
|
@@ -4,24 +4,27 @@ require 'digest/md5'
|
|
4
4
|
module Sprinkle::Package
|
5
5
|
module Rendering
|
6
6
|
extend ActiveSupport::Concern
|
7
|
-
|
7
|
+
|
8
8
|
included do
|
9
9
|
self.send :include, Helpers
|
10
10
|
end
|
11
|
-
|
12
|
-
def template(src,
|
11
|
+
|
12
|
+
def template(src, context=binding)
|
13
13
|
eruby = Erubis::Eruby.new(src)
|
14
|
-
output = eruby.result(
|
14
|
+
output = eruby.result(context)
|
15
15
|
rescue Object => e
|
16
|
-
raise Sprinkle::Errors::TemplateError.new(e, src,
|
16
|
+
raise Sprinkle::Errors::TemplateError.new(e, src, context)
|
17
17
|
end
|
18
18
|
|
19
|
-
def render(
|
20
|
-
contents=File.read(expand_filename(
|
21
|
-
template(contents)
|
19
|
+
def render(filename, context=binding)
|
20
|
+
contents=File.read(expand_filename(filename))
|
21
|
+
template(contents, context)
|
22
22
|
end
|
23
23
|
|
24
|
+
# Helper methods can be called from inside your package and
|
25
|
+
# verification code
|
24
26
|
module Helpers
|
27
|
+
# return the md5 of a string (as a hex string)
|
25
28
|
def md5(s)
|
26
29
|
Digest::MD5.hexdigest(s)
|
27
30
|
end
|
@@ -29,13 +32,13 @@ module Sprinkle::Package
|
|
29
32
|
|
30
33
|
private
|
31
34
|
|
32
|
-
def expand_filename(n)
|
35
|
+
def expand_filename(n) #:nodoc:
|
33
36
|
return n.to_s if n.to_s.starts_with? "/"
|
34
37
|
["./templates/#{n}","./templates/#{n}.erb"].each do |f|
|
35
38
|
return f if File.exist?(f)
|
36
39
|
end
|
37
40
|
raise "template file not found"
|
38
41
|
end
|
39
|
-
|
42
|
+
|
40
43
|
end
|
41
44
|
end
|
data/lib/sprinkle/policy.rb
CHANGED
@@ -1,20 +1,31 @@
|
|
1
1
|
require 'highline/import'
|
2
2
|
|
3
3
|
module Sprinkle
|
4
|
+
class NoMatchingServersError < StandardError #:nodoc:
|
5
|
+
def initialize(name, roles)
|
6
|
+
@name = name
|
7
|
+
@roles = roles
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"Policy #{@name} is to be installed on #{@roles.inspect} but no server has such a role."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
4
15
|
# = Policies
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Policies define a set of packages which are required for a certain
|
7
18
|
# role (app, database, etc.). All policies defined will be run and all
|
8
19
|
# packages required by the policy will be installed. So whereas defining
|
9
20
|
# a Sprinkle::Package merely defines it, defining a Sprinkle::Policy
|
10
21
|
# actually causes those packages to install.
|
11
22
|
#
|
12
|
-
# ==
|
23
|
+
# == Example
|
13
24
|
#
|
14
25
|
# policy :blog, :roles => :app do
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
26
|
+
# requires :webserver
|
27
|
+
# requires :database
|
28
|
+
# requires :rails
|
18
29
|
# end
|
19
30
|
#
|
20
31
|
# This says that for the blog on the app role, it requires certain
|
@@ -38,91 +49,77 @@ module Sprinkle
|
|
38
49
|
# no software will be installed twice, so you may require a webserver on
|
39
50
|
# multiple packages within the same role without having to wait for
|
40
51
|
# that package to install repeatedly.
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
class Policy
|
53
|
+
attr_reader :name
|
54
|
+
# roles for which a policy should be installed [required]
|
55
|
+
attr_reader :roles
|
56
|
+
|
57
|
+
# creates a new policy,
|
58
|
+
# although policies are typically not created directly but
|
59
|
+
# rather via the Core#policy helper.
|
60
|
+
def initialize(name, metadata = {}, &block)
|
61
|
+
raise 'No name provided' unless name
|
62
|
+
raise 'No roles provided' unless metadata[:roles]
|
63
|
+
|
64
|
+
@name = name
|
65
|
+
@roles = metadata[:roles]
|
66
|
+
@packages = []
|
67
|
+
self.instance_eval(&block)
|
51
68
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@roles = roles
|
57
|
-
end
|
58
|
-
|
59
|
-
def to_s
|
60
|
-
"Policy #{@name} is to be installed on #{@roles.inspect} but no server has such a role."
|
61
|
-
end
|
69
|
+
|
70
|
+
# tell a policy which packages are required
|
71
|
+
def requires(package, opts={})
|
72
|
+
@packages << [package, opts]
|
62
73
|
end
|
63
74
|
|
64
|
-
|
65
|
-
|
75
|
+
def packages #:nodoc:
|
76
|
+
@packages.map {|x| x.first }
|
77
|
+
end
|
66
78
|
|
67
|
-
|
68
|
-
|
69
|
-
raise 'No roles provided' unless metadata[:roles]
|
79
|
+
def to_s #:nodoc:
|
80
|
+
name; end
|
70
81
|
|
71
|
-
|
72
|
-
|
73
|
-
@packages = []
|
74
|
-
self.instance_eval(&block)
|
75
|
-
end
|
76
|
-
|
77
|
-
def requires(package, opts={})
|
78
|
-
@packages << [package, opts]
|
79
|
-
end
|
82
|
+
def process(deployment) #:nodoc:
|
83
|
+
raise NoMatchingServersError.new(@name, @roles) unless deployment.style.servers_for_role?(@roles)
|
80
84
|
|
81
|
-
|
85
|
+
all = []
|
86
|
+
|
87
|
+
logger.info "[#{name}]"
|
82
88
|
|
83
|
-
|
89
|
+
cloud_info "--> Cloud hierarchy for policy #{@name}"
|
84
90
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
all = []
|
89
|
-
|
90
|
-
logger.info "[#{name}]"
|
91
|
+
@packages.each do |p, args|
|
92
|
+
cloud_info " * requires package #{p}"
|
91
93
|
|
92
|
-
|
94
|
+
package = Sprinkle::Package::PACKAGES.find_all(p, args)
|
95
|
+
raise "Package definition not found for key: #{p}" unless package
|
96
|
+
package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
|
97
|
+
# get an instance of the package and pass our config options
|
98
|
+
package = package.instance(*args)
|
93
99
|
|
94
|
-
|
95
|
-
|
100
|
+
tree = package.tree do |parent, child, depth|
|
101
|
+
indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
|
102
|
+
end
|
96
103
|
|
97
|
-
|
98
|
-
|
99
|
-
package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
|
100
|
-
# get an instance of the package and pass our config options
|
101
|
-
package = package.instance(*args)
|
104
|
+
all << tree
|
105
|
+
end
|
102
106
|
|
103
|
-
|
104
|
-
|
105
|
-
|
107
|
+
normalize(all).each do |package|
|
108
|
+
package.process(deployment, @roles)
|
109
|
+
end
|
110
|
+
end
|
106
111
|
|
107
|
-
|
108
|
-
end
|
112
|
+
private
|
109
113
|
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
def normalize(all, &block)
|
115
|
+
all = all.flatten.uniq {|x| [x.name, x.version] }
|
116
|
+
cloud_info "--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}\n"
|
117
|
+
all
|
113
118
|
end
|
114
119
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
logger.info(message) if Sprinkle::OPTIONS[:cloud] or logger.debug?
|
119
|
-
end
|
120
|
+
def cloud_info(message)
|
121
|
+
logger.info(message) if Sprinkle::OPTIONS[:cloud] or logger.debug?
|
122
|
+
end
|
120
123
|
|
121
|
-
def normalize(all, &block)
|
122
|
-
all = all.flatten.uniq {|x| [x.name, x.version] }
|
123
|
-
cloud_info "--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}\n"
|
124
|
-
all.each &block
|
125
|
-
end
|
126
|
-
end
|
127
124
|
end
|
128
125
|
end
|
data/lib/sprinkle/script.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Sprinkle
|
2
|
-
# =
|
2
|
+
# = Scripting
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# Script gives you a way to programatically run a given
|
5
5
|
# sprinkle script.
|
6
6
|
class Script
|
7
7
|
include Sprinkle::Deployment
|
@@ -12,11 +12,27 @@ module Sprinkle
|
|
12
12
|
#
|
13
13
|
module File
|
14
14
|
Sprinkle::Verify.register(Sprinkle::Verifiers::File)
|
15
|
-
|
15
|
+
|
16
|
+
# tests that the file <tt>path</tt> exists
|
16
17
|
def has_file(path)
|
17
18
|
test "-f #{path}"
|
18
19
|
end
|
19
20
|
|
21
|
+
# Tests that the directory <tt>dir</tt> exists.
|
22
|
+
def has_directory(dir)
|
23
|
+
test "-d #{dir}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Checks that <tt>symlink</tt> is a symbolic link. If <tt>file</tt> is
|
27
|
+
# given, it checks that <tt>symlink</tt> points to <tt>file</tt>
|
28
|
+
def has_symlink(symlink, file = nil)
|
29
|
+
if file.nil?
|
30
|
+
test "-L #{symlink}"
|
31
|
+
else
|
32
|
+
test "'#{file}' = `readlink #{symlink}`"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
20
36
|
def no_file(path)
|
21
37
|
test "! -f #{path}"
|
22
38
|
end
|