minicron 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +187 -0
  4. data/Rakefile +17 -0
  5. data/bin/minicron +26 -0
  6. data/lib/minicron.rb +179 -0
  7. data/lib/minicron/alert.rb +115 -0
  8. data/lib/minicron/alert/email.rb +50 -0
  9. data/lib/minicron/alert/pagerduty.rb +39 -0
  10. data/lib/minicron/alert/sms.rb +47 -0
  11. data/lib/minicron/cli.rb +367 -0
  12. data/lib/minicron/constants.rb +7 -0
  13. data/lib/minicron/cron.rb +192 -0
  14. data/lib/minicron/hub/app.rb +132 -0
  15. data/lib/minicron/hub/assets/app/application.js +151 -0
  16. data/lib/minicron/hub/assets/app/components/schedules.js +280 -0
  17. data/lib/minicron/hub/assets/app/controllers/executions.js +35 -0
  18. data/lib/minicron/hub/assets/app/controllers/hosts.js +129 -0
  19. data/lib/minicron/hub/assets/app/controllers/jobs.js +109 -0
  20. data/lib/minicron/hub/assets/app/controllers/schedules.js +80 -0
  21. data/lib/minicron/hub/assets/app/helpers.js +22 -0
  22. data/lib/minicron/hub/assets/app/models/execution.js +13 -0
  23. data/lib/minicron/hub/assets/app/models/host.js +15 -0
  24. data/lib/minicron/hub/assets/app/models/job.js +15 -0
  25. data/lib/minicron/hub/assets/app/models/job_execution_output.js +11 -0
  26. data/lib/minicron/hub/assets/app/models/schedule.js +32 -0
  27. data/lib/minicron/hub/assets/app/router.js +31 -0
  28. data/lib/minicron/hub/assets/app/routes/executions.js +36 -0
  29. data/lib/minicron/hub/assets/app/routes/hosts.js +42 -0
  30. data/lib/minicron/hub/assets/app/routes/index.js +9 -0
  31. data/lib/minicron/hub/assets/app/routes/jobs.js +52 -0
  32. data/lib/minicron/hub/assets/app/routes/schedules.js +37 -0
  33. data/lib/minicron/hub/assets/css/bootswatch.min.css +9 -0
  34. data/lib/minicron/hub/assets/css/main.scss +323 -0
  35. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  36. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  37. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  38. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  39. data/lib/minicron/hub/assets/fonts/lato-bold-700.woff +0 -0
  40. data/lib/minicron/hub/assets/fonts/lato-italic-400.woff +0 -0
  41. data/lib/minicron/hub/assets/fonts/lato-regular-400.woff +0 -0
  42. data/lib/minicron/hub/assets/js/ansi_up-1.1.1.min.js +6 -0
  43. data/lib/minicron/hub/assets/js/auth/ember-auth-9.0.7.min.js +2 -0
  44. data/lib/minicron/hub/assets/js/auth/ember-auth-request-jquery-1.0.3.min.js +1 -0
  45. data/lib/minicron/hub/assets/js/bootstrap-3.1.1.min.js +6 -0
  46. data/lib/minicron/hub/assets/js/ember-1.4.1.min.js +18 -0
  47. data/lib/minicron/hub/assets/js/ember-data-1.0.0-beta.7.f87cba88.min.js +10 -0
  48. data/lib/minicron/hub/assets/js/faye-browser-1.0.1.min.js +2 -0
  49. data/lib/minicron/hub/assets/js/handlebars-1.3.0.min.js +29 -0
  50. data/lib/minicron/hub/assets/js/jquery-2.1.0.min.js +4 -0
  51. data/lib/minicron/hub/assets/js/moment-2.5.1.min.js +7 -0
  52. data/lib/minicron/hub/controllers/api/executions.rb +34 -0
  53. data/lib/minicron/hub/controllers/api/hosts.rb +150 -0
  54. data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +30 -0
  55. data/lib/minicron/hub/controllers/api/jobs.rb +118 -0
  56. data/lib/minicron/hub/controllers/api/schedule.rb +184 -0
  57. data/lib/minicron/hub/controllers/index.rb +5 -0
  58. data/lib/minicron/hub/db/schema.rb +98 -0
  59. data/lib/minicron/hub/db/schema.sql +158 -0
  60. data/lib/minicron/hub/models/alert.rb +7 -0
  61. data/lib/minicron/hub/models/execution.rb +8 -0
  62. data/lib/minicron/hub/models/host.rb +7 -0
  63. data/lib/minicron/hub/models/job.rb +18 -0
  64. data/lib/minicron/hub/models/job_execution_output.rb +7 -0
  65. data/lib/minicron/hub/models/schedule.rb +25 -0
  66. data/lib/minicron/hub/serializers/execution.rb +75 -0
  67. data/lib/minicron/hub/serializers/host.rb +57 -0
  68. data/lib/minicron/hub/serializers/job.rb +104 -0
  69. data/lib/minicron/hub/serializers/job_execution_output.rb +48 -0
  70. data/lib/minicron/hub/serializers/schedule.rb +68 -0
  71. data/lib/minicron/hub/views/handlebars/application.erb +51 -0
  72. data/lib/minicron/hub/views/handlebars/errors.erb +29 -0
  73. data/lib/minicron/hub/views/handlebars/executions.erb +79 -0
  74. data/lib/minicron/hub/views/handlebars/hosts.erb +205 -0
  75. data/lib/minicron/hub/views/handlebars/jobs.erb +203 -0
  76. data/lib/minicron/hub/views/handlebars/loading.erb +3 -0
  77. data/lib/minicron/hub/views/handlebars/schedules.erb +354 -0
  78. data/lib/minicron/hub/views/index.erb +7 -0
  79. data/lib/minicron/hub/views/layouts/app.erb +15 -0
  80. data/lib/minicron/monitor.rb +116 -0
  81. data/lib/minicron/transport.rb +15 -0
  82. data/lib/minicron/transport/client.rb +80 -0
  83. data/lib/minicron/transport/faye/client.rb +103 -0
  84. data/lib/minicron/transport/faye/extensions/job_handler.rb +184 -0
  85. data/lib/minicron/transport/faye/server.rb +58 -0
  86. data/lib/minicron/transport/server.rb +62 -0
  87. data/lib/minicron/transport/ssh.rb +51 -0
  88. data/spec/invalid_config.toml +2 -0
  89. data/spec/minicron/cli_spec.rb +154 -0
  90. data/spec/minicron/transport/client_spec.rb +8 -0
  91. data/spec/minicron/transport/faye/client_spec.rb +53 -0
  92. data/spec/minicron/transport/server_spec.rb +70 -0
  93. data/spec/minicron/transport_spec.rb +13 -0
  94. data/spec/minicron_spec.rb +133 -0
  95. data/spec/spec_helper.rb +33 -0
  96. data/spec/valid_config.toml +48 -0
  97. metadata +577 -0
@@ -0,0 +1,187 @@
1
+ minicron
2
+ =======
3
+
4
+ [![Build Status](http://img.shields.io/travis/jamesrwhite/minicron.svg)](http://travis-ci.org/jamesrwhite/minicron) [![Coverage Status](http://img.shields.io/coveralls/jamesrwhite/minicron.svg)](https://coveralls.io/r/jamesrwhite/minicron?branch=master) [![Code Climate](http://img.shields.io/codeclimate/github/jamesrwhite/minicron.svg)](https://codeclimate.com/github/jamesrwhite/minicron) [![Dependency Status](http://img.shields.io/gemnasium/jamesrwhite/minicron.svg)](https://gemnasium.com/jamesrwhite/minicron) [![Inline docs](http://inch-pages.github.io/github/jamesrwhite/minicron.png)](http://inch-pages.github.io/github/jamesrwhite/minicron)
5
+
6
+ minicron aims to complement ````cron```` by making it easier to manage and monitor cron jobs, it can largely be thought of as two components that interact together, the CLI and the Hub. The CLI is what is installed on your server(s) and executes your cron command and reports the status back to the Hub. The Hub is the central point where data from one or many instances of the CLI are is recieved and stored in a database. The Hub also provides a web interface to the data and makes it easy to manage your cron jobs.
7
+
8
+ - [Background](https://github.com/jamesrwhite/minicron/blob/master/README.md#background)
9
+ - [Goals](https://github.com/jamesrwhite/minicron/blob/master/README.md#features)
10
+ - [Features](https://github.com/jamesrwhite/minicron/blob/master/README.md#goals)
11
+ - [Installation](https://github.com/jamesrwhite/minicron/blob/master/README.md#installation)
12
+ - [Requirements](https://github.com/jamesrwhite/minicron/blob/master/README.md#requirements)
13
+ - [Usage](https://github.com/jamesrwhite/minicron/blob/master/README.md#usage)
14
+ - [Documentation](https://github.com/jamesrwhite/minicron/blob/master/README.md#documentation)
15
+ - [Versioning](https://github.com/jamesrwhite/minicron/blob/master/README.md#versioning)
16
+ - [Contributing](https://github.com/jamesrwhite/minicron/blob/master/README.md#contributing)
17
+ - [Support](https://github.com/jamesrwhite/minicron/blob/master/README.md#support)
18
+ - [License](https://github.com/jamesrwhite/minicron/blob/master/README.md#license)
19
+
20
+ Background
21
+ -----------
22
+
23
+ I'm developing minicron as part of my dissertation at university which is due in May but I plan to continue development after that. My inspiration for developing minicron comes from time spent working at [Miniclip](http://www.miniclip.com) where the management and monitoring of cron jobs at times proved to be tricky!
24
+
25
+ Goals
26
+ ------
27
+
28
+ Some rough goals that minicron is trying to achieve.
29
+
30
+ - Remove the need to understand cron syntax
31
+ - Increase visiblity into cron failures and missed executions
32
+ - Have minimal external dependencies
33
+ - Fault tolerance
34
+
35
+ Features
36
+ ---------
37
+
38
+ - Web UI
39
+ - CRUD for cron jobs using ssh
40
+ - GUI for cron schedule create/read/update
41
+ - View realtime output/status as jobs run
42
+ - Historical data for all job executions
43
+ - Alerts when jobs executions are missed or fail via:
44
+ - Email
45
+ - SMS ([using Twilio](https://www.twilio.com))
46
+ - [PagerDuty](www.pagerduty.com)
47
+
48
+ Lots more is planned for the feature, see issues tagged [feature](https://github.com/jamesrwhite/minicron/issues?labels=feature&milestone=&page=1&state=open).
49
+
50
+ Installation
51
+ -------------
52
+
53
+ minicron is currently under heavy development and as such I would not recommend that you use this in production yet but I encourage you to give it a try in a non critical environment and help me improve it.
54
+
55
+ #### Development Install
56
+
57
+ If you wish to test the latest from GitHub version you can clone this repo ````bundle install```` and ````rake install````.
58
+
59
+ #### Released Install
60
+
61
+ To install the latest release (currently 0.1) you can ````gem install minicron````.
62
+
63
+ #### Database Setup
64
+
65
+ Set your database configuration options in ````/etc/minicron.toml```` and you can then ````minicron db setup````
66
+
67
+ > **WARNING** this will drop any existing tables in the configured database and create new ones
68
+
69
+ or set it up manually using the [schema dump provided](https://github.com/jamesrwhite/minicron/blob/master/lib/minicron/hub/db/schema.sql).
70
+
71
+ Requirements
72
+ -------------
73
+
74
+ #### Ruby
75
+ - MRI
76
+ - 1.9.3 and above (tested on 1.9.3, 2.0.0, 2.1.0)
77
+ - <del>Rubinius</del>
78
+ - <del>Travis builds are run on the latest release</del> [*awaiting bug fix*](https://github.com/rubinius/rubinius/issues/2944)
79
+ - JRuby
80
+ - As yet untested
81
+
82
+
83
+ #### Database
84
+ - MySQL
85
+ - Support for PostgreSQL and SQlite is planned in the future
86
+
87
+ #### Browser
88
+ - I have been testing the web interface in the latest versions of Chrome, Firefox and Safari. I'm currently unsure of how it functions in the various of Internet Explorer but in theory it should support IE9+
89
+
90
+ #### OS
91
+ - Should run on any linux/bsd based OS that the above ruby versions run on.
92
+ - No windows support.
93
+
94
+ Usage
95
+ -----
96
+
97
+ minicron is packaged as a gem and can be interacted with from the command line once you have installed it. The current commands are as follows:
98
+
99
+ #### Run a command
100
+
101
+ ````
102
+ minicron run 'command --options'
103
+ ````
104
+
105
+ You can alter the way in which the command alters it's output by passing the --mode option to the run argument with the value of either 'line' or 'char'. Most of the time you'll want to use the default value of line but for some commands e.g a script that outputs a progress bar minicron printing the output each character at a time can be useful.
106
+
107
+ ````
108
+ minicron run 'mysqldump db > backup.sql'
109
+ ````
110
+
111
+ The global ````--verbose```` option can also be passed to the ````run```` argument like so ````minicron run --verbose ls````, for further information see ````minicron help run````.
112
+
113
+ #### Get help
114
+
115
+ Running ````minicron```` with no arguments is an alias to running ````minicron help````, ````minicron -h```` or ````minicron --help````. You can also use the help argument to get information on any command as shown above in the run a command section or alternatively you can pass the ````-h```` or ````--help```` options like so ````minicron run -h````.
116
+
117
+ #### Server
118
+
119
+ To launch the server (aka the Hub) run ````minicron server```` - by default it will bind to port 9292 on the host 127.0.0.1 but this can be configured by the command line arguments ````--host```` ````--port```` and ````--path```` or in the config file.
120
+
121
+ See [sample.nginx.conf](https://github.com/jamesrwhite/minicron/blob/master/sample.nginx.conf) for an example of how to run minicron behind a reverse proxy. It should be possible to run minicron behind any web server/reverse proxy as long as it supports WebSockets.
122
+
123
+ #### Version
124
+
125
+ Like many command line programs minicron will show it's version number when the global options ````-v```` or ````--version```` are passed to the CLI.
126
+
127
+ #### Configuration
128
+
129
+ Some configuration options can be passed in manually but the recommend way to configure minicron is through the use of a config file. You can specify the path to the file using the ````--config```` global option. The file is expected to be in the [toml](https://github.com/mojombo/toml "toml") format. The default options are specified in the [default.config.toml](https://github.com/jamesrwhite/minicron/blob/master/default.config.toml "default.config.toml") file and minicron will parse a config located in ````/etc/minicron.toml```` if it exists. Options specified via the command line will take precedence over those taken from a config file.
130
+
131
+ Documentation
132
+ -------------
133
+
134
+ minicron uses [Yard](http://yardoc.org/ "Yard") for it's code documentation, you can either generate it and view it locally using the following commands:
135
+
136
+ ````
137
+ yard doc
138
+ yard server
139
+ ````
140
+
141
+ or view the most up to date version online at [RubyDoc.info](http://rdoc.info/github/jamesrwhite/minicron/master/frames "RubyDoc.info").
142
+
143
+ Versioning
144
+ -----------
145
+
146
+ Where possible all releases will follow the [semantic versioning](http://semver.org/) guidelines.
147
+
148
+ Releases will be numbered with the following format:
149
+
150
+ `<major>.<minor>.<patch>`
151
+
152
+ Based on the following guidelines:
153
+
154
+ * A new *major* release indicates a large change where backwards compatibility is broken.
155
+ * A new *minor* release indicates a normal change that maintains backwards compatibility.
156
+ * A new *patch* release indicates a bugfix or small change which does not affect compatibility.
157
+
158
+ Contributing
159
+ ------------
160
+
161
+ Feedback and pull requests are welcome, please see [CONTRIBUTING.md](https://github.com/jamesrwhite/minicron/blob/master/CONTRIBUTING.md "CONTRIBUTING.md") for more info.
162
+
163
+ Areas that I would love some help with:
164
+
165
+ - Any of the unassigned [issues here](https://github.com/jamesrwhite/minicron/issues?state=open).
166
+ - General testing of the system, let me know what you think and create issues for any bugs you find!
167
+ - Tests!!
168
+ - Validation and error handling improvements
169
+ - Documentation improvements. Find something confusing or unexpected, let me know and I'll add or improve documentation for it!
170
+ - Look for '[TODO:](https://github.com/jamesrwhite/minicron/search?q=TODO%3A)' notices littered around the code, I'm trying to convert them all to issues but there are a lot..
171
+ - Code refactoring, I had to have 0.1 ready by a certain deadline so some parts are far from perfect
172
+ - UI improvements
173
+
174
+ Support
175
+ --------
176
+
177
+ Where possible I will try and provide support for minicron, you can get in touch with me via:
178
+
179
+ - Twitter [@jamesrwhite](https://twitter.com/jamesrwhite)
180
+ - Email [dev.jameswhite+minicron@gmail.com](mailto:dev.jameswhite+minicron@gmail.com)
181
+
182
+ Or feel free to open an issue and I'll do my best to help.
183
+
184
+ License
185
+ --------
186
+
187
+ minicron is licensed under the GPL v3, [see here for the full license](https://github.com/jamesrwhite/minicron/blob/master/LICENSE "see here")
@@ -0,0 +1,17 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'sinatra/activerecord/rake'
4
+ require 'minicron'
5
+ require 'minicron/hub/app'
6
+
7
+ # rspec tests
8
+ desc 'Run specs'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.verbose = true
11
+ t.rspec_opts = '--color --order random'
12
+ end
13
+
14
+ # Show a list of tasks by default
15
+ task :default do
16
+ puts `rake --tasks`
17
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ require 'minicron'
3
+
4
+ begin
5
+ # Capture any output from STDERR so we can handle it how we want to
6
+ Minicron.capture_output(:type => :stderr) do
7
+ # Run the CLI and pass it all arguments passed to us
8
+ Minicron::CLI.new.run(ARGV) do |output|
9
+ print output
10
+ STDOUT.flush
11
+ end
12
+ end
13
+ # Handle ctrl-c and other nasty interruptions
14
+ rescue Interrupt, SignalException
15
+ puts "\nExiting.."
16
+ # Accept failure
17
+ rescue Exception => e
18
+ $stderr.write("#{e.message}\n")
19
+
20
+ if Minicron.config['cli']['trace']
21
+ puts
22
+ fail e
23
+ end
24
+
25
+ exit(1)
26
+ end
@@ -0,0 +1,179 @@
1
+ require 'stringio'
2
+ require 'toml'
3
+ require 'sshkey'
4
+ require 'minicron/cli'
5
+ require 'minicron/constants'
6
+
7
+ # @author James White <dev.jameswhite+minicron@gmail.com>
8
+ module Minicron
9
+ # Default configuration, this can be overriden
10
+ @config = {
11
+ 'global' => {
12
+ 'verbose' => false,
13
+ 'trace' => false
14
+ },
15
+ 'client' => {
16
+ 'scheme' => 'http',
17
+ 'host' => '127.0.0.1',
18
+ 'port' => 9292,
19
+ 'path' => '/',
20
+ 'connect_timeout' => 5,
21
+ 'inactivity_timeout' => 5
22
+ },
23
+ 'server' => {
24
+ 'host' => '127.0.0.1',
25
+ 'port' => 9292,
26
+ 'path' => '/'
27
+ },
28
+ 'database' => {
29
+ 'type' => 'mysql',
30
+ 'host' => '127.0.0.1',
31
+ 'database' => 'minicron',
32
+ 'username' => 'minicron',
33
+ 'password' => 'password'
34
+ },
35
+ 'cli' => {
36
+ 'mode' => 'line',
37
+ 'dry_run' => false
38
+ },
39
+ 'alerts' => {
40
+ 'email' => {
41
+ 'enabled' => false,
42
+ 'smtp' => {
43
+ 'address' => 'localhost',
44
+ 'port' => 25
45
+ }
46
+ },
47
+ 'sms' => {
48
+ 'enabled' => false
49
+ },
50
+ 'pagerduty' => {
51
+ 'enabled' => false
52
+ }
53
+ }
54
+ }
55
+
56
+ class << self
57
+ attr_accessor :config
58
+ end
59
+
60
+ # Parse the given config file and update the config hash
61
+ #
62
+ # @param file_path [String]
63
+ def self.parse_file_config(file_path)
64
+ file_path ||= Minicron::DEFAULT_CONFIG_FILE
65
+
66
+ begin
67
+ @config = TOML.load_file(file_path)
68
+ rescue Errno::ENOENT
69
+ # Fail if the file doesn't exist unless it's the default config file
70
+ if file_path != DEFAULT_CONFIG_FILE
71
+ fail Exception, "Unable to the load the file '#{file_path}', are you sure it exists?"
72
+ end
73
+ rescue Errno::EACCES
74
+ fail Exception, "Unable to the readthe file '#{file_path}', check it has the right permissions."
75
+ rescue TOML::ParseError
76
+ fail Exception, "An error occured parsing the config file '#{file_path}', please check it uses valid TOML syntax."
77
+ end
78
+ end
79
+
80
+ # Parses the config options from the cli
81
+ # @option options [Hash] global global options
82
+ # @option options [Hash] server server options
83
+ # @option options [Hash] cli cli options
84
+ def self.parse_cli_config(options = {})
85
+ options.each do |type, _|
86
+ options[type].each do |key, value|
87
+ if value
88
+ @config[type][key] = value
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # Helper function to capture STDOUT and/or STDERR
95
+ # adapted from http://stackoverflow.com/a/11349621/483271
96
+ #
97
+ # @option options [Symbol] type (:both) what to capture: :stdout, :stderr or :both
98
+ # @return [StringIO] if the type was set to :stdout or :stderr
99
+ # @return [Hash] containg both the StringIO instances if the type was set to :both
100
+ def self.capture_output(options = {}, &block)
101
+ # Default options
102
+ options[:type] ||= :both
103
+
104
+ # Make copies of the origin STDOUT/STDERR
105
+ original_stdout = $stdout
106
+ original_stderr = $stderr
107
+
108
+ # Which are we handling?
109
+ case options[:type]
110
+ when :stdout
111
+ $stdout = stdout = StringIO.new
112
+ when :stderr
113
+ $stderr = stderr = StringIO.new
114
+ when :both
115
+ $stderr = $stdout = stdout = stderr = StringIO.new
116
+ else
117
+ fail ArgumentError, 'The type must be one of [stdout, stderr, both]'
118
+ end
119
+
120
+ # Yield to the code block to do whatever it has to do
121
+ begin
122
+ yield
123
+ # Whatever happens make sure we reset STDOUT/STDERR
124
+ ensure
125
+ $stdout = original_stdout
126
+ $stderr = original_stderr
127
+ end
128
+
129
+ # What are we going to return?
130
+ case options[:type]
131
+ when :stdout
132
+ stdout
133
+ when :stderr
134
+ stderr
135
+ else
136
+ { :stdout => stdout, :stderr => stderr }
137
+ end
138
+ end
139
+
140
+ # Sanitize a filename - taken from http://guides.rubyonrails.org/security.html
141
+ #
142
+ # @param filename [String]
143
+ # @return [String]
144
+ def self.sanitize_filename(filename)
145
+ filename.strip.tap do |name|
146
+ name.sub!(/\A.*(\\|\/)/, '')
147
+ # Finally, replace all non alphanumeric, underscore
148
+ # or periods with underscore
149
+ name.gsub!(/[^\w\.\-]/, '_')
150
+ end
151
+
152
+ filename
153
+ end
154
+
155
+
156
+ # Used to generate SSH keys for hosts but is completely generic
157
+ #
158
+ # @param type [String] the thing that is using the key, this is just here
159
+ # so this could be used for something other than hosts if needed
160
+ # @param id [Integer]
161
+ # @param name [String]
162
+ def self.generate_ssh_key(type, id, name)
163
+ key = SSHKey.generate(:comment => "minicron public key for #{name}")
164
+
165
+ # Set the locations to save the public key private key pair
166
+ private_key_path = sanitize_filename(File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa"))
167
+ public_key_path = sanitize_filename(File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa.pub"))
168
+
169
+ # Save the public key private key pair
170
+ File.write(private_key_path, key.private_key)
171
+ File.write(public_key_path, key.ssh_public_key)
172
+
173
+ # Set the correct permissions on the files
174
+ File.chmod(0600, private_key_path)
175
+ File.chmod(0644, public_key_path)
176
+
177
+ key
178
+ end
179
+ end
@@ -0,0 +1,115 @@
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
+ module Minicron
8
+ class Alert
9
+ # Send an alert using all enabled mediums
10
+ #
11
+ # @option options [String] kind 'fail' or 'miss'
12
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
13
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
14
+ # @option options [Integer] job_id used by the #send method
15
+ # @option options [Time] expected_at only applies to 'miss' alerts
16
+ def send_all(options = {})
17
+ Minicron.config['alerts'].each do |medium, value|
18
+ # Check if the medium is enabled and alert hasn't already been sent
19
+ if value['enabled'] && !sent?(options)
20
+ send(
21
+ :kind => options[:kind],
22
+ :schedule_id => options[:schedule_id],
23
+ :execution_id => options[:execution_id],
24
+ :job_id => options[:job_id],
25
+ :expected_at => options[:expected_at],
26
+ :medium => medium
27
+ )
28
+ end
29
+ end
30
+ end
31
+
32
+ # Send an individual alert
33
+ #
34
+ # @option options [String] kind 'fail' or 'miss'
35
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
36
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
37
+ # @option options [Integer] job_id used to look up the job name for the alert message
38
+ # @option options [Time] expected_at when the schedule was expected to execute
39
+ # @option options [String] medium the medium to send the alert via
40
+ def send(options = {})
41
+ # Look up the job for this schedule
42
+ options[:job] = Minicron::Hub::Job.find(options[:job_id])
43
+
44
+ # Switch the medium that the alert will be sent via
45
+ case options[:medium]
46
+ when 'email'
47
+ send_email(options)
48
+ when 'sms'
49
+ send_sms(options)
50
+ when 'pagerduty'
51
+ send_pagerduty(options)
52
+ else
53
+ raise Exception, "The medium '#{options[:medium]}' is not supported!"
54
+ end
55
+
56
+ # Store that we sent the alert
57
+ Minicron::Hub::Alert.create(
58
+ :schedule_id => options[:schedule_id],
59
+ :execution_id => options[:execution_id],
60
+ :kind => options[:kind],
61
+ :expected_at => options[:expected_at],
62
+ :medium => options[:medium],
63
+ :sent_at => Time.now.utc
64
+ )
65
+ end
66
+
67
+ # Send an email alert, this has the same options as #send
68
+ def send_email(options = {})
69
+ email = Minicron::Email.new
70
+ email.send(
71
+ Minicron.config['alerts']['email']['from'],
72
+ Minicron.config['alerts']['email']['to'],
73
+ "minicron alert for job '#{options[:job].name}'!",
74
+ email.get_message(options)
75
+ )
76
+ end
77
+
78
+ # Send an sms alert, this has the same options as #send
79
+ def send_sms(options = {})
80
+ sms = Minicron::SMS.new
81
+ sms.send(
82
+ Minicron.config['alerts']['sms']['from'],
83
+ Minicron.config['alerts']['sms']['to'],
84
+ sms.get_message(options)
85
+ )
86
+ end
87
+
88
+ # Send a pagerduty alert, this has the same options as #send
89
+ def send_pagerduty(options = {})
90
+ pagerduty = Minicron::PagerDuty.new
91
+ pagerduty.send(
92
+ options[:kind] == 'fail' ? 'Job failed!' : 'Job missed!',
93
+ pagerduty.get_message(options)
94
+ )
95
+ end
96
+
97
+ # Queries the database to determine if an alert for this kind has already
98
+ # been sent
99
+ #
100
+ # @option options [String] kind 'fail' or 'miss'
101
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
102
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
103
+ # @option options [Time] expected_at when the schedule was expected to execute
104
+ # @option options [String] medium the medium to send the alert via
105
+ def sent?(options = {})
106
+ Minicron::Hub::Alert.exists?(
107
+ :kind => options[:kind],
108
+ :schedule_id => options[:schedule_id],
109
+ :execution_id => options[:execution_id],
110
+ :expected_at => options[:expected_at],
111
+ :medium => options[:medium]
112
+ )
113
+ end
114
+ end
115
+ end