minicron 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +42 -33
- data/bin/minicron +3 -0
- data/lib/minicron.rb +12 -3
- data/lib/minicron/alert.rb +9 -6
- data/lib/minicron/cli.rb +15 -6
- data/lib/minicron/cli/commands.rb +35 -12
- data/lib/minicron/constants.rb +1 -1
- data/lib/minicron/cron.rb +71 -30
- data/lib/minicron/hub/app.rb +6 -0
- data/lib/minicron/hub/assets/app/components/schedules.js +1 -1
- data/lib/minicron/hub/assets/app/controllers/hosts.js +6 -2
- data/lib/minicron/hub/assets/app/controllers/jobs.js +5 -2
- data/lib/minicron/hub/assets/app/controllers/schedules.js +15 -13
- data/lib/minicron/hub/assets/app/models/host.js +1 -0
- data/lib/minicron/hub/assets/app/models/job.js +1 -0
- data/lib/minicron/hub/controllers/api/executions.rb +0 -1
- data/lib/minicron/hub/controllers/api/hosts.rb +12 -13
- data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +0 -1
- data/lib/minicron/hub/controllers/api/jobs.rb +5 -3
- data/lib/minicron/hub/controllers/api/schedule.rb +3 -1
- data/lib/minicron/hub/db/schema.rb +8 -6
- data/lib/minicron/hub/db/schema.sql +4 -2
- data/lib/minicron/hub/views/handlebars/hosts.erb +18 -0
- data/lib/minicron/hub/views/handlebars/jobs.erb +18 -0
- data/lib/minicron/monitor.rb +14 -12
- data/lib/minicron/transport.rb +0 -1
- data/lib/minicron/transport/client.rb +19 -11
- data/lib/minicron/transport/faye/client.rb +16 -2
- data/lib/minicron/transport/faye/extensions/job_handler.rb +10 -4
- data/lib/minicron/transport/faye/server.rb +5 -4
- data/lib/minicron/transport/server.rb +9 -4
- data/lib/minicron/transport/ssh.rb +5 -4
- data/spec/minicron/alert/pagerduty_spec.rb +1 -0
- data/spec/minicron/alert/sms_spec.rb +1 -0
- data/spec/minicron/cli_spec.rb +1 -0
- data/spec/minicron/transport/client_spec.rb +1 -0
- data/spec/minicron/transport/faye/client_spec.rb +1 -0
- data/spec/minicron/transport/server_spec.rb +1 -0
- data/spec/minicron/transport_spec.rb +1 -0
- data/spec/minicron_spec.rb +6 -0
- metadata +88 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b6939554f2e620783856cad085a5caebb87d70c
|
4
|
+
data.tar.gz: 3384f8536105f764031a7035c9a3fea95b985bcf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9420b0503c77643198a875eda7a194630186dd9809f90574b1c234eff524ffc9a1f6b925dc5e766ad775f2d9f89e94e3450c3c810347157d55de6745f9b8287
|
7
|
+
data.tar.gz: d4ffe62daecf9ae0abab5b85baf68d40da45a6c1b89a68b20793c4256a7488c8b1e875e4827ab5bcf0856d455c2260d5ed5cf1359b5d41e60d4d9fdc70b487b7
|
data/README.md
CHANGED
@@ -14,23 +14,31 @@ server(s) and executes your cron command and reports the status back to the Hub.
|
|
14
14
|
where data from one or many instances of the CLI are is recieved and stored in a database. The Hub also provides
|
15
15
|
a web interface to the data and makes it easy to manage your cron jobs.
|
16
16
|
|
17
|
-
- [
|
18
|
-
- [
|
19
|
-
- [
|
20
|
-
- [
|
21
|
-
- [
|
22
|
-
- [
|
23
|
-
- [
|
24
|
-
- [
|
25
|
-
- [
|
26
|
-
- [
|
17
|
+
- [Screenshots](#screenshots)
|
18
|
+
- [Background](#background)
|
19
|
+
- [Features](#goals)
|
20
|
+
- [Requirements](#requirements)
|
21
|
+
- [Installation](#installation)
|
22
|
+
- [Usage](#usage)
|
23
|
+
- [Documentation](#documentation)
|
24
|
+
- [Versioning](#versioning)
|
25
|
+
- [Contributing](#contributing)
|
26
|
+
- [Support](#support)
|
27
|
+
- [License](#license)
|
28
|
+
|
29
|
+
Screenshots
|
30
|
+
------------
|
31
|
+
|
32
|
+
<img src="http://f.cl.ly/items/2o3q3x1N1X3n2t180H1u/Image%202014-04-12%20at%2010.54.39%20pm.png" height="100"/>
|
33
|
+
|
34
|
+
More coming..
|
27
35
|
|
28
36
|
Background
|
29
37
|
-----------
|
30
38
|
|
31
|
-
I'm developing minicron as part of my dissertation at university which
|
32
|
-
development after that.
|
33
|
-
[Miniclip](http://www.miniclip.com) where the management and monitoring of cron jobs at times proved to be tricky!
|
39
|
+
I'm developing minicron as part of my dissertation at university which has to be completed by May but I plan to continue
|
40
|
+
development after that. The inspiration for developing minicron comes from my own experience, in particular my time spent
|
41
|
+
working at [Miniclip](http://www.miniclip.com) where the management and monitoring of cron jobs at times proved to be tricky!
|
34
42
|
|
35
43
|
Features
|
36
44
|
---------
|
@@ -43,9 +51,9 @@ Features
|
|
43
51
|
- Alerts when jobs executions are missed or fail via:
|
44
52
|
- Email
|
45
53
|
- SMS ([using Twilio](https://www.twilio.com))
|
46
|
-
- [PagerDuty](www.pagerduty.com)
|
54
|
+
- [PagerDuty](http://www.pagerduty.com) (SMS, Phone, Mobile Push Notifications and Email)
|
47
55
|
|
48
|
-
Lots more is planned for the future, see issues
|
56
|
+
Lots more is planned for the future, see [open issues](issues?state=open) or if you don't see the feature you want there add it!
|
49
57
|
|
50
58
|
Requirements
|
51
59
|
-------------
|
@@ -53,7 +61,7 @@ Requirements
|
|
53
61
|
#### Ruby
|
54
62
|
- **MRI**: 1.9.3 and above (tested on 1.9.3, 2.0.0, 2.1.0)
|
55
63
|
- <del>**Rubinius**: Travis builds are run on the latest release</del> [*awaiting bug fix*](https://github.com/rubinius/rubinius/issues/2944)
|
56
|
-
- **JRuby:** currently untested but most likely needs some
|
64
|
+
- **JRuby:** currently untested but most likely needs some work
|
57
65
|
|
58
66
|
#### Database
|
59
67
|
|
@@ -63,7 +71,7 @@ Requirements
|
|
63
71
|
#### Web Server / Reverse Proxy
|
64
72
|
|
65
73
|
If you want to run minicron behind a web server or proxy it needs to support the web socket protocol.
|
66
|
-
nginx for example supports web sockets from version 1.3.13 and up. I've included an [example config](
|
74
|
+
nginx for example supports web sockets from version 1.3.13 and up. I've included an [example config](sample.nginx.conf) for nginx.
|
67
75
|
|
68
76
|
#### Browser
|
69
77
|
|
@@ -72,22 +80,22 @@ I'm currently unsure of how it functions in the various of Internet Explorer but
|
|
72
80
|
|
73
81
|
#### OS
|
74
82
|
|
75
|
-
Should run on any linux/bsd based OS that the above ruby versions run on.
|
83
|
+
Should run on osx and any linux/bsd based OS that the above ruby versions run on.
|
76
84
|
|
77
85
|
Installation
|
78
86
|
-------------
|
79
87
|
|
80
88
|
minicron is currently under heavy development and as such I would not recommend that you use this in production yet
|
81
|
-
but I encourage you to give it a try in a non critical environment and help me to improve it.
|
89
|
+
but I encourage you to give it a try in a non critical environment and help me to improve it and work towards the first stable release (1.0).
|
82
90
|
|
83
|
-
1. First check you meet the [requirements](
|
91
|
+
1. First check you meet the [requirements](#requirements)
|
84
92
|
|
85
93
|
2. On some distributions you may need to install the ````ruby-dev```` and ````build-essential```` packages
|
86
94
|
|
87
|
-
3. To install the latest release (currently 0.
|
95
|
+
3. To install the latest release (currently 0.4) you can ````gem install minicron````, depending on your ruby setup
|
88
96
|
you may need to run this with ````sudo````
|
89
97
|
|
90
|
-
4. Set your database configuration options in ````/etc/minicron.toml````, you can use the [default.config.toml](
|
98
|
+
4. Set your database configuration options in ````/etc/minicron.toml````, you can use the [default.config.toml](default.config.toml) as a guide on what options are configurable
|
91
99
|
|
92
100
|
5. Make sure you have created an empty database with the name you set in ````/etc/minicron.toml````
|
93
101
|
|
@@ -99,7 +107,7 @@ but I encourage you to give it a try in a non critical environment and help me t
|
|
99
107
|
> ````
|
100
108
|
|
101
109
|
6. You can then ````minicron db setup```` to create the database schema, alternatively you can use
|
102
|
-
the [schema dump provided](
|
110
|
+
the [schema dump provided](lib/minicron/hub/db/schema.sql)
|
103
111
|
|
104
112
|
7. Done! See the usage section below for more details on how to use minicron now you have it installed
|
105
113
|
|
@@ -149,7 +157,7 @@ you can also use the ````stop```` and ````status```` commands to control the ser
|
|
149
157
|
To run the server in debug mode, i.e not as a daemon so you can see its output you can pass the ````--debug````
|
150
158
|
option.
|
151
159
|
|
152
|
-
See [sample.nginx.conf](
|
160
|
+
See [sample.nginx.conf](sample.nginx.conf) for an example of
|
153
161
|
how to run minicron behind a reverse proxy.
|
154
162
|
|
155
163
|
#### Connecting to a host via SSH
|
@@ -163,7 +171,7 @@ most linux distributions or ````/var/root/.ssh/authorized_keys```` on OSX.
|
|
163
171
|
|
164
172
|
#### Version
|
165
173
|
|
166
|
-
Like many command line programs minicron will show
|
174
|
+
Like many command line programs minicron will show its version number when the global options ````-v````
|
167
175
|
or ````--version```` are passed to the CLI.
|
168
176
|
|
169
177
|
#### Configuration
|
@@ -171,14 +179,14 @@ or ````--version```` are passed to the CLI.
|
|
171
179
|
Some configuration options can be passed in manually but the recommend way to configure minicron is through the use
|
172
180
|
of a config file. You can specify the path to the file using the ````--config```` global option. The file is expected
|
173
181
|
to be in the [toml](https://github.com/mojombo/toml "toml") format. The default options are specified in the
|
174
|
-
[default.config.toml](
|
182
|
+
[default.config.toml](default.config.toml "default.config.toml")
|
175
183
|
file and minicron will parse a config located in ````/etc/minicron.toml```` if it exists. Options specified via
|
176
184
|
the command line will take precedence over those taken from a config file.
|
177
185
|
|
178
186
|
Documentation
|
179
187
|
-------------
|
180
188
|
|
181
|
-
minicron uses [Yard](http://yardoc.org/ "Yard") for
|
189
|
+
minicron uses [Yard](http://yardoc.org/ "Yard") for its code documentation (currently the only *usage* documentation is what you're reading right now), you can either generate it and view
|
182
190
|
it locally using the following commands:
|
183
191
|
|
184
192
|
````bash
|
@@ -191,7 +199,8 @@ or view the most up to date version online at [RubyDoc.info](http://rdoc.info/gi
|
|
191
199
|
Versioning
|
192
200
|
-----------
|
193
201
|
|
194
|
-
|
202
|
+
All stable releases will follow the [semantic versioning](http://semver.org/) guidelines. Until 1.0 hits I will try to document any
|
203
|
+
major breaking changes in the release descriptions.
|
195
204
|
|
196
205
|
Releases will be numbered with the following format:
|
197
206
|
|
@@ -206,17 +215,17 @@ Based on the following guidelines:
|
|
206
215
|
Contributing
|
207
216
|
------------
|
208
217
|
|
209
|
-
Feedback and pull requests are welcome, please see [CONTRIBUTING.md](
|
218
|
+
Feedback and pull requests are welcome, please see [CONTRIBUTING.md](CONTRIBUTING.md "CONTRIBUTING.md") for more info.
|
210
219
|
|
211
220
|
Areas that I would love some help with:
|
212
221
|
|
213
|
-
- Any of the unassigned [issues here](
|
222
|
+
- Any of the unassigned [issues here](issues?state=open).
|
214
223
|
- General testing of the system, let me know what you think and create issues for any bugs you find!
|
215
224
|
- Tests!!
|
216
225
|
- Validation and error handling improvements
|
217
|
-
- Documentation improvements.
|
226
|
+
- Documentation improvements. If you find something confusing or unexpected let me know and I'll add or improve
|
218
227
|
documentation for it!
|
219
|
-
- Look for '[TODO:](
|
228
|
+
- Look for '[TODO:](search?q=TODO%3A)' notices littered around the code,
|
220
229
|
I'm trying to convert them all to issues but there are a lot..
|
221
230
|
- Code refactoring, I had a reasonably tight deadline to have the main concept done by so some parts are a bit rushed
|
222
231
|
- UI improvements
|
@@ -234,4 +243,4 @@ Or feel free to open an issue and I'll do my best to help.
|
|
234
243
|
License
|
235
244
|
--------
|
236
245
|
|
237
|
-
minicron is licensed under the GPL v3, [see here for the full license](
|
246
|
+
minicron is licensed under the GPL v3, [see here for the full license](LICENSE "see here")
|
data/bin/minicron
CHANGED
@@ -4,6 +4,9 @@ require 'minicron'
|
|
4
4
|
require 'minicron/cli'
|
5
5
|
require 'minicron/transport/server'
|
6
6
|
|
7
|
+
# Set the process name to something more useful
|
8
|
+
$PROGRAM_NAME = "minicron #{ARGV.join(' ')}"
|
9
|
+
|
7
10
|
begin
|
8
11
|
# Capture any output from STDERR so we can handle it how we want to
|
9
12
|
Minicron.capture_output(:type => :stderr) do
|
data/lib/minicron.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
require 'toml'
|
3
|
-
require 'sshkey'
|
4
1
|
require 'minicron/constants'
|
5
2
|
|
6
3
|
# @author James White <dev.jameswhite+minicron@gmail.com>
|
7
4
|
module Minicron
|
5
|
+
# Define module autoloading
|
6
|
+
autoload :TOML, 'toml'
|
7
|
+
autoload :StringIO, 'stringio'
|
8
|
+
autoload :SSHKey, 'sshkey'
|
9
|
+
|
8
10
|
# Default configuration, this can be overriden
|
9
11
|
@config = {
|
10
12
|
'verbose' => false,
|
@@ -179,4 +181,11 @@ module Minicron
|
|
179
181
|
def self.get_hostname
|
180
182
|
`hostname -s`.strip
|
181
183
|
end
|
184
|
+
|
185
|
+
# Get the user minicron is being run as
|
186
|
+
#
|
187
|
+
# @return [String]
|
188
|
+
def self.get_user
|
189
|
+
`whoami`.strip
|
190
|
+
end
|
182
191
|
end
|
data/lib/minicron/alert.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
require 'minicron/alert/email'
|
2
|
-
require 'minicron/alert/sms'
|
3
|
-
require 'minicron/alert/pagerduty'
|
4
|
-
require 'minicron/hub/models/alert'
|
5
|
-
require 'minicron/hub/models/job'
|
6
|
-
|
7
1
|
module Minicron
|
2
|
+
autoload :Email, 'minicron/alert/email'
|
3
|
+
autoload :SMS, 'minicron/alert/sms'
|
4
|
+
autoload :PagerDuty, 'minicron/alert/pagerduty'
|
5
|
+
|
6
|
+
module Hub
|
7
|
+
autoload :Alert, 'minicron/hub/models/alert'
|
8
|
+
autoload :Job, 'minicron/hub/models/job'
|
9
|
+
end
|
10
|
+
|
8
11
|
# Allows the sending of alerts via multiple mediums
|
9
12
|
class Alert
|
10
13
|
# Send an alert using all enabled mediums
|
data/lib/minicron/cli.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
|
-
|
1
|
+
autoload :PTY, 'pty'
|
2
|
+
autoload :Minicron, 'minicron'
|
3
|
+
|
2
4
|
require 'English'
|
3
5
|
require 'rainbow/ext/string'
|
4
6
|
require 'commander'
|
5
7
|
require 'minicron/constants'
|
6
8
|
require 'minicron/cli/commands'
|
7
|
-
require 'minicron/transport'
|
8
|
-
require 'minicron/transport/client'
|
9
|
-
require 'minicron/transport/server'
|
10
|
-
require 'minicron/monitor'
|
11
9
|
|
12
10
|
include Commander::UI
|
13
11
|
|
14
12
|
module Minicron
|
13
|
+
autoload :Transport, 'minicron/transport'
|
14
|
+
autoload :Monitor, 'minicron/monitor'
|
15
|
+
|
16
|
+
module Transport
|
17
|
+
autoload :Client, 'minicron/transport/client'
|
18
|
+
autoload :Server, 'minicron/transport/server'
|
19
|
+
end
|
20
|
+
|
15
21
|
# Handles the main CLI interaction of minicron
|
16
22
|
# TODO: this class is probably too complicated and should be refactored a bit
|
17
23
|
module CLI
|
@@ -188,6 +194,9 @@ module Minicron
|
|
188
194
|
@cli.program :version, Minicron::VERSION
|
189
195
|
@cli.program :description, 'cli for minicron; a system a to manage and monitor cron jobs'
|
190
196
|
|
197
|
+
# Display the output in a compact format
|
198
|
+
@cli.program :help_formatter, Commander::HelpFormatter::TerminalCompact
|
199
|
+
|
191
200
|
# Set the default command to run
|
192
201
|
@cli.default_command :help
|
193
202
|
|
@@ -197,7 +206,7 @@ module Minicron
|
|
197
206
|
end
|
198
207
|
|
199
208
|
# Add a global option for verbose mode
|
200
|
-
@cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['
|
209
|
+
@cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['verbose'].to_s}" do
|
201
210
|
Minicron.config['verbose'] = true
|
202
211
|
end
|
203
212
|
|
@@ -1,8 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
autoload :Minicron, 'minicron'
|
2
|
+
autoload :Insidious, 'insidious'
|
3
|
+
autoload :Rake, 'rake'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
autoload :ActiveRecordTasks, 'sinatra/activerecord/rake'
|
7
|
+
end
|
4
8
|
|
5
9
|
module Minicron
|
10
|
+
autoload :Transport, 'minicron/transport'
|
11
|
+
|
12
|
+
module Transport
|
13
|
+
autoload :Client, 'minicron/transport/client'
|
14
|
+
autoload :Server, 'minicron/transport/server'
|
15
|
+
end
|
16
|
+
|
17
|
+
module Hub
|
18
|
+
autoload :App, 'minicron/hub/app'
|
19
|
+
end
|
20
|
+
|
6
21
|
module CLI
|
7
22
|
class Commands
|
8
23
|
# Add the `minicron db` command
|
@@ -20,11 +35,6 @@ module Minicron
|
|
20
35
|
# Parse the file and cli config options
|
21
36
|
Minicron::CLI.parse_config(opts)
|
22
37
|
|
23
|
-
# These are inlined as we only need them in this use case
|
24
|
-
require 'rake'
|
25
|
-
require 'minicron/hub/app'
|
26
|
-
require 'sinatra/activerecord/rake'
|
27
|
-
|
28
38
|
# Setup the db
|
29
39
|
Minicron::Hub::App.setup_db
|
30
40
|
|
@@ -125,7 +135,16 @@ module Minicron
|
|
125
135
|
# Set up the job and get the jexecution and job ids back from the server
|
126
136
|
ids = setup_job(args.first, faye)
|
127
137
|
end
|
138
|
+
rescue Exception => e
|
139
|
+
raise Exception, "Unable to setup job, reason: #{e.message}"
|
128
140
|
|
141
|
+
# Ensure that all messages are delivered and that we
|
142
|
+
unless Minicron.config['cli']['dry_run']
|
143
|
+
faye.tidy_up
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
begin
|
129
148
|
# Execute the command and yield the output
|
130
149
|
Minicron::CLI.run_command(args.first, :mode => Minicron.config['cli']['mode'], :verbose => Minicron.config['verbose']) do |output|
|
131
150
|
# We need to handle the yielded output differently based on it's type
|
@@ -143,6 +162,7 @@ module Minicron
|
|
143
162
|
yield output[:output] unless output[:type] == :status
|
144
163
|
end
|
145
164
|
rescue Exception => e
|
165
|
+
p e
|
146
166
|
# Send the exception message to the server and yield it
|
147
167
|
unless Minicron.config['cli']['dry_run']
|
148
168
|
faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => e.message)
|
@@ -171,9 +191,6 @@ module Minicron
|
|
171
191
|
# Get the fully qualified domain name of the currnet host
|
172
192
|
fqdn = Minicron.get_fqdn
|
173
193
|
|
174
|
-
# Get the short hostname of the current host
|
175
|
-
hostname = Minicron.get_hostname
|
176
|
-
|
177
194
|
# Get the md5 hash for the job
|
178
195
|
job_hash = Minicron::Transport.get_job_hash(command, fqdn)
|
179
196
|
|
@@ -181,7 +198,13 @@ module Minicron
|
|
181
198
|
faye.ensure_em_running
|
182
199
|
|
183
200
|
# Setup the job on the server
|
184
|
-
ids = faye.setup(
|
201
|
+
ids = faye.setup(
|
202
|
+
:job_hash => job_hash,
|
203
|
+
:user => Minicron.get_user,
|
204
|
+
:command => command,
|
205
|
+
:fqdn => fqdn,
|
206
|
+
:hostname => Minicron.get_hostname
|
207
|
+
)
|
185
208
|
|
186
209
|
# Wait until we get the execution id
|
187
210
|
faye.ensure_delivery
|
data/lib/minicron/constants.rb
CHANGED
data/lib/minicron/cron.rb
CHANGED
@@ -3,9 +3,6 @@ require 'escape'
|
|
3
3
|
|
4
4
|
module Minicron
|
5
5
|
# Used to interact with the crontab on hosts over an ssh connection
|
6
|
-
# TODO: I've had a moment of clarity, I don't need to do all the CRUD
|
7
|
-
# using unix commands. I can cat the crontab, manipulate it in ruby
|
8
|
-
# and then echo it back!
|
9
6
|
class Cron
|
10
7
|
# Initialise the cron class
|
11
8
|
#
|
@@ -16,15 +13,49 @@ module Minicron
|
|
16
13
|
|
17
14
|
# Build the minicron command to be used in the crontab
|
18
15
|
#
|
19
|
-
# @param command [String]
|
20
16
|
# @param schedule [String]
|
17
|
+
# @param user [String]
|
18
|
+
# @param command [String]
|
21
19
|
# @return [String]
|
22
|
-
def build_minicron_command(
|
20
|
+
def build_minicron_command(schedule, user, command)
|
23
21
|
# Escape the command so it will work in bourne shells
|
24
22
|
command = Escape.shell_command(['minicron', 'run', command])
|
25
|
-
cron_command =Escape.shell_command(['/bin/bash', '-l', '-c', command])
|
23
|
+
cron_command = Escape.shell_command(['/bin/bash', '-l', '-c', command])
|
26
24
|
|
27
|
-
"#{schedule}
|
25
|
+
"#{schedule} #{user} #{cron_command}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Test an SSH connection and the permissions for the crontab
|
29
|
+
#
|
30
|
+
# @param conn an instance of an open ssh connection
|
31
|
+
# @return [Hash]
|
32
|
+
def test_host_permissions(conn = nil)
|
33
|
+
# Open an SSH connection
|
34
|
+
conn ||= @ssh.open
|
35
|
+
|
36
|
+
# Check if /etc is writeable
|
37
|
+
etc_write = conn.exec!("/bin/sh -c 'test -w /etc && echo \"y\" || echo \"n\"'").strip
|
38
|
+
|
39
|
+
# Check if /etc is executable
|
40
|
+
etc_execute = conn.exec!("/bin/sh -c 'test -x /etc && echo \"y\" || echo \"n\"'").strip
|
41
|
+
|
42
|
+
# Check if the crontab is readable
|
43
|
+
crontab_read = conn.exec!("/bin/sh -c 'test -r /etc/crontab && echo \"y\" || echo \"n\"'").strip
|
44
|
+
|
45
|
+
# Check if the crontab is writeable
|
46
|
+
crontab_write = conn.exec!("/bin/sh -c 'test -w /etc/crontab && echo \"y\" || echo \"n\"'").strip
|
47
|
+
|
48
|
+
{
|
49
|
+
:connect => true,
|
50
|
+
:etc => {
|
51
|
+
:write => etc_write == 'y',
|
52
|
+
:execute => etc_execute == 'y'
|
53
|
+
},
|
54
|
+
:crontab => {
|
55
|
+
:read => crontab_read == 'y',
|
56
|
+
:write => crontab_write == 'y'
|
57
|
+
}
|
58
|
+
}
|
28
59
|
end
|
29
60
|
|
30
61
|
# Used to find a string and replace it with another in the crontab by
|
@@ -34,7 +65,27 @@ module Minicron
|
|
34
65
|
# @param find [String]
|
35
66
|
# @param replace [String]
|
36
67
|
def find_and_replace(conn, find, replace)
|
37
|
-
|
68
|
+
begin
|
69
|
+
# Test the SSH connection first
|
70
|
+
test = test_host_permissions(conn)
|
71
|
+
rescue Exception => e
|
72
|
+
raise Exception, "Error connecting to host, reason: #{e.message}"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check the connection worked
|
76
|
+
raise Exception, "Unable to connect to host, reason: unknown" if !test[:connect]
|
77
|
+
|
78
|
+
# Check the crontab is readable
|
79
|
+
raise Exception, "Insufficient permissions to read from /etc/crontab" if !test[:crontab][:read]
|
80
|
+
|
81
|
+
# Check the crontab is writeable
|
82
|
+
raise Exception, "Insufficient permissions to write to /etc/crontab" if !test[:crontab][:write]
|
83
|
+
|
84
|
+
# Check /etc is writeable
|
85
|
+
raise Exception, "/etc is not writeable by the current user" if !test[:etc][:write]
|
86
|
+
|
87
|
+
# Check /etc is executable
|
88
|
+
raise Exception, "/etc is not executable by the current user" if !test[:etc][:execute]
|
38
89
|
|
39
90
|
# Get the full crontab
|
40
91
|
crontab = conn.exec!('cat /etc/crontab').to_s.strip
|
@@ -47,17 +98,12 @@ module Minicron
|
|
47
98
|
end
|
48
99
|
|
49
100
|
# Echo the crontab back to the tmp crontab
|
50
|
-
|
51
|
-
|
52
|
-
# Throw an exception if it failed
|
53
|
-
if update != 'y'
|
54
|
-
fail Exception, "Unable to replace '#{find}' with '#{replace}' in the crontab"
|
55
|
-
end
|
101
|
+
conn.exec!("echo #{crontab.shellescape} > /tmp/minicron_crontab").to_s.strip
|
56
102
|
|
57
103
|
# If it's a delete
|
58
104
|
if replace == ''
|
59
105
|
# Check the original line is no longer there
|
60
|
-
grep = conn.exec!("grep -F #{find.shellescape} /
|
106
|
+
grep = conn.exec!("grep -F #{find.shellescape} /tmp/minicron_crontab").to_s.strip
|
61
107
|
|
62
108
|
# Throw an exception if we can't see our new line at the end of the file
|
63
109
|
if grep != replace
|
@@ -65,7 +111,7 @@ module Minicron
|
|
65
111
|
end
|
66
112
|
else
|
67
113
|
# Check the updated line is there
|
68
|
-
grep = conn.exec!("grep -F #{replace.shellescape} /
|
114
|
+
grep = conn.exec!("grep -F #{replace.shellescape} /tmp/minicron_crontab").to_s.strip
|
69
115
|
|
70
116
|
# Throw an exception if we can't see our new line at the end of the file
|
71
117
|
if grep != replace
|
@@ -74,10 +120,10 @@ module Minicron
|
|
74
120
|
end
|
75
121
|
|
76
122
|
# And finally replace the crontab with the new one now we now the change worked
|
77
|
-
move = conn.exec!("mv /
|
123
|
+
move = conn.exec!("/bin/sh -c 'mv /tmp/minicron_crontab /etc/crontab && echo \"y\" || echo \"n\"'").to_s.strip
|
78
124
|
|
79
125
|
if move != 'y'
|
80
|
-
fail Exception, 'Unable to move tmp crontab
|
126
|
+
fail Exception, 'Unable to move /tmp/minicron_crontab to /etc/crontab, check the permissions?'
|
81
127
|
end
|
82
128
|
end
|
83
129
|
|
@@ -91,20 +137,15 @@ module Minicron
|
|
91
137
|
conn ||= @ssh.open
|
92
138
|
|
93
139
|
# Prepare the line we are going to write to the crontab
|
94
|
-
line = build_minicron_command(job.
|
140
|
+
line = build_minicron_command(schedule, job.user, job.command)
|
95
141
|
escaped_line = line.shellescape
|
96
|
-
echo_line = "echo #{escaped_line} >> /etc/crontab
|
142
|
+
echo_line = "echo #{escaped_line} >> /etc/crontab"
|
97
143
|
|
98
144
|
# Append it to the end of the crontab
|
99
|
-
|
100
|
-
|
101
|
-
# Throw an exception if it failed
|
102
|
-
if write != 'y'
|
103
|
-
fail Exception, "Unable to echo #{escaped_line} to the crontab"
|
104
|
-
end
|
145
|
+
conn.exec!(echo_line).to_s.strip
|
105
146
|
|
106
147
|
# Check the line is there
|
107
|
-
tail = conn.exec!('tail -n 1 /etc/crontab').strip
|
148
|
+
tail = conn.exec!('tail -n 1 /etc/crontab').to_s.strip
|
108
149
|
|
109
150
|
# Throw an exception if we can't see our new line at the end of the file
|
110
151
|
if tail != line
|
@@ -123,10 +164,10 @@ module Minicron
|
|
123
164
|
conn ||= @ssh.open
|
124
165
|
|
125
166
|
# We are looking for the current value of the schedule
|
126
|
-
find = build_minicron_command(job.
|
167
|
+
find = build_minicron_command(old_schedule, job.user, job.command)
|
127
168
|
|
128
169
|
# And replacing it with the updated value
|
129
|
-
replace = build_minicron_command(job.
|
170
|
+
replace = build_minicron_command(new_schedule, job.user, job.command)
|
130
171
|
|
131
172
|
# Replace the old schedule with the new schedule
|
132
173
|
find_and_replace(conn, find, replace)
|
@@ -142,7 +183,7 @@ module Minicron
|
|
142
183
|
conn ||= @ssh.open
|
143
184
|
|
144
185
|
# We are looking for the current value of the schedule
|
145
|
-
find = build_minicron_command(job.
|
186
|
+
find = build_minicron_command(schedule, job.user, job.command)
|
146
187
|
|
147
188
|
# Replace the old schedule with nothing i.e deleting it
|
148
189
|
find_and_replace(conn, find, '')
|