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