sprinkle 0.7.2 → 0.7.3

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 CHANGED
@@ -5,4 +5,8 @@ pkg
5
5
  .*.swp
6
6
  coverage/*
7
7
  rdoc
8
- .ruby-version
8
+ .ruby-version
9
+
10
+ work
11
+ config
12
+ tmp
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sprinkle (0.7.1.1)
4
+ sprinkle (0.7.2)
5
5
  activesupport (>= 2.0.2)
6
6
  capistrano (>= 2.5.5)
7
7
  erubis (>= 2.7.0)
data/README.md CHANGED
@@ -4,7 +4,7 @@ Sprinkle is a software provisioning tool you can use to build remote servers wit
4
4
  system has been installed. For example, to install a Rails or Merb stack on a brand new slice directly after
5
5
  its been created.
6
6
 
7
- [![Build Status](https://travis-ci.org/sprinkle-tool/sprinkle.png?branch=master)](https://travis-ci.org/sprinkle-tool/sprinkle)
7
+ [![Build Status](https://travis-ci.org/sprinkle-tool/sprinkle.png?branch=master)](https://travis-ci.org/sprinkle-tool/sprinkle) [![Code Climate](https://codeclimate.com/github/sprinkle-tool/sprinkle.png)](https://codeclimate.com/github/sprinkle-tool/sprinkle/)
8
8
 
9
9
  * `#sprinkle` channel on the Freenode IRC Network
10
10
  * <http://redartisan.com/2008/5/27/sprinkle-intro>
@@ -1,5 +1,6 @@
1
1
  require 'net/ssh/gateway'
2
2
  require 'net/scp'
3
+ require File.dirname(__FILE__) + "/ssh/connection_cache"
3
4
 
4
5
  module Sprinkle
5
6
  module Actors
@@ -43,20 +44,10 @@ module Sprinkle
43
44
  class SSHCommandFailure < StandardError #:nodoc:
44
45
  attr_accessor :details
45
46
  end
46
-
47
- class SSHConnectionCache #:nodoc:
48
- def initialize; @cache={}; end
49
- def start(host, user, opts={})
50
- key="#{host}#{user}#{opts.to_s}"
51
- @cache[key] ||= Net::SSH.start(host,user,opts)
52
- end
53
- end
54
-
55
-
47
+
56
48
  def initialize(options = {}, &block) #:nodoc:
57
49
  @options = options.update(:user => 'root')
58
50
  @roles = {}
59
- @connection_cache = SSHConnectionCache.new
60
51
  self.instance_eval &block if block
61
52
  raise "You must define at least a single role." if @roles.empty?
62
53
  end
@@ -115,24 +106,17 @@ module Sprinkle
115
106
  def sudo_command #:nodoc:
116
107
  "sudo"
117
108
  end
118
-
119
- def setup_gateway #:nodoc:
120
- @gateway ||= Net::SSH::Gateway.new(@options[:gateway], @options[:user]) if @options[:gateway]
121
- end
122
109
 
123
110
  def teardown #:nodoc:
124
- @gateway.shutdown! if @gateway
111
+ connections.shutdown!
125
112
  end
126
113
 
127
- def verify(verifier, roles, opts = {}) #:nodoc:
128
- @verifier = verifier
114
+ def verify(verifier, roles) #:nodoc:
129
115
  # issue all the verification steps in a single SSH command
130
116
  commands=[verifier.commands.join(" && ")]
131
117
  process(verifier.package.name, commands, roles)
132
118
  rescue SSHCommandFailure => e
133
119
  false
134
- ensure
135
- @verifier = nil
136
120
  end
137
121
 
138
122
  def install(installer, roles, opts = {}) #:nodoc:
@@ -144,24 +128,20 @@ module Sprinkle
144
128
  @installer = nil
145
129
  end
146
130
 
147
- protected
131
+ private
148
132
 
149
133
  def raise_error(e) #:nodoc:
150
134
  raise Sprinkle::Errors::RemoteCommandFailure.new(@installer, e.details, e)
151
135
  end
152
136
 
153
- def process(name, commands, roles, opts = {}) #:nodoc:
154
- setup_gateway
155
- r=execute_on_role(commands, roles)
156
- logger.debug green "process returning #{r}"
157
- return r
137
+ def process(name, commands, roles) #:nodoc:
138
+ execute_on_role(commands, roles)
158
139
  end
159
140
 
160
141
  def execute_on_role(commands, role) #:nodoc:
161
142
  hosts = @roles[role]
162
143
  Array(hosts).each do |host|
163
144
  success = execute_on_host(commands, host)
164
- return false unless success
165
145
  end
166
146
  end
167
147
 
@@ -174,33 +154,28 @@ module Sprinkle
174
154
  end
175
155
 
176
156
  def execute_on_host(commands,host) #:nodoc:
177
- session = ssh_session(host)
178
- @log_recorder = Sprinkle::Utility::LogRecorder.new
179
157
  prepare_commands(commands).each do |cmd|
180
- if cmd == :TRANSFER
181
- transfer_to_host(@installer.sourcepath, @installer.destination, session,
182
- :recursive => @installer.options[:recursive])
183
- next
184
- elsif cmd == :RECONNECT
185
- session.close # disconnenct
186
- session = ssh_session(host) # reconnect
187
- next
188
- end
189
- @log_recorder.reset cmd
190
- res = ssh(session, cmd)
191
- if res != 0
192
- fail=SSHCommandFailure.new
193
- fail.details = @log_recorder.hash.merge(:hosts => host)
194
- raise fail
158
+ case cmd
159
+ when :RECONNECT
160
+ reconnect host
161
+ when :TRANSFER
162
+ transfer_to_host(@installer.sourcepath, @installer.destination, host,
163
+ :recursive => @installer.options[:recursive])
164
+ else
165
+ run_command cmd, host
195
166
  end
196
167
  end
197
- true
198
168
  end
199
169
 
200
- def ssh(host, cmd, opts={}) #:nodoc:
201
- session = host.is_a?(Net::SSH::Connection::Session) ? host : ssh_session(host)
170
+ def run_command(cmd,host) #:nodoc:
171
+ @log_recorder= Sprinkle::Utility::LogRecorder.new(cmd)
172
+ session = ssh_session(host)
202
173
  logger.debug "[#{session.host}] ssh: #{cmd}"
203
- channel_runner(session, cmd)
174
+ if channel_runner(session, cmd) != 0
175
+ fail=SSHCommandFailure.new
176
+ fail.details = @log_recorder.hash.merge(:hosts => host)
177
+ raise fail
178
+ end
204
179
  end
205
180
 
206
181
  def channel_runner(session, command) #:nodoc:
@@ -244,7 +219,7 @@ module Sprinkle
244
219
 
245
220
  def transfer_to_host(source, destination, host, opts={}) #:nodoc:
246
221
  logger.debug "upload: #{destination}"
247
- session = host.is_a?(Net::SSH::Connection::Session) ? host : ssh_session(host)
222
+ session = ssh_session(host)
248
223
  scp = Net::SCP.new(session)
249
224
  scp.upload! source, destination, :recursive => opts[:recursive], :chunk_size => 32.kilobytes
250
225
  rescue RuntimeError => e
@@ -256,28 +231,32 @@ module Sprinkle
256
231
  end
257
232
 
258
233
  def ssh_session(host) #:nodoc:
259
- if @gateway
260
- gateway.ssh(host, @options[:user])
261
- else
262
- @connection_cache.start(host, @options[:user],:password => @options[:password], :keys => @options[:keys])
263
- end
264
- end
234
+ connections.start(host, @options[:user], @options.slice(:password, :keys))
235
+ end
236
+
237
+ def reconnect(host) #:nodoc:
238
+ connections.reconnect host
239
+ end
240
+
241
+ def connections #:nodoc:
242
+ @connection_cache ||= SSHConnectionCache.new @options.slice(:gateway, :user)
243
+ end
265
244
 
266
245
  private
267
- def color(code, s)
268
- "\033[%sm%s\033[0m"%[code,s]
246
+ def color(code, text)
247
+ "\033[%sm%s\033[0m"%[code,text]
269
248
  end
270
- def red(s)
271
- color(31, s)
249
+ def red(text)
250
+ color(31, text)
272
251
  end
273
- def yellow(s)
274
- color(33, s)
252
+ def yellow(text)
253
+ color(33, text)
275
254
  end
276
- def green(s)
277
- color(32, s)
255
+ def green(text)
256
+ color(32, text)
278
257
  end
279
- def blue(s)
280
- color(34, s)
258
+ def blue(text)
259
+ color(34, text)
281
260
  end
282
261
  end
283
262
  end
@@ -0,0 +1,26 @@
1
+ module Sprinkle
2
+ module Actors
3
+ class SSHConnectionCache #:nodoc:
4
+ def initialize(options={})
5
+ @cache = {}
6
+ @gateway = Net::SSH::Gateway.new(options[:gateway], options[:user]) if options[:gateway]
7
+ end
8
+ def start(host, user, opts={})
9
+ key="#{host}/#{user}#{opts.to_s}"
10
+ if @gateway
11
+ @cache[key] ||= @gateway.ssh(host, user, opts)
12
+ else
13
+ @cache[key] ||= Net::SSH.start(host, user, opts)
14
+ end
15
+ end
16
+ def reconnect(host)
17
+ @cache.delete_if do |k,v|
18
+ (v.close; true) if k =~ /^#{host}\//
19
+ end
20
+ end
21
+ def shutdown!
22
+ @gateway.shutdown! if @gateway
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Sprinkle
2
+ module Sudo
3
+
4
+ def sudo_cmd
5
+ return "#{@delivery.try(:sudo_command) || "sudo"} " if sudo?
6
+ end
7
+
8
+ def sudo?
9
+ options[:sudo] or package.sudo? or @delivery.try(:sudo?)
10
+ end
11
+
12
+ end
13
+ end
@@ -21,61 +21,62 @@ module Sprinkle
21
21
  #
22
22
  # Should you need to run commands before or after the file transfer (making
23
23
  # directories or changing permissions), you can use the pre/post :install directives.
24
- #
24
+ #
25
25
  # == Rendering templates
26
26
  #
27
- # Use the template render helper to render an ERB template to a remote file (you
27
+ # Use the template render helper to render an ERB template to a remote file (you
28
28
  # can use variables in your templates by setting them as instance variables inside
29
29
  # your package. Templates have access to package methods such as opts, args, etc.
30
30
  #
31
31
  # package :nginx_conf do
32
32
  # @nginx_port = 8080
33
- # file '/etc/nginx.conf',
33
+ # file '/etc/nginx.conf',
34
34
  # :contents => render("nginx.conf")
35
- # # ./templates/nginx.conf.erb or
35
+ # # ./templates/nginx.conf.erb or
36
36
  # # ./templates/nginx.conf should contain the erb template
37
37
  # end
38
38
  class FileInstaller < Installer
39
39
  attr_reader :sourcepath, :destination, :contents #:nodoc:
40
-
40
+
41
41
  api do
42
42
  def file(destination, options = {}, &block) #:nodoc:
43
43
  # options.merge!(:binding => binding())
44
44
  install FileInstaller.new(self, destination, options, &block)
45
45
  end
46
46
  end
47
-
47
+
48
48
  def initialize(parent, destination, options={}, &block) #:nodoc:
49
49
  @destination = destination
50
50
  @contents = options[:content] || options[:contents]
51
51
  raise "need :contents key for file" unless @contents
52
52
  super parent, options, &block
53
-
54
- post_move_if_sudo
55
- setup_source
53
+
56
54
  # setup file attributes
57
55
  owner options[:owner] if options[:owner]
58
56
  mode options[:mode] if options[:mode]
57
+
58
+ post_move_if_sudo
59
+ setup_source
59
60
  end
60
-
61
+
61
62
  def install_commands #:nodoc:
62
63
  :TRANSFER
63
64
  end
64
-
65
+
65
66
  # calls chown own to set the file ownership
66
67
  def owner(owner)
67
68
  @owner = owner
68
69
  post :install, "#{sudo_cmd}chown #{owner} #{@destination}"
69
70
  end
70
-
71
+
71
72
  # calls chmod to set the files permissions
72
73
  def mode(mode)
73
74
  @mode = mode
74
75
  post :install, "#{sudo_cmd}chmod #{mode} #{@destination}"
75
76
  end
76
-
77
+
77
78
  private
78
-
79
+
79
80
  def post_move_if_sudo
80
81
  return unless sudo? # perform the file copy in two steps if we're using sudo
81
82
  final = @destination
@@ -84,14 +85,14 @@ module Sprinkle
84
85
  # a user may have requested
85
86
  post(:install).unshift ["#{sudo_cmd}mv #{@destination} #{final}"]
86
87
  end
87
-
88
+
88
89
  def setup_source
89
90
  file=Tempfile.new(@package.name.to_s)
90
91
  file.print(@contents)
91
92
  file.close
92
93
  @sourcepath = file.path
93
94
  end
94
-
95
+
95
96
  end
96
97
  end
97
98
  end
@@ -51,7 +51,8 @@ module Sprinkle
51
51
  # or post :install. If this is the case, it will be documented on
52
52
  # the installation method's corresponding documentation page.
53
53
  class Installer
54
- include Sprinkle::Attributes
54
+ include Sprinkle::Attributes
55
+ include Sprinkle::Sudo
55
56
 
56
57
  delegate :version, :to => :package
57
58
 
@@ -84,14 +85,6 @@ module Sprinkle
84
85
  end
85
86
  end
86
87
 
87
- def sudo_cmd
88
- return "#{@delivery.try(:sudo_command) || "sudo"} " if sudo?
89
- end
90
-
91
- def sudo?
92
- options[:sudo] or package.sudo? or @delivery.try(:sudo?)
93
- end
94
-
95
88
  def escape_shell_arg(str)
96
89
  str.gsub("'", "'\\\\''").gsub("\n", '\n')
97
90
  end
@@ -15,33 +15,50 @@ module Sprinkle
15
15
  # runner [ "make world", "destroy world" ]
16
16
  # end
17
17
  #
18
+ # Environment variables can be supplied throught the :env option.
19
+ #
20
+ # package :magic_beans do
21
+ # runner "make world", :env => {
22
+ # :PATH => '/this/is/my/path:$PATH'
23
+ # }
24
+ # end
25
+ #
18
26
  class Runner < Installer
19
-
27
+
20
28
  api do
21
29
  def runner(*cmds, &block)
22
30
  options = cmds.extract_options!
23
31
  install Runner.new(self, cmds, options, &block)
24
32
  end
25
-
33
+
26
34
  # runs 'echo noop' on the remote host
27
35
  def noop
28
36
  install Runner.new(self, "echo noop")
29
37
  end
30
38
  end
31
-
39
+
32
40
  attr_accessor :cmds #:nodoc:
33
41
  def initialize(parent, cmds, options = {}, &block) #:nodoc:
34
42
  super parent, options, &block
43
+ @env = options.delete(:env)
35
44
  @cmds = [*cmds].flatten
36
45
  raise "you need to specify a command" if cmds.nil?
37
46
  end
38
-
47
+
39
48
  protected
40
-
49
+
50
+ def env_str #:nodoc:
51
+ @env_str ||= @env.inject("env ") do |s, (k,v)|
52
+ s << "#{k.to_s.upcase}=#{v} "
53
+ end
54
+ end
55
+
41
56
  def install_commands #:nodoc:
42
- sudo? ?
43
- @cmds.map { |cmd| "#{sudo_cmd}#{cmd}"} :
44
- @cmds
57
+ cmds = @env ? @cmds.map { |cmd| "#{env_str}#{cmd}"} : @cmds
58
+
59
+ sudo? ?
60
+ cmds.map { |cmd| "#{sudo_cmd}#{cmd}"} :
61
+ cmds
45
62
  end
46
63
  end
47
64
  end
@@ -102,7 +102,8 @@ module Sprinkle
102
102
  end
103
103
 
104
104
  multi_attributes :enable, :disable, :with, :without, :option,
105
- :custom_install, :configure_command, :build_command, :install_command
105
+ :custom_install
106
+ attributes :configure_command, :build_command, :install_command
106
107
 
107
108
  def install_sequence #:nodoc:
108
109
  prepare + download + extract + configure + build + install
@@ -18,7 +18,6 @@ module Sprinkle
18
18
  # package :spec do
19
19
  # thor 'spec', :file => "/var/setup/Thorfile"
20
20
  # end
21
-
22
21
  class Thor < Rake
23
22
 
24
23
  api do
@@ -11,7 +11,6 @@ module Sprinkle
11
11
  # has_user 'admin', :in_group => "root"
12
12
  # end
13
13
  # end
14
-
15
14
  class User < Installer
16
15
 
17
16
  api do
@@ -68,8 +68,8 @@ module Sprinkle
68
68
  end
69
69
 
70
70
  # tell a policy which packages are required
71
- def requires(package, opts={})
72
- @packages << [package, opts]
71
+ def requires(package, *args)
72
+ @packages << [package, args]
73
73
  end
74
74
 
75
75
  def packages #:nodoc:
@@ -91,7 +91,8 @@ module Sprinkle
91
91
  @packages.each do |p, args|
92
92
  cloud_info " * requires package #{p}"
93
93
 
94
- package = Sprinkle::Package::PACKAGES.find_all(p, args)
94
+ opts = args.clone.extract_options!
95
+ package = Sprinkle::Package::PACKAGES.find_all(p, opts)
95
96
  raise "Package definition not found for key: #{p}" unless package
96
97
  package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
97
98
  # get an instance of the package and pass our config options
@@ -4,8 +4,8 @@ module Sprinkle
4
4
 
5
5
  attr_accessor :err, :out, :command, :code
6
6
 
7
- def initialize
8
- reset
7
+ def initialize(cmd=nil)
8
+ reset(cmd)
9
9
  end
10
10
 
11
11
  def log(stream, data)
@@ -38,7 +38,7 @@ module Sprinkle
38
38
  end
39
39
 
40
40
  def md5_of_file(path, md5)
41
- test "\"`md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\""
41
+ test "\"`#{sudo_cmd}md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\""
42
42
  end
43
43
 
44
44
  def file_contains(path, text)
@@ -55,7 +55,7 @@ module Sprinkle
55
55
  raise "Couldn't find local file #{localfile}" unless ::File.exists?(localfile)
56
56
  require 'digest/md5'
57
57
  local = Digest::MD5.hexdigest(::File.read(localfile))
58
- @commands << %{[ "X$(md5sum #{remotefile}|cut -d\\ -f 1)" = "X#{local}" ]}
58
+ md5_of_file remotefile, local
59
59
  end
60
60
  end
61
61
  end
@@ -20,19 +20,13 @@ module Sprinkle
20
20
  end
21
21
 
22
22
  def belongs_to_user(path, user)
23
- if user.is_a?(Integer)
24
- @commands << "find #{path} -maxdepth 0 -uid #{user} | egrep '.*'"
25
- else
26
- @commands << "find #{path} -maxdepth 0 -user #{user} | egrep '.*'"
27
- end
23
+ arg = user.is_a?(Integer) ? "-uid" : "-user"
24
+ @commands << "find #{path} -maxdepth 0 #{arg} #{user} | egrep '.*'"
28
25
  end
29
26
 
30
27
  def belongs_to_group(path, group)
31
- if group.is_a?(Integer)
32
- @commands << "find #{path} -maxdepth 0 -gid #{group} | egrep '.*'"
33
- else
34
- @commands << "find #{path} -maxdepth 0 -group #{group} | egrep '.*'"
35
- end
28
+ arg = group.is_a?(Integer) ? "-gid" : "-group"
29
+ @commands << "find #{path} -maxdepth 0 #{arg} #{group} | egrep '.*'"
36
30
  end
37
31
 
38
32
  end
@@ -61,7 +61,8 @@ module Sprinkle
61
61
  class Verify
62
62
  include Sprinkle::Attributes
63
63
  include Sprinkle::Package::Rendering::Helpers
64
- attr_accessor :package, :description, :commands #:nodoc:
64
+ include Sprinkle::Sudo
65
+ attr_accessor :package, :description, :commands, :options #:nodoc:
65
66
 
66
67
  delegate :opts, :to => :package
67
68
  delegate :args, :to => :package
@@ -1,3 +1,3 @@
1
1
  module Sprinkle
2
- Version = "0.7.2"
2
+ Version = "0.7.3"
3
3
  end
@@ -7,8 +7,8 @@ describe Sprinkle::Installers::FileInstaller do
7
7
  @package = mock(Sprinkle::Package, :name => 'package', :sudo? => false)
8
8
  @empty = Proc.new { }
9
9
  @delivery = mock(Sprinkle::Deployment, :install => true)
10
- @source = 'source'
11
- @destination = 'destination'
10
+ @source = 'source'
11
+ @destination = 'destination'
12
12
  @contents = "hi"
13
13
  @installer = create_file_installer(@destination, :contents => @contents)
14
14
  @roles = []
@@ -21,7 +21,7 @@ describe Sprinkle::Installers::FileInstaller do
21
21
  def create_file_installer(dest, options={}, &block)
22
22
  i = Sprinkle::Installers::FileInstaller.new(@package, dest, options, &block)
23
23
  i.delivery = @delivery
24
- i
24
+ i
25
25
  end
26
26
 
27
27
  describe 'when created' do
@@ -34,24 +34,65 @@ describe Sprinkle::Installers::FileInstaller do
34
34
  describe 'during installation' do
35
35
 
36
36
  context "setting mode and owner" do
37
- before do
37
+ before do
38
38
  @installer = create_file_installer @destination, :content => @contents do
39
39
  mode "744"
40
40
  owner "root"
41
41
  end
42
42
  @installer_commands = @installer.install_sequence
43
43
  end
44
-
44
+
45
45
  it "should include command to set owner" do
46
46
  @installer_commands.should include("chmod 744 #{@destination}")
47
47
  end
48
-
48
+
49
49
  it "should include command to set mode" do
50
50
  @installer_commands.should include("chown root #{@destination}")
51
51
  end
52
-
52
+
53
+ end
54
+
55
+ context "setting mode and owner with sudo" do
56
+ before do
57
+ @installer = create_file_installer @destination, :content => @contents do
58
+ @options[:sudo]= true
59
+ mode "744"
60
+ owner "root"
61
+ end
62
+ @installer_commands = @installer.install_sequence
63
+ end
64
+
65
+ it "should run commands in correct order" do
66
+ @installer_commands.should == [
67
+ :TRANSFER,
68
+ "sudo mv /tmp/sprinkle_#{@destination} #{@destination}",
69
+ "sudo chmod 744 #{@destination}",
70
+ "sudo chown root #{@destination}"
71
+ ]
72
+ end
73
+ end
74
+
75
+ context "setting mode and owner with sudo as options" do
76
+ before do
77
+ @installer = create_file_installer @destination, :content => @contents,
78
+ :mode => "744", :owner => "root" do
79
+ @options[:sudo]= true
80
+ end
81
+ @installer_commands = @installer.install_sequence
82
+ end
83
+
84
+ it "should run commands in correct order" do
85
+ @installer_commands.should == [
86
+ :TRANSFER,
87
+ "sudo mv /tmp/sprinkle_#{@destination} #{@destination}",
88
+ "sudo chown root #{@destination}",
89
+ "sudo chmod 744 #{@destination}"
90
+ ]
91
+ end
92
+
53
93
  end
54
94
 
95
+
55
96
  context 'single pre/post commands' do
56
97
  before do
57
98
  @installer = create_file_installer @destination, :content => @contents do
@@ -67,7 +108,7 @@ describe Sprinkle::Installers::FileInstaller do
67
108
  end
68
109
 
69
110
  end
70
-
111
+
71
112
  context 'pre/post with sudo' do
72
113
  before do
73
114
  @installer = create_file_installer @destination, :content => @contents do
@@ -80,7 +121,7 @@ describe Sprinkle::Installers::FileInstaller do
80
121
  end
81
122
 
82
123
  it "should call the pre and post install commands around the file transfer" do
83
- @installer_commands.should == ["op1",:TRANSFER,
124
+ @installer_commands.should == ["op1",:TRANSFER,
84
125
  "sudo mv /tmp/sprinkle_destination destination", "op2"]
85
126
  end
86
127
  end
@@ -101,7 +142,7 @@ describe Sprinkle::Installers::FileInstaller do
101
142
 
102
143
  end
103
144
 
104
- after do
145
+ after do
105
146
  @installer.process @roles
106
147
  end
107
148
  end
@@ -2,46 +2,63 @@ require File.expand_path("../../spec_helper", File.dirname(__FILE__))
2
2
 
3
3
  describe Sprinkle::Installers::Runner do
4
4
 
5
- before do
6
- @package = mock(Sprinkle::Package, :name => 'package', :sudo? => false)
7
- end
8
-
9
- def create_runner(*cmds)
10
- options=cmds.extract_options!
11
- Sprinkle::Installers::Runner.new(@package, cmds, options)
12
- end
13
-
14
- describe 'when created' do
15
- it 'should accept a single cmd to run' do
16
- @installer = create_runner 'teste'
17
- @installer.cmds.should == ['teste']
18
- end
19
-
20
- it 'should accept an array of commands to run' do
21
- @installer = create_runner ['teste', 'world']
22
- @installer.cmds.should == ['teste', 'world']
23
- @installer.install_sequence.should == ['teste', 'world']
24
- end
25
- end
26
-
27
- describe 'during installation' do
28
-
29
- it 'should use sudo if specified locally' do
30
- @installer = create_runner 'teste', :sudo => true
31
- @install_commands = @installer.send :install_commands
32
- @install_commands.should == ['sudo teste']
33
- end
34
-
35
- it "should accept multiple commands" do
36
- @installer = create_runner 'teste', 'test2'
37
- @install_commands = @installer.send :install_commands
38
- @install_commands.should == ['teste','test2']
5
+ before do
6
+ @package = mock(Sprinkle::Package, :name => 'package', :sudo? => false)
7
+ end
8
+
9
+ def create_runner(*cmds)
10
+ options=cmds.extract_options!
11
+ Sprinkle::Installers::Runner.new(@package, cmds, options)
12
+ end
13
+
14
+ describe 'when created' do
15
+ it 'should accept a single cmd to run' do
16
+ @installer = create_runner 'teste'
17
+ @installer.cmds.should == ['teste']
18
+ end
19
+
20
+ it 'should accept an array of commands to run' do
21
+ @installer = create_runner ['teste', 'world']
22
+ @installer.cmds.should == ['teste', 'world']
23
+ @installer.install_sequence.should == ['teste', 'world']
39
24
  end
25
+ end
26
+
27
+ describe 'during installation' do
28
+
29
+ it 'should use sudo if specified locally' do
30
+ @installer = create_runner 'teste', :sudo => true
31
+ @install_commands = @installer.send :install_commands
32
+ @install_commands.should == ['sudo teste']
33
+ end
34
+
35
+ it "should accept env options and convert to uppercase" do
36
+ @installer = create_runner 'command1', :env => {
37
+ :z => 'foo',
38
+ :PATH => '/some/path',
39
+ :user => 'deploy',
40
+ :a => 'bar'
41
+ }
42
+ @install_commands = @installer.send :install_commands
43
+ command_parts = @install_commands.first.split(/ /)
40
44
 
41
- it 'should run the given command for all specified packages' do
42
- @installer = create_runner 'teste'
43
- @install_commands = @installer.send :install_commands
44
- @install_commands.should == ['teste']
45
- end
46
- end
45
+ command_parts.shift.should == 'env'
46
+ command_parts.pop.should == 'command1'
47
+
48
+ command_parts.should =~ ['PATH=/some/path', 'USER=deploy', 'Z=foo', 'A=bar']
49
+
50
+ end
51
+
52
+ it "should accept multiple commands" do
53
+ @installer = create_runner 'teste', 'test2'
54
+ @install_commands = @installer.send :install_commands
55
+ @install_commands.should == ['teste','test2']
56
+ end
57
+
58
+ it 'should run the given command for all specified packages' do
59
+ @installer = create_runner 'teste'
60
+ @install_commands = @installer.send :install_commands
61
+ @install_commands.should == ['teste']
62
+ end
63
+ end
47
64
  end
@@ -237,9 +237,9 @@ describe Sprinkle::Installers::Source do
237
237
  end
238
238
 
239
239
  it 'should store the custom commands' do
240
- @installer.options[:configure_command].first.should == './custom-configure'
241
- @installer.options[:build_command].first.should == 'custom-make'
242
- @installer.options[:install_command].first.should == 'custom-make install'
240
+ @installer.options[:configure_command].should == './custom-configure'
241
+ @installer.options[:build_command].should == 'custom-make'
242
+ @installer.options[:install_command].should == 'custom-make install'
243
243
  end
244
244
 
245
245
  it 'should use the custom commands' do
@@ -54,12 +54,34 @@ describe Sprinkle::Verify do
54
54
 
55
55
  # Check for a certain RPM package
56
56
  has_rpm 'ntp'
57
+
58
+ belongs_to_user "/etc/", "me"
59
+ belongs_to_user "/etc/", 2
60
+ belongs_to_group "/etc/", "root"
61
+ belongs_to_group "/etc/", 0
57
62
  end
58
63
  end
59
64
  @verification = @package.verifications[0]
60
- @delivery = mock(Sprinkle::Deployment, :process => true)
65
+ @delivery = mock(Sprinkle::Deployment, :process => true, :sudo_command => "sudo")
61
66
  @verification.delivery = @delivery
62
67
  end
68
+
69
+ describe "with sudo" do
70
+ before do
71
+ @package = package @name do
72
+ use_sudo true
73
+ gem 'nonexistent'
74
+ verify 'moo' do
75
+ md5_of_file "/etc/secret", "123abc"
76
+ end
77
+ end
78
+ @verification = @package.verifications[0]
79
+ @verification.delivery = @delivery
80
+ end
81
+ it "should run sudo when necessary" do
82
+ @verification.commands.should include(%{test "`sudo md5sum /etc/secret | cut -f1 -d' '`" = "123abc"})
83
+ end
84
+ end
63
85
 
64
86
  describe 'when created' do
65
87
  it 'should raise error without a block' do
@@ -68,6 +90,13 @@ describe Sprinkle::Verify do
68
90
  end
69
91
 
70
92
  describe 'with checks' do
93
+ it "should test that a file belongs to a given user or group" do
94
+ @verification.commands.should include("find /etc/ -maxdepth 0 -user me | egrep '.*'")
95
+ @verification.commands.should include("find /etc/ -maxdepth 0 -uid 2 | egrep '.*'")
96
+ @verification.commands.should include("find /etc/ -maxdepth 0 -group root | egrep '.*'")
97
+ @verification.commands.should include("find /etc/ -maxdepth 0 -gid 0 | egrep '.*'")
98
+ end
99
+
71
100
  it 'should do a "test -f" on the has_file check' do
72
101
  @verification.commands.should include('test -f my_file.txt')
73
102
  end
@@ -77,7 +106,7 @@ describe Sprinkle::Verify do
77
106
  end
78
107
 
79
108
  it 'should do a md5sum to see if a file matches local file' do
80
- @verification.commands.should include(%{[ "X$(md5sum my_file.txt|cut -d\\ -f 1)" = "Xed20d984b757ad5291963389fc209864" ]})
109
+ @verification.commands.should include(%{test "`md5sum my_file.txt | cut -f1 -d' '`" = "ed20d984b757ad5291963389fc209864"})
81
110
  end
82
111
 
83
112
  it 'should do a "test -d" on the has_directory check' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprinkle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-06-23 00:00:00.000000000 Z
13
+ date: 2013-06-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -158,9 +158,7 @@ files:
158
158
  - MIT-LICENSE
159
159
  - README.md
160
160
  - Rakefile
161
- - bad.rb
162
161
  - bin/sprinkle
163
- - config/deploy.rb
164
162
  - examples/packages/build_essential.rb
165
163
  - examples/packages/databases/mysql.rb
166
164
  - examples/packages/databases/mysql_source.rb
@@ -183,13 +181,13 @@ files:
183
181
  - examples/rails/rails.rb
184
182
  - examples/rails/templates/mysql.cnf.erb
185
183
  - examples/sprinkle/sprinkle.rb
186
- - inner.rb
187
184
  - lib/sprinkle.rb
188
185
  - lib/sprinkle/actors/actor.rb
189
186
  - lib/sprinkle/actors/capistrano.rb
190
187
  - lib/sprinkle/actors/dummy.rb
191
188
  - lib/sprinkle/actors/local.rb
192
189
  - lib/sprinkle/actors/ssh.rb
190
+ - lib/sprinkle/actors/ssh/connection_cache.rb
193
191
  - lib/sprinkle/actors/vlad.rb
194
192
  - lib/sprinkle/core.rb
195
193
  - lib/sprinkle/deployment.rb
@@ -201,6 +199,7 @@ files:
201
199
  - lib/sprinkle/extensions/attributes.rb
202
200
  - lib/sprinkle/extensions/blank_slate.rb
203
201
  - lib/sprinkle/extensions/string.rb
202
+ - lib/sprinkle/extensions/sudo.rb
204
203
  - lib/sprinkle/extensions/symbol.rb
205
204
  - lib/sprinkle/installers/apt.rb
206
205
  - lib/sprinkle/installers/binary.rb
@@ -299,8 +298,6 @@ files:
299
298
  - spec/templates/test.erb
300
299
  - sprinkle.gemspec
301
300
  - templates/test.erb
302
- - test.rb
303
- - work/inner.rb
304
301
  homepage: https://github.com/sprinkle-tool/sprinkle
305
302
  licenses:
306
303
  - MIT
data/bad.rb DELETED
@@ -1,16 +0,0 @@
1
- package :ubuntu_version do
2
- runner "lsb_release -r"
3
- end
4
-
5
-
6
- policy :myapp, :roles => :app do
7
- requires :ubuntu_version
8
- end
9
-
10
- deployment do
11
- delivery :ssh do
12
- user 'root'
13
- password 'secret'
14
- role :app, 'server'
15
- end
16
- end
data/config/deploy.rb DELETED
@@ -1,25 +0,0 @@
1
- set :application, "set your application name here"
2
- set :repository, "set your repository location here"
3
-
4
- # set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
5
- # Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
6
-
7
- role :web, "pastie.org" # Your HTTP server, Apache/etc
8
- role :app, "pastie.org" # This may be the same as your `Web` server
9
- role :db, "pastie.org", :primary => true # This is where Rails migrations will run
10
- role :db, "pastie.org"
11
-
12
- # if you want to clean up old releases on each deploy uncomment this:
13
- # after "deploy:restart", "deploy:cleanup"
14
-
15
- # if you're still using the script/reaper helper you will need
16
- # these http://github.com/rails/irs_process_scripts
17
-
18
- # If you are using Passenger mod_rails uncomment this:
19
- namespace :deploy do
20
- task :start do ; end
21
- # task :stop do ; end
22
- # task :restart, :roles => :app, :except => { :no_release => true } do
23
- # run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
24
- # end
25
- end
data/inner.rb DELETED
@@ -1,45 +0,0 @@
1
- policy :twice, :roles => :app do
2
- requires :hostname
3
- # requires :db
4
- # requires :web, :name => "bob"
5
- # requires :web, :name => "suzy"
6
- # requires :web, :name => "nick"
7
- end
8
-
9
- package :hostname do
10
- apt "test" do
11
- pre :install do
12
- runner "BEFORE"
13
- runner "BEFORE 2"
14
- end
15
- post :install do
16
- runner "AFTER" do
17
- pre(:install) { runner "before after" }
18
- post(:install) { runner "after after" }
19
- end
20
- end
21
- end
22
- end
23
-
24
- deployment do
25
-
26
- # delivery :dummy do
27
- # role :app, 'beta1.pastie.org'
28
- # role :app, 'beta2.pastie.org'
29
- # end
30
-
31
- # use vlad for deployment
32
- # delivery :ssh do
33
- # role :app, 'beta1.pastie.org'
34
- # user "appz"
35
- # end
36
-
37
- # delivery :capistrano
38
- delivery :capistrano do
39
- role :app, 'beta1.pastie.org'
40
- # role :app, 'beta2.pastie.org'
41
- set :user, "appz"
42
- set :use_sudo, true
43
- end
44
-
45
- end
data/test.rb DELETED
@@ -1,102 +0,0 @@
1
- # package :echo do
2
- # runner "echo hello world"
3
- # end
4
- #
5
- # package :version do
6
- # runner "cat /etc/lsb-release"
7
- # end
8
- #
9
- # policy :once, :roles => :app do
10
- # requires :echo
11
- # requires :version
12
- # end
13
- #
14
- package :db do
15
- # go do
16
- # puts "<eval db>"
17
- # runner "installing the db"
18
- # end
19
- verify do
20
- has_file "/etc/db"
21
- end
22
- # runner "finalized"
23
- end
24
-
25
- package :hostname do
26
- # go do
27
- # # puts "<eval hostname : #{hostname}>"
28
- # runner "echo #{hostname} > /etc/hostname", :sudo => true
29
- # end
30
- # push_text "now", "/etc/stupid_file"
31
- # details "using name: front.pastie.org"
32
-
33
- # runner "echo 'hostname'"
34
- # runner "cat /etc/hostname"
35
-
36
- version "5"
37
-
38
- @what = "secret"
39
- @something = "else"
40
- file "/Users/jgoebel/notnow#{version}", :contents => c=render(:first)
41
- # transfer "<%= @what %>\n<%= @what + something %>", "/Users/jgoebel/notnow2", :render => true,
42
- # :binding => binding
43
-
44
- verify do
45
- has_file "/Users/jgoebel/notnow#{version}"
46
- # md5_of_file "/Users/jgoebel/notnow", md5(c)
47
- end
48
- # verify do
49
- # has_executable "/bin/ccc"
50
- # end
51
- end
52
-
53
- package :web do
54
- requires :db
55
-
56
- # go do
57
- # # puts "<eval web>"
58
- # runner "installing web #{opts[:name]}"
59
- # end
60
- # runner "finalized"
61
-
62
- verify do
63
- # has_file "/etc/web/#{opts[:name]}"
64
- end
65
- end
66
-
67
- policy :twice, :roles => :app do
68
- requires :hostname
69
- # requires :db
70
- # requires :web, :name => "bob"
71
- # requires :web, :name => "suzy"
72
- # requires :web, :name => "nick"
73
- end
74
-
75
- deployment do
76
-
77
- # delivery :dummy do
78
- # role :app, 'beta1.pastie.org'
79
- # role :app, 'beta2.pastie.org'
80
- # end
81
-
82
- delivery :local
83
-
84
- # delivery :vlad do
85
- # script "vlad"
86
- # end
87
-
88
- # use ssh for deployment
89
- # delivery :ssh do
90
- # role :app, 'front.pastie.org'
91
- # user "appz"
92
- # end
93
-
94
- # delivery :capistrano
95
- # delivery :capistrano do
96
- # role :app, 'beta1.pastie.org'
97
- # role :app, 'beta2.pastie.org'
98
- # set :user, "appz"
99
- # set :use_sudo, true
100
- # end
101
-
102
- end
data/work/inner.rb DELETED
@@ -1,24 +0,0 @@
1
- policy :sprinkle, :roles => :app do
2
- requires :sprinkle
3
- end
4
-
5
- package :sprinkle do
6
- i=runner "test" do
7
- # pre(:install) { install Installers::Runner.new(self,"before") }
8
- # pre(:install) { runner "pre" }
9
- # post(:install) { runner "after" }
10
- post(:install) { noop }
11
- end
12
- # puts runner("blah")
13
- # puts i.inspect
14
- runner "next"
15
- end
16
-
17
- deployment do
18
-
19
- # use vlad for deployment
20
- delivery :dummy do
21
- # role :app, 'yourhost.com'
22
- end
23
-
24
- end