sprinkle 0.7.2 → 0.7.3

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