crontabinator 0.0.0 → 0.0.1

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