cronicle 0.1.4 → 0.1.5

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.
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