crontabinator 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,2 +1,6 @@
1
1
  set :crontab_log_level, "info"
2
+ set :crontab_logs_path, -> { shared_path.join('log') }
2
3
  set :crontab_templates_path, "templates/crontab"
4
+ set :crontab_lockfile_path, -> { "#{fetch(:crontab_templates_path)}/crontab.lock" }
5
+ set :crontab_scripts_path, -> { "#{fetch(:crontab_templates_path)}/scripts.d" }
6
+ set :crontab_server_scripts_path, -> { current_path.join('script') }
@@ -1,8 +1,37 @@
1
1
  namespace :crontab do
2
2
  namespace :check do
3
3
 
4
+ task :scripts do
5
+ run_locally do
6
+ files = Dir.glob("#{fetch(:crontab_scripts_path)}/*\.erb")
7
+ set :crontab_script_files, files.collect { |f| File.expand_path(f) }
8
+ fetch(:crontab_script_files).each do |file|
9
+ hash = eval(File.read(file).lines.to_a.shift)
10
+ if hash.nil? or hash[:user].nil? or hash[:schedule].nil?
11
+ fatal "Error reading the first line of #{file}"
12
+ fatal "Ensure the first line is a Ruby hash in the form: " +
13
+ "\"{ :user => \"www-data\", :schedule => \"* * * * *\" }\""
14
+ fatal "Your shebang line directly next"
15
+ exit
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ task :erb_validity do
22
+ run_locally do
23
+ fetch(:crontab_script_files).each do |file|
24
+ unless test "erb", "-x", "-T", "'-'", file, "|", "ruby", "-c"
25
+ fatal "There's a syntax error with #{file}"
26
+ fatal "Test it manually with `erb -x -T '-' #{file} | ruby -c`"
27
+ exit
28
+ end
29
+ end
30
+ end
31
+ end
32
+
4
33
  desc 'Ensure all crontabinator specific settings are set, and warn and exit if not.'
5
- before 'crontab:setup', :settings do
34
+ task :settings => [:scripts, :erb_validity] do
6
35
  {
7
36
  (File.dirname(__FILE__) + "/examples/config/deploy.rb") => 'config/deploy.rb',
8
37
  (File.dirname(__FILE__) + "/examples/config/deploy/staging.rb") => "config/deploy/#{fetch(:stage)}.rb"
@@ -18,12 +18,13 @@ namespace :crontabinator do
18
18
  desc "Write example config files (with '_example' appended to their names)."
19
19
  task :write_example_configs do
20
20
  run_locally do
21
- execute "mkdir", "-p", "config/deploy", fetch(:crontab_templates_path)
21
+ execute "mkdir", "-p", "config/deploy", fetch(:crontab_templates_path), fetch(:crontab_scripts_path)
22
22
  {
23
23
  "examples/Capfile" => "Capfile#{fetch(:example)}",
24
24
  "examples/config/deploy.rb" => "config/deploy#{fetch(:example)}.rb",
25
25
  "examples/config/deploy/staging.rb" => "config/deploy/staging#{fetch(:example)}.rb",
26
26
  "examples/crontab.erb" => "#{fetch(:crontab_templates_path)}/crontab#{fetch(:example)}.erb",
27
+ "examples/myscript.sh.erb" => "#{fetch(:crontab_scripts_path)}/myscript#{fetch(:example)}.sh.erb"
27
28
  }.each do |source, destination|
28
29
  config = File.read(File.dirname(__FILE__) + "/#{source}")
29
30
  File.open("./#{destination}", 'w') { |f| f.write(config) }
@@ -1,31 +1,108 @@
1
1
  namespace :crontab do
2
2
 
3
+ # sets :user_crontab_hash in the form:
4
+ # { :"user" => ["#!/bin/bash", "/bin/echo 'asdf' >> /tmp/test.log"] }
5
+ task :read_all_settings => ['crontab:check:scripts'] do
6
+ run_locally do
7
+ user_crontab_hash = {}
8
+
9
+ # Auto entries
10
+ auto_entries = []
11
+ fetch(:crontab_script_files).each do |file|
12
+ hash = eval(File.read(file).lines.to_a.shift)
13
+ path = "#{fetch(:crontab_server_scripts_path)}/#{File.basename(file, '.erb')}"
14
+ auto_entries += [{ :user => hash[:user], :schedule => hash[:schedule], :path => path }]
15
+ end
16
+ auto_entries.each do |entry|
17
+ name = File.basename(entry[:path], '.erb')
18
+ user_crontab_hash[entry[:user]] ||= []
19
+ user_crontab_hash[entry[:user]] << [
20
+ "# #{name}",
21
+ "#{entry[:schedule]} #{entry[:path]} >> #{fetch(:crontab_logs_path)}/#{name} 2>&1",
22
+ ""
23
+ ]
24
+ end
25
+
26
+ # User entries
27
+ fetch(:user_crontab_entries, {}).each do |user, lines|
28
+ user_crontab_hash[user] ||= []
29
+ user_crontab_hash[user] << [lines]
30
+ end
31
+
32
+ # All entries
33
+ user_crontab_hash.each { |user, lines| user_crontab_hash[user] = lines.flatten }
34
+
35
+ set :user_crontab_hash, user_crontab_hash
36
+
37
+ # Newly removed crontabs
38
+ crontabs_to_remove = []
39
+ if File.exists?(fetch(:crontab_lockfile_path))
40
+ old_users = eval(File.read(fetch(:crontab_lockfile_path))).sort
41
+ new_users = user_crontab_hash.collect { |user, _| user }.sort
42
+ crontabs_to_remove = old_users - new_users
43
+ end
44
+ set :crontabs_to_remove, crontabs_to_remove
45
+ end
46
+ end
47
+
48
+ task :upload_scripts => [:read_all_settings] do
49
+ on roles(:cron) do |host|
50
+ fetch(:crontab_script_files).each do |path|
51
+ lines = File.read(path).lines.to_a
52
+ lines.shift
53
+ file = ERB.new(lines.join, nil, '-').result(binding)
54
+ as :root do execute("rm", "/tmp/script", "-f") end
55
+ upload! StringIO.new(file), "/tmp/script"
56
+ final_path = "#{fetch(:crontab_server_scripts_path)}/#{File.basename(path, '.erb')}"
57
+ as :root do
58
+ execute("mv", "/tmp/script", final_path)
59
+ execute("chmod", "750", final_path)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
3
65
  desc "Idempotently setup Crontabs."
4
- task :setup do
66
+ task :setup => ['crontab:check:settings', :read_all_settings, :upload_scripts] do
5
67
  log_level = SSHKit.config.output_verbosity
6
68
  log_level = "info" if log_level.nil?
7
69
  SSHKit.config.output_verbosity = fetch(:crontab_log_level)
8
70
 
9
71
  on roles(:cron) do |host|
10
- fetch(:user_crontab_entries).each do |user, entries|
72
+ # New
73
+ fetch(:user_crontab_hash).each do |user, lines|
11
74
  unless unix_user_exists?(user)
12
- error "User #{user} does not exist even though you defined crontab settings for it - Skipping!"
75
+ error "You defined crontab settings for '#{user}', but no such user exists - Skipping!"
13
76
  else
14
- set :crontab_entries, entries
15
- template_path = File.expand_path("./#{fetch(:crontab_templates_path)}/crontab.erb")
16
- generated_config_file = ERB.new(File.new(template_path).read, nil, '-').result(binding)
17
- upload! StringIO.new(generated_config_file), "/tmp/crontab"
18
- as :root do
19
- execute("chown", "#{user}:#{user}", "/tmp/crontab")
20
- end
21
- as user do
22
- execute "crontab", "/tmp/crontab"
23
- end
77
+ set :crontab_entries, lines
78
+ path = File.expand_path("./#{fetch(:crontab_templates_path)}/crontab.erb")
79
+ file = ERB.new(File.read(path), nil, '-').result(binding)
80
+ as :root do execute("rm", "/tmp/crontab", "-f") end
81
+ upload! StringIO.new(file), "/tmp/crontab"
82
+ as :root do execute("chown", "#{user}:#{user}", "/tmp/crontab") end
83
+ as user do execute "crontab", "/tmp/crontab" end
24
84
  as :root do
25
85
  execute "rm", "/tmp/crontab"
26
86
  end
27
87
  end
28
88
  end
89
+
90
+ # Old
91
+ fetch(:crontabs_to_remove).each do |user|
92
+ as :root do
93
+ execute "crontab", "-u", user, "-r"
94
+ end
95
+ end
96
+ content = [
97
+ "# Add this file to version control, - it tracks and removes crontab",
98
+ "# entries on the server which you have removed from the config",
99
+ fetch(:user_crontab_hash).collect { |u, _| u }.sort.to_s
100
+ ].join("\n") + "\n"
101
+ unless File.exists?(fetch(:crontab_lockfile_path)) &&
102
+ File.read(fetch(:crontab_lockfile_path)) == content
103
+ File.open(fetch(:crontab_lockfile_path), 'w') { |f| f.write(content) }
104
+ warn "Updated '#{fetch(:crontab_lockfile_path)}', add it to version control"
105
+ end
29
106
  end
30
107
  SSHKit.config.output_verbosity = log_level
31
108
  end
@@ -35,13 +112,13 @@ namespace :crontab do
35
112
  end
36
113
 
37
114
  desc "Check the status of the Crontabs."
38
- task :status do
115
+ task :status => [:read_all_settings] do
39
116
  log_level = SSHKit.config.output_verbosity
40
117
  log_level = "info" if log_level.nil?
41
118
  SSHKit.config.output_verbosity = fetch(:crontab_log_level)
42
119
 
43
120
  on roles(:cron) do
44
- fetch(:user_crontab_entries).each do |user, _|
121
+ fetch(:user_crontab_hash).each do |user, _|
45
122
  as :root do
46
123
  unless unix_user_exists?(user)
47
124
  error "User #{user} does not exist even though you defined crontab settings for it - Skipping!"
@@ -4,7 +4,7 @@ set :domain, "my-app.example.com"
4
4
  server fetch(:domain),
5
5
  :user => fetch(:deployment_username),
6
6
  :roles => ["cron"]
7
- set :user_crontab_entries, {
7
+ set :user_crontab_entries, { # this must be set, even if an empty Hash
8
8
  "www-data" => [
9
9
  "SHELL=/bin/bash",
10
10
  "MAILTO=myemail@example.com",
@@ -0,0 +1,4 @@
1
+ { :user => "root", :schedule => '* * * * *' }
2
+ #!/bin/bash
3
+
4
+ /bin/echo "example scripts.d script" >> <%= current_path.join('log', 'example.log') %> 2>&1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crontabinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-05-27 00:00:00.000000000 Z
12
+ date: 2015-10-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capistrano
@@ -90,6 +90,7 @@ files:
90
90
  - lib/crontabinator/examples/config/deploy.rb
91
91
  - lib/crontabinator/examples/config/deploy/staging.rb
92
92
  - lib/crontabinator/examples/crontab.erb
93
+ - lib/crontabinator/examples/myscript.sh.erb
93
94
  homepage: https://github.com/snarlysodboxer/crontabinator
94
95
  licenses:
95
96
  - GNU
@@ -117,3 +118,4 @@ signing_key:
117
118
  specification_version: 3
118
119
  summary: Deploy Crontabs
119
120
  test_files: []
121
+ has_rdoc: