cronicle 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7cdae0546bbdc1bd3e6a5bafd16d9b1f90f67d17
4
- data.tar.gz: 61b267dfbc54560acdd815389696bda3ec5d8fdb
3
+ metadata.gz: 397f41f3a15c86c5307a304e878fdf755ee47474
4
+ data.tar.gz: 57a0933ff281f922f79bcef23304d570e563d56a
5
5
  SHA512:
6
- metadata.gz: 6fa6f2ff6eefa7bc123f0f6af444d566c6db47e8786439cb23b53aee310b8e3378c40385d5a3c2764c3658072d220fb64c36924fe94b51697e5f51d88232ff9f
7
- data.tar.gz: ed515c832462b40bf65b737a9c963ac12db5a194cfc9e97bdf5acd504204ab0a3932aa716050190b841b2b9db6968103c841017e39bca06de21556722537de8c
6
+ metadata.gz: aba44a6c955bfc541ddf83d010031656935800cfca10b7c4dc88194201bddb8149762b5a7d93754363c691ff12a22da71950ba6b959326464bd6a8c2992fc538
7
+ data.tar.gz: 5772cd0031968bc5e026dc773190baffdff5d98c376ea4b8c7e119e19143d4a29f765519c4938f484027fec583d5b11684d70c4f3ec6b11c4fda57dc22d90683
data/.gitignore CHANGED
@@ -17,3 +17,5 @@ Jobfile
17
17
  /.vagrant
18
18
  *.pem
19
19
  *.bak
20
+ /_site
21
+ ssh_config
data/.rspec CHANGED
@@ -1,2 +1,4 @@
1
1
  --colour
2
2
  --require spec_helper
3
+ --require rspec/instafail
4
+ --format RSpec::Instafail
data/README.md CHANGED
@@ -39,13 +39,13 @@ Options:
39
39
  [--ask-pass], [--no-ask-pass] # Ask sudo password
40
40
  [--dry-run], [--no-dry-run] # Do not actually change
41
41
  -c, [--ssh-config=SSH-CONFIG] # OpenSSH configuration file
42
- # Default: ~/.ssh/config
42
+ # Default: ssh_config
43
43
  [--ssh-options=SSH-OPTIONS] # SSH options (JSON)
44
44
  [--connection-timeout=N] # SSH connection timeout
45
45
  [--concurrency=N] # SSH concurrency
46
46
  # Default: 10
47
- [--libexec=LIBEXEC] # Cronicle libexec path
48
- # Default: /var/lib/cronicle/libexec
47
+ [--var-dir=VAR-DIR] # Cronicle var dir path
48
+ # Default: /var/lib/cronicle
49
49
  -v, [--verbose], [--no-verbose] # Verbose mode
50
50
  [--debug], [--no-debug] # Debug mode
51
51
  [--color], [--no-color] # Colorize log
@@ -90,8 +90,12 @@ puts "hello"
90
90
 
91
91
  ```ruby
92
92
  on servers: :your_hostname do
93
- job :my_job, user: "ec2-user", schedule: "* * * * *" do
94
- puts "hello"
93
+ job :my_job, user: "ec2-user", schedule: "* * * * *", bundle: 'ruby-mysql' do
94
+ require 'mysql'
95
+ my = Mysql.connect('hostname', 'username', 'password', 'dbname')
96
+ my.query("select col1, col2 from tblname").each do |col1, col2|
97
+ p col1, col2
98
+ end
95
99
  end
96
100
 
97
101
  job :my_job2, user: "ec2-user", schedule: "* * * * *", content: <<-EOS
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'rake'
31
31
  spec.add_development_dependency 'rspec', '>= 3.0.0'
32
32
  spec.add_development_dependency 'serverspec'
33
+ spec.add_development_dependency 'rspec-instafail'
33
34
  end
@@ -12,7 +12,7 @@ class Cronicle::CLI < Thor
12
12
  class_option 'ssh-options', :desc => 'SSH options (JSON)', :default => ENV['CRONICLE_SSH_OPTIONS']
13
13
  class_option 'connection-timeout', :desc => 'SSH connection timeout', :type => :numeric, :default => nil
14
14
  class_option 'concurrency', :desc => 'SSH concurrency', :type => :numeric, :default => Cronicle::Client::DEFAULTS[:concurrency]
15
- class_option 'libexec', :desc => 'Cronicle libexec path', :default => Cronicle::Client::DEFAULTS[:libexec]
15
+ class_option 'var-dir', :desc => 'Cronicle var dir path', :default => Cronicle::Client::DEFAULTS[:var_dir]
16
16
  class_option 'verbose', :aliases => '-v', :desc => 'Verbose mode', :type => :boolean, :default => false
17
17
  class_option 'debug', :desc => 'Debug mode', :type => :boolean, :default => false
18
18
  class_option 'color', :desc => 'Colorize log', :type => :boolean, :default => true
@@ -85,7 +85,7 @@ class Cronicle::CLI < Thor
85
85
  :sudo_password => options['sudo-password'],
86
86
  :ssh_user => options['ssh-user'],
87
87
  :concurrency => options['concurrency'],
88
- :libexec => options['libexec'],
88
+ :var_dir => options['var-dir'],
89
89
  :dry_run => options['dry-run'],
90
90
  :verbose => options['verbose']
91
91
  }
@@ -3,7 +3,7 @@ class Cronicle::Client
3
3
 
4
4
  DEFAULTS = {
5
5
  :concurrency => 10,
6
- :libexec => '/var/lib/cronicle/libexec'
6
+ :var_dir => '/var/lib/cronicle'
7
7
  }
8
8
 
9
9
  def initialize(host_list, options = {})
@@ -138,6 +138,8 @@ class Cronicle::Client
138
138
  (selected_hots + dsl_hosts).uniq.each do |h|
139
139
  if hosts[h][job_user][job_name]
140
140
  log(:warn, "Job is duplicated", :color => :yellow, :host => h, :user => job_user, :job => job_name)
141
+ elsif job_name.nil?
142
+ hosts[h] ||= {}
141
143
  else
142
144
  hosts[h][job_user][job_name] = job_hash
143
145
  end
@@ -54,7 +54,20 @@ class Cronicle::Driver
54
54
  end
55
55
 
56
56
  upload_script(temp_dir, name, job[:content]) do |temp_script|
57
- command = sudo(:_execute, temp_script, :user => user, :raise_on_non_zero_exit => false)
57
+ exec_opts = {:user => user, :raise_on_non_zero_exit => false}
58
+ command = nil
59
+
60
+ if job[:bundle]
61
+ mkgemfile(user, name, job[:bundle], temp_dir)
62
+ bundle(user, name, temp_dir)
63
+
64
+ with_bundle(user, name, temp_dir) do
65
+ command = sudo(:_execute, bundler_path, :exec, temp_script, exec_opts)
66
+ end
67
+ else
68
+ command = sudo(:_execute, temp_script, exec_opts)
69
+ end
70
+
58
71
  out = command.full_stdout
59
72
  Cronicle::Utils.remove_prompt!(out)
60
73
  host_user_job = {:host => host.hostname, :user => user, :job => name}
@@ -79,6 +92,13 @@ class Cronicle::Driver
79
92
  end
80
93
 
81
94
  def create_job(user, name, job)
95
+ execute do
96
+ if job[:bundle]
97
+ mkgemfile(user, name, job[:bundle])
98
+ bundle(user, name)
99
+ end
100
+ end
101
+
82
102
  create_or_update_job(user, name, job)
83
103
  end
84
104
 
@@ -86,6 +106,13 @@ class Cronicle::Driver
86
106
  job_content = job[:content].chomp
87
107
  script_content = script[:content].chomp
88
108
 
109
+ execute do
110
+ if job[:bundle]
111
+ mkgemfile(user, name, job[:bundle])
112
+ bundle(user, name)
113
+ end
114
+ end
115
+
89
116
  if [:schedule, :content].any? {|k| job[k].chomp != script[k].chomp }
90
117
  create_or_update_job(user, name, job, script)
91
118
  end
@@ -114,7 +141,7 @@ class Cronicle::Driver
114
141
  sudo(:execute, :cp, temp_script, libexec_script)
115
142
  sudo(:execute, :touch, user_crontab(user))
116
143
  delete_cron_entry(user, name)
117
- add_cron_entry(user, name, job[:schedule], user_temp_dir)
144
+ add_cron_entry(user, name, job[:schedule], user_temp_dir, job[:bundle])
118
145
  end
119
146
  end
120
147
  end
@@ -135,6 +162,7 @@ class Cronicle::Driver
135
162
  unless host.options[:dry_run]
136
163
  delete_cron_entry(user, name)
137
164
  sudo(:execute, :rm, '-f', script[:path], :raise_on_non_zero_exit => false)
165
+ sudo(:execute, :rm, '-rf', gemfile_dir(user, name), :raise_on_non_zero_exit => false)
138
166
  end
139
167
  end
140
168
  end
@@ -42,7 +42,12 @@ class Cronicle::DSL::Context
42
42
  end
43
43
 
44
44
  target.assert_valid_keys(:servers, :roles)
45
+ values = Cronicle::DSL::Context::Job.new(target, &block).result.values
45
46
 
46
- @result.concat(Cronicle::DSL::Context::Job.new(target, &block).result.values)
47
+ @result.concat(values.empty? ? [{
48
+ :servers => Array(target[:servers]),
49
+ :roles => Array(target[:roles]),
50
+ :job => {}
51
+ }] : values)
47
52
  end
48
53
  end
@@ -30,7 +30,7 @@ class Cronicle::DSL::Context::Job
30
30
  raise ArgumentError, "Job `#{name}`: :user is required"
31
31
  end
32
32
 
33
- opts.assert_valid_keys(:schedule, :user, :content)
33
+ opts.assert_valid_keys(:schedule, :user, :content, :bundle)
34
34
 
35
35
  if opts[:content] and block
36
36
  raise ArgumentError, 'Can not pass :content and block to `job` method'
@@ -42,6 +42,11 @@ class Cronicle::DSL::Context::Job
42
42
  job_hash[:name] = name
43
43
  job_hash[:user] = opts.fetch(:user).to_s
44
44
  job_hash[:schedule] = opts[:schedule].to_s if opts[:schedule]
45
+ bundle = opts[:bundle]
46
+
47
+ if bundle
48
+ job_hash[:bundle] = bundle.kind_of?(Hash) ? bundle : Array(bundle).map(&:to_s)
49
+ end
45
50
 
46
51
  if block
47
52
  source = block.to_raw_source(:strip_enclosure => true).each_line.to_a
@@ -32,12 +32,12 @@ class Cronicle::Exporter
32
32
 
33
33
  def parse_crontab(crontab, libexec_contents)
34
34
  scripts = {}
35
- libexec_dir = @options.fetch(:libexec)
35
+ libexec_dir = @options.fetch(:var_dir) + '/libexec'
36
36
 
37
37
  crontab.each_line.map(&:strip).each do |line|
38
38
  next if line =~ /\A#/
39
39
 
40
- md = line.match(/\A(@\w+|\S+(?:\s+\S+){4})\s+(.\S+)(.*)\z/)
40
+ md = line.match(/\A(@\w+|\S+(?:\s+\S+){4})\s+(?:cd\s+\S+\s+&&\s+\S*bundle\s+exec\s+)?(.\S+)(.*)\z/)
41
41
  schedule, path, extra = md.captures if md
42
42
 
43
43
  if %r|\A#{Regexp.escape(libexec_dir)}/(?:[^/]+)/(.+)| =~ path
@@ -2,7 +2,7 @@ class Hash
2
2
  def assert_valid_keys(*valid_keys)
3
3
  each_key do |k|
4
4
  next if valid_keys.include?(k)
5
- raise ArgumentError, "Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}"
5
+ raise ArgumentError, "unknown key: #{k.inspect}. valid keys are: #{valid_keys.map(&:inspect).join(', ')}"
6
6
  end
7
7
  end
8
8
  end
@@ -77,11 +77,17 @@ class SSHKit::Backend::Netssh
77
77
  sudo(:execute, :sed, '-i', sed_cmd, user_crontab(user), :raise_on_non_zero_exit => false)
78
78
  end
79
79
 
80
- def add_cron_entry(user, name, schedule, temp_dir)
80
+ def add_cron_entry(user, name, schedule, temp_dir, bundle_gems = nil)
81
81
  script = script_path(user, name)
82
82
  temp_entry = [temp_dir, name + '.entry'].join('/')
83
83
 
84
- cron_entry = "#{schedule}\\t#{script} 2>&1 | logger -t cronicle/#{user}/#{name}"
84
+ cron_entry = "#{schedule}\\t"
85
+
86
+ if bundle_gems
87
+ cron_entry << "cd #{gemfile_dir(user, name)} && #{bundler_path} exec "
88
+ end
89
+
90
+ cron_entry << "#{script} 2>&1 | logger -t cronicle/#{user}/#{name}"
85
91
  cron_entry = Shellwords.shellescape(cron_entry)
86
92
  sudo(:execute, :echo, '-e', cron_entry, '>', temp_entry)
87
93
 
@@ -91,7 +97,7 @@ class SSHKit::Backend::Netssh
91
97
  end
92
98
 
93
99
  def upload_script(temp_dir, name, content)
94
- temp_script = [temp_dir, name].join
100
+ temp_script = [temp_dir, name].join('/')
95
101
  upload!(StringIO.new(content), temp_script)
96
102
  execute(:chmod, 755, temp_script)
97
103
  yield(temp_script)
@@ -113,18 +119,87 @@ class SSHKit::Backend::Netssh
113
119
 
114
120
  yield(*block_args)
115
121
  ensure
116
- execute(:rm, '-rf', temp_dir, :raise_on_non_zero_exit => false) rescue nil
122
+ sudo(:execute, :rm, '-rf', temp_dir, :raise_on_non_zero_exit => false) rescue nil
123
+ end
124
+ end
125
+
126
+ def mkgemfile(user, name, bundle_gems, temp_dir = nil)
127
+ sudo(:execute, :mkdir, '-p', gemfile_dir(user, name, temp_dir))
128
+ sudo(:execute, :bash, '-c',
129
+ Shellwords.shellescape(
130
+ [:echo, Shellwords.shellescape("source 'https://rubygems.org'"), '>', gemfile(user, name, temp_dir)].join(' ')
131
+ )
132
+ )
133
+
134
+ bundle_gems.each do |gem_name, version|
135
+ line = "gem '#{gem_name}'"
136
+ line << ", '#{version}'" if version
137
+ sudo(:execute, :bash, '-c',
138
+ Shellwords.shellescape(
139
+ [:echo, Shellwords.shellescape(line), '>>', gemfile(user, name, temp_dir)].join(' ')
140
+ )
141
+ )
142
+ end
143
+ end
144
+
145
+ def bundle(user, name, temp_dir = nil)
146
+ with_bundle(user, name, temp_dir) do |bundler_opts|
147
+ unless sudo(:execute, bundler_path, :check, *bundler_opts, :raise_on_non_zero_exit => false)
148
+ sudo(:execute, bundler_path, :install, *bundler_opts)
149
+ end
150
+ end
151
+ end
152
+
153
+ def with_bundle(user, name, temp_dir = nil)
154
+ within gemfile_dir(user, name, temp_dir) do
155
+ bundler_opts = ['--no-color', '--gemfile', gemfile(user, name, temp_dir), '--path', bundle_dir]
156
+ yield(bundler_opts)
117
157
  end
118
158
  end
119
159
 
120
160
  def libexec_dir
121
- host.options.fetch(:libexec)
161
+ host.options.fetch(:var_dir) + '/libexec'
162
+ end
163
+
164
+ def run_dir
165
+ host.options.fetch(:var_dir) + '/run'
166
+ end
167
+
168
+ def bundle_dir
169
+ host.options.fetch(:var_dir) + '/bundle'
170
+ end
171
+
172
+ BUNDLER_PATHS = %w(
173
+ /usr/local/bin/bundle
174
+ /usr/bin/bundle
175
+ )
176
+
177
+ def bundler_path
178
+ @bundler_path ||= (BUNDLER_PATHS.find {|path|
179
+ execute(:test, '-f', path, :raise_on_non_zero_exit => false)
180
+ } || :bundle)
122
181
  end
123
182
 
124
183
  def user_libexec_dir(user)
125
184
  [libexec_dir, user].join('/')
126
185
  end
127
186
 
187
+ def user_run_dir(user)
188
+ [run_dir, user].join('/')
189
+ end
190
+
191
+ def gemfile_dir(user, name, temp_dir = nil)
192
+ if temp_dir
193
+ [temp_dir, user, name].join('/')
194
+ else
195
+ [user_run_dir(user), name].join('/')
196
+ end
197
+ end
198
+
199
+ def gemfile(user, name, temp_dir = nil)
200
+ [gemfile_dir(user, name, temp_dir), 'Gemfile'].join('/')
201
+ end
202
+
128
203
  def user_crontab(user)
129
204
  cron_dir = find_cron_dir
130
205
  [cron_dir, user].join('/')
@@ -1,3 +1,3 @@
1
1
  module Cronicle
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
@@ -242,6 +242,103 @@ ZOO=baz
242
242
  end
243
243
  end
244
244
 
245
+ context 'when apply with bundle' do
246
+ let(:jobfile) do
247
+ <<-RUBY.unindent
248
+ on servers: /.*/ do
249
+ job :foo, user: :root, schedule: '1 2 * * *', bundle: 'ruby-mysql' do
250
+ require 'mysql'
251
+ p Mysql
252
+ end
253
+ end
254
+ RUBY
255
+ end
256
+
257
+ let(:amzn_crontab) do
258
+ {
259
+ "/var/spool/cron/ec2-user" =>
260
+ "FOO=bar
261
+ ZOO=baz
262
+ 1 1 1 1 1 echo ec2-user > /dev/null
263
+ ",
264
+ "/var/spool/cron/root" =>
265
+ "FOO=bar
266
+ ZOO=baz
267
+ 1 1 1 1 1 echo root > /dev/null
268
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
269
+ "
270
+ }
271
+ end
272
+
273
+ let(:amzn_gemfile) do
274
+ {
275
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
276
+ "source 'https://rubygems.org'
277
+ gem 'ruby-mysql'
278
+ "
279
+ }
280
+ end
281
+
282
+ let(:ubuntu_crontab) do
283
+ {
284
+ "/var/spool/cron/crontabs/root" =>
285
+ "FOO=bar
286
+ ZOO=baz
287
+ 1 1 1 1 1 echo root > /dev/null
288
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
289
+ ",
290
+ "/var/spool/cron/crontabs/ubuntu" =>
291
+ "FOO=bar
292
+ ZOO=baz
293
+ 1 1 1 1 1 echo ubuntu > /dev/null
294
+ "
295
+ }
296
+ end
297
+
298
+ let(:ubuntu_gemfile) do
299
+ {
300
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
301
+ "source 'https://rubygems.org'
302
+ gem 'ruby-mysql'
303
+ "
304
+ }
305
+ end
306
+
307
+ before do
308
+ cronicle(:apply) { jobfile }
309
+ end
310
+
311
+ it do
312
+ on :amazon_linux do
313
+ expect(get_uname).to match /amzn/
314
+ expect(get_crontabs).to eq amzn_crontab
315
+
316
+ expect(get_file('/var/lib/cronicle/libexec/root/foo')).to eq <<-EOS.unindent
317
+ #!/usr/bin/env ruby
318
+ require 'mysql'
319
+ p Mysql
320
+ EOS
321
+
322
+ expect(get_gemfiles).to eq amzn_gemfile
323
+ end
324
+ end
325
+
326
+ it do
327
+ on :ubuntu do
328
+ expect(get_uname).to match /Ubuntu/
329
+ expect(get_crontabs).to eq ubuntu_crontab
330
+
331
+ expect(get_file('/var/lib/cronicle/libexec/root/foo')).to eq <<-EOS.unindent
332
+ #!/usr/bin/env ruby
333
+ require 'mysql'
334
+ p Mysql
335
+ EOS
336
+
337
+ expect(get_gemfiles).to eq ubuntu_gemfile
338
+ end
339
+ end
340
+ end
341
+
245
342
  context 'when apply (dry-run)' do
246
343
  let(:amzn_crontab) do
247
344
  {
@@ -206,6 +206,165 @@ ZOO=baz
206
206
  end
207
207
  end
208
208
 
209
+ context 'when cron is deleted with bundle' do
210
+ let(:jobfile) do
211
+ <<-RUBY.unindent
212
+ on servers: /.*/ do
213
+ job :foo, user: :root, schedule: '1 2 * * *', bundle: 'ruby-mysql' do
214
+ require 'mysql'
215
+ p Mysql
216
+ end
217
+ end
218
+ RUBY
219
+ end
220
+
221
+ let(:amzn_crontab_orig) do
222
+ {
223
+ "/var/spool/cron/ec2-user" =>
224
+ "FOO=bar
225
+ ZOO=baz
226
+ 1 1 1 1 1 echo ec2-user > /dev/null
227
+ ",
228
+ "/var/spool/cron/root" =>
229
+ "FOO=bar
230
+ ZOO=baz
231
+ 1 1 1 1 1 echo root > /dev/null
232
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
233
+ "
234
+ }
235
+ end
236
+
237
+ let(:amzn_gemfile_orig) do
238
+ {
239
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
240
+ "source 'https://rubygems.org'
241
+ gem 'ruby-mysql'
242
+ "
243
+ }
244
+ end
245
+
246
+ let(:ubuntu_crontab_orig) do
247
+ {
248
+ "/var/spool/cron/crontabs/root" =>
249
+ "FOO=bar
250
+ ZOO=baz
251
+ 1 1 1 1 1 echo root > /dev/null
252
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
253
+ ",
254
+ "/var/spool/cron/crontabs/ubuntu" =>
255
+ "FOO=bar
256
+ ZOO=baz
257
+ 1 1 1 1 1 echo ubuntu > /dev/null
258
+ "
259
+ }
260
+ end
261
+
262
+ let(:ubuntu_gemfile_orig) do
263
+ {
264
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
265
+ "source 'https://rubygems.org'
266
+ gem 'ruby-mysql'
267
+ "
268
+ }
269
+ end
270
+
271
+ let(:amzn_crontab) do
272
+ {
273
+ "/var/spool/cron/ec2-user" =>
274
+ "FOO=bar
275
+ ZOO=baz
276
+ 1 1 1 1 1 echo ec2-user > /dev/null
277
+ ",
278
+ "/var/spool/cron/root" =>
279
+ "FOO=bar
280
+ ZOO=baz
281
+ 1 1 1 1 1 echo root > /dev/null
282
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
283
+ "
284
+ }
285
+ end
286
+
287
+ let(:amzn_gemfile) do
288
+ {
289
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
290
+ "source 'https://rubygems.org'
291
+ gem 'ruby-mysql'
292
+ "
293
+ }
294
+ end
295
+
296
+ let(:ubuntu_crontab) do
297
+ {
298
+ "/var/spool/cron/crontabs/root" =>
299
+ "FOO=bar
300
+ ZOO=baz
301
+ 1 1 1 1 1 echo root > /dev/null
302
+ 1 2 * * *\tcd /var/lib/cronicle/run/root/foo && /usr/local/bin/bundle exec /var/lib/cronicle/libexec/root/foo 2>&1 | logger -t cronicle/root/foo
303
+ ",
304
+ "/var/spool/cron/crontabs/ubuntu" =>
305
+ "FOO=bar
306
+ ZOO=baz
307
+ 1 1 1 1 1 echo ubuntu > /dev/null
308
+ "
309
+ }
310
+ end
311
+
312
+ let(:ubuntu_gemfile) do
313
+ {
314
+ "/var/lib/cronicle/run/root/foo/Gemfile" =>
315
+ "source 'https://rubygems.org'
316
+ gem 'ruby-mysql'
317
+ "
318
+ }
319
+ end
320
+
321
+ before do
322
+ cronicle(:apply) { jobfile }
323
+ end
324
+
325
+ it do
326
+ on :amazon_linux do
327
+ expect(get_uname).to match /amzn/
328
+ expect(get_crontabs).to eq amzn_crontab_orig
329
+
330
+ expect(get_file('/var/lib/cronicle/libexec/root/foo')).to eq <<-EOS.unindent
331
+ #!/usr/bin/env ruby
332
+ require 'mysql'
333
+ p Mysql
334
+ EOS
335
+
336
+ expect(get_gemfiles).to eq amzn_gemfile_orig
337
+ end
338
+
339
+ on :ubuntu do
340
+ expect(get_uname).to match /Ubuntu/
341
+ expect(get_crontabs).to eq ubuntu_crontab_orig
342
+
343
+ expect(get_file('/var/lib/cronicle/libexec/root/foo')).to eq <<-EOS.unindent
344
+ #!/usr/bin/env ruby
345
+ require 'mysql'
346
+ p Mysql
347
+ EOS
348
+
349
+ expect(get_gemfiles).to eq ubuntu_gemfile_orig
350
+ end
351
+
352
+ cronicle(:apply) { '' }
353
+
354
+ on :amazon_linux do
355
+ expect(get_uname).to match /amzn/
356
+ expect(get_crontabs).to eq amzn_crontab
357
+ expect(get_gemfiles).to eq amzn_gemfile
358
+ end
359
+
360
+ on :ubuntu do
361
+ expect(get_uname).to match /Ubuntu/
362
+ expect(get_crontabs).to eq ubuntu_crontab
363
+ expect(get_gemfiles).to eq ubuntu_gemfile
364
+ end
365
+ end
366
+ end
367
+
209
368
  context 'when cron is deleted (dry-run)' do
210
369
  let(:amzn_crontab) do
211
370
  {
@@ -162,4 +162,52 @@ describe 'Cronicle::Client#exec' do
162
162
  }.to raise_error('Definition cannot be found: Job `bar`')
163
163
  end
164
164
  end
165
+
166
+ context 'with bundle' do
167
+ let(:jobfile) do
168
+ <<-RUBY.unindent
169
+ on servers: /amazon_linux/ do
170
+ job :foo, user: 'ec2-user', bundle: 'hashie' do
171
+ require 'hashie'
172
+ mash = Hashie::Mash.new
173
+ mash.name = "My Mash on amazon_linux"
174
+ p mash.name
175
+ p mash.name?
176
+ end
177
+ end
178
+
179
+ on servers: /ubuntu/ do
180
+ job :foo, user: :ubuntu, bundle: 'hashie' do
181
+ require 'hashie'
182
+ mash = Hashie::Mash.new
183
+ mash.name = "My Mash on ubuntu"
184
+ p mash.name
185
+ p mash.name?
186
+ end
187
+ end
188
+ RUBY
189
+ end
190
+
191
+ before do
192
+ cronicle(:exec, :foo, logger: logger) { jobfile }
193
+ end
194
+
195
+ it do
196
+ expect(amzn_out).to eq <<-EOS.unindent
197
+ foo on amazon_linux/ec2-user> Execute job
198
+ foo on amazon_linux/ec2-user>\s
199
+ foo on amazon_linux/ec2-user> "My Mash on amazon_linux"
200
+ foo on amazon_linux/ec2-user> true
201
+ EOS
202
+ end
203
+
204
+ it do
205
+ expect(ubuntu_out).to eq <<-EOS.unindent
206
+ foo on ubuntu/ubuntu> Execute job
207
+ foo on ubuntu/ubuntu>\s
208
+ foo on ubuntu/ubuntu> "My Mash on ubuntu"
209
+ foo on ubuntu/ubuntu> true
210
+ EOS
211
+ end
212
+ end
165
213
  end
@@ -50,6 +50,15 @@ def get_crontabs
50
50
  }.flatten]
51
51
  end
52
52
 
53
+ def get_gemfiles
54
+ gemfiles = Specinfra.backend.run_command("ls /var/lib/cronicle/run/*/*/Gemfile 2> /dev/null").stdout.strip.split(/\s+/)
55
+
56
+ Hash[*gemfiles.map {|gemfile|
57
+ content = Specinfra.backend.run_command("cat #{gemfile}").stdout
58
+ [gemfile, content]
59
+ }.flatten]
60
+ end
61
+
53
62
  def get_file(path)
54
63
  Specinfra.backend.run_command("cat #{path}").stdout
55
64
  end
@@ -87,9 +96,14 @@ def on(*hosts)
87
96
  end
88
97
 
89
98
  RSpec.configure do |config|
90
- config.before(:each) do
99
+ config.before(:all) do
91
100
  on :ubuntu do
92
101
  Specinfra.backend.run_command("apt-get -y install ruby")
102
+ Specinfra.backend.run_command("gem install bundler")
103
+ end
104
+
105
+ on :amazon_linux do
106
+ Specinfra.backend.run_command("gem install bundler")
93
107
  end
94
108
  end
95
109
 
@@ -97,6 +111,7 @@ RSpec.configure do |config|
97
111
  on TARGET_HOSTS do
98
112
  cron_dir = get_cron_dir
99
113
  Specinfra.backend.run_command("rm -f #{cron_dir}/*")
114
+ Specinfra.backend.run_command("rm -rf /var/lib/cronicle/run")
100
115
  end
101
116
  end
102
117
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cronicle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - '>='
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec-instafail
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
181
195
  description: It is a tool for execute script, and define cron on remote hosts.
182
196
  email:
183
197
  - sgwr_dts@yahoo.co.jp