minicron 0.1.0
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 +7 -0
- data/LICENSE +674 -0
- data/README.md +187 -0
- data/Rakefile +17 -0
- data/bin/minicron +26 -0
- data/lib/minicron.rb +179 -0
- data/lib/minicron/alert.rb +115 -0
- data/lib/minicron/alert/email.rb +50 -0
- data/lib/minicron/alert/pagerduty.rb +39 -0
- data/lib/minicron/alert/sms.rb +47 -0
- data/lib/minicron/cli.rb +367 -0
- data/lib/minicron/constants.rb +7 -0
- data/lib/minicron/cron.rb +192 -0
- data/lib/minicron/hub/app.rb +132 -0
- data/lib/minicron/hub/assets/app/application.js +151 -0
- data/lib/minicron/hub/assets/app/components/schedules.js +280 -0
- data/lib/minicron/hub/assets/app/controllers/executions.js +35 -0
- data/lib/minicron/hub/assets/app/controllers/hosts.js +129 -0
- data/lib/minicron/hub/assets/app/controllers/jobs.js +109 -0
- data/lib/minicron/hub/assets/app/controllers/schedules.js +80 -0
- data/lib/minicron/hub/assets/app/helpers.js +22 -0
- data/lib/minicron/hub/assets/app/models/execution.js +13 -0
- data/lib/minicron/hub/assets/app/models/host.js +15 -0
- data/lib/minicron/hub/assets/app/models/job.js +15 -0
- data/lib/minicron/hub/assets/app/models/job_execution_output.js +11 -0
- data/lib/minicron/hub/assets/app/models/schedule.js +32 -0
- data/lib/minicron/hub/assets/app/router.js +31 -0
- data/lib/minicron/hub/assets/app/routes/executions.js +36 -0
- data/lib/minicron/hub/assets/app/routes/hosts.js +42 -0
- data/lib/minicron/hub/assets/app/routes/index.js +9 -0
- data/lib/minicron/hub/assets/app/routes/jobs.js +52 -0
- data/lib/minicron/hub/assets/app/routes/schedules.js +37 -0
- data/lib/minicron/hub/assets/css/bootswatch.min.css +9 -0
- data/lib/minicron/hub/assets/css/main.scss +323 -0
- data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/minicron/hub/assets/fonts/lato-bold-700.woff +0 -0
- data/lib/minicron/hub/assets/fonts/lato-italic-400.woff +0 -0
- data/lib/minicron/hub/assets/fonts/lato-regular-400.woff +0 -0
- data/lib/minicron/hub/assets/js/ansi_up-1.1.1.min.js +6 -0
- data/lib/minicron/hub/assets/js/auth/ember-auth-9.0.7.min.js +2 -0
- data/lib/minicron/hub/assets/js/auth/ember-auth-request-jquery-1.0.3.min.js +1 -0
- data/lib/minicron/hub/assets/js/bootstrap-3.1.1.min.js +6 -0
- data/lib/minicron/hub/assets/js/ember-1.4.1.min.js +18 -0
- data/lib/minicron/hub/assets/js/ember-data-1.0.0-beta.7.f87cba88.min.js +10 -0
- data/lib/minicron/hub/assets/js/faye-browser-1.0.1.min.js +2 -0
- data/lib/minicron/hub/assets/js/handlebars-1.3.0.min.js +29 -0
- data/lib/minicron/hub/assets/js/jquery-2.1.0.min.js +4 -0
- data/lib/minicron/hub/assets/js/moment-2.5.1.min.js +7 -0
- data/lib/minicron/hub/controllers/api/executions.rb +34 -0
- data/lib/minicron/hub/controllers/api/hosts.rb +150 -0
- data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +30 -0
- data/lib/minicron/hub/controllers/api/jobs.rb +118 -0
- data/lib/minicron/hub/controllers/api/schedule.rb +184 -0
- data/lib/minicron/hub/controllers/index.rb +5 -0
- data/lib/minicron/hub/db/schema.rb +98 -0
- data/lib/minicron/hub/db/schema.sql +158 -0
- data/lib/minicron/hub/models/alert.rb +7 -0
- data/lib/minicron/hub/models/execution.rb +8 -0
- data/lib/minicron/hub/models/host.rb +7 -0
- data/lib/minicron/hub/models/job.rb +18 -0
- data/lib/minicron/hub/models/job_execution_output.rb +7 -0
- data/lib/minicron/hub/models/schedule.rb +25 -0
- data/lib/minicron/hub/serializers/execution.rb +75 -0
- data/lib/minicron/hub/serializers/host.rb +57 -0
- data/lib/minicron/hub/serializers/job.rb +104 -0
- data/lib/minicron/hub/serializers/job_execution_output.rb +48 -0
- data/lib/minicron/hub/serializers/schedule.rb +68 -0
- data/lib/minicron/hub/views/handlebars/application.erb +51 -0
- data/lib/minicron/hub/views/handlebars/errors.erb +29 -0
- data/lib/minicron/hub/views/handlebars/executions.erb +79 -0
- data/lib/minicron/hub/views/handlebars/hosts.erb +205 -0
- data/lib/minicron/hub/views/handlebars/jobs.erb +203 -0
- data/lib/minicron/hub/views/handlebars/loading.erb +3 -0
- data/lib/minicron/hub/views/handlebars/schedules.erb +354 -0
- data/lib/minicron/hub/views/index.erb +7 -0
- data/lib/minicron/hub/views/layouts/app.erb +15 -0
- data/lib/minicron/monitor.rb +116 -0
- data/lib/minicron/transport.rb +15 -0
- data/lib/minicron/transport/client.rb +80 -0
- data/lib/minicron/transport/faye/client.rb +103 -0
- data/lib/minicron/transport/faye/extensions/job_handler.rb +184 -0
- data/lib/minicron/transport/faye/server.rb +58 -0
- data/lib/minicron/transport/server.rb +62 -0
- data/lib/minicron/transport/ssh.rb +51 -0
- data/spec/invalid_config.toml +2 -0
- data/spec/minicron/cli_spec.rb +154 -0
- data/spec/minicron/transport/client_spec.rb +8 -0
- data/spec/minicron/transport/faye/client_spec.rb +53 -0
- data/spec/minicron/transport/server_spec.rb +70 -0
- data/spec/minicron/transport_spec.rb +13 -0
- data/spec/minicron_spec.rb +133 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/valid_config.toml +48 -0
- metadata +577 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'digest/md5'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Minicron
|
|
5
|
+
# The transport module deals with interactions between the server and client
|
|
6
|
+
module Transport
|
|
7
|
+
# Calculate the job hash based on the command and host
|
|
8
|
+
#
|
|
9
|
+
# @param command [String] the job command e.g 'ls -la'
|
|
10
|
+
# @param fqdn [String] the fqdn of the server running the job e.g `db1.example.com`
|
|
11
|
+
def self.get_job_hash(command, fqdn)
|
|
12
|
+
Digest::MD5.hexdigest(command + fqdn)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'minicron/transport/faye/client'
|
|
2
|
+
|
|
3
|
+
module Minicron
|
|
4
|
+
module Transport
|
|
5
|
+
class Client < Minicron::Transport::FayeClient
|
|
6
|
+
# Instantiate a new instance of the client
|
|
7
|
+
#
|
|
8
|
+
# @param host [String] The host to be communicated with
|
|
9
|
+
def initialize(scheme, host, port, path)
|
|
10
|
+
@scheme = scheme
|
|
11
|
+
@host = host
|
|
12
|
+
@path = path == '/' ? '/faye' : "#{path}/faye"
|
|
13
|
+
@port = port
|
|
14
|
+
@seq = 1
|
|
15
|
+
super(@scheme, @host, @port, @path)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Used to set up a job on the server
|
|
19
|
+
#
|
|
20
|
+
# @param job_hash [String]
|
|
21
|
+
# @param command [Integer]
|
|
22
|
+
# @param fqdn [String]
|
|
23
|
+
# @param hostname [String]
|
|
24
|
+
# @return [Hash]
|
|
25
|
+
def setup(job_hash, command, fqdn, hostname)
|
|
26
|
+
# Send a request to set up the job
|
|
27
|
+
publish("/job/#{job_hash}/status", {
|
|
28
|
+
:action => 'SETUP',
|
|
29
|
+
:command => command,
|
|
30
|
+
:fqdn => fqdn,
|
|
31
|
+
:hostname => hostname
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
# Wait for the response..
|
|
35
|
+
ensure_delivery
|
|
36
|
+
|
|
37
|
+
# TODO: Handle errors here!
|
|
38
|
+
# Get the job and execution id from the response
|
|
39
|
+
ids = JSON.parse(responses.first[:body]).first['channel'].split('/')[3]
|
|
40
|
+
|
|
41
|
+
# Split them up
|
|
42
|
+
ids = ids.split('-')
|
|
43
|
+
|
|
44
|
+
# Return them as a hash
|
|
45
|
+
{
|
|
46
|
+
:job_id => ids[0],
|
|
47
|
+
:execution_id => ids[1]
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Helper that wraps the publish function making it quicker to use
|
|
52
|
+
#
|
|
53
|
+
# @option options [String] job_id
|
|
54
|
+
# @option options [String, Symbol] type status or output
|
|
55
|
+
# @option options [Integer] execution_id
|
|
56
|
+
def send(options = {})
|
|
57
|
+
# Publish the message to the correct channel
|
|
58
|
+
publish("/job/#{options[:job_id]}/#{options[:execution_id]}/#{options[:type]}", options[:message])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Publishes a message on the given channel to the server
|
|
62
|
+
#
|
|
63
|
+
# @param channel [String]
|
|
64
|
+
# @param message [String]
|
|
65
|
+
def publish(channel, message)
|
|
66
|
+
# Set up the data to send to faye
|
|
67
|
+
data = {:channel => channel, :data => {
|
|
68
|
+
:ts => Time.now.utc.strftime("%Y-%m-%d %H:%M:%S"),
|
|
69
|
+
:message => message,
|
|
70
|
+
:seq => @seq
|
|
71
|
+
}}
|
|
72
|
+
|
|
73
|
+
# Increment the sequence id
|
|
74
|
+
@seq += 1
|
|
75
|
+
|
|
76
|
+
request({ :message => data.to_json })
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
require 'em-http-request'
|
|
3
|
+
require 'digest/md5'
|
|
4
|
+
|
|
5
|
+
module Minicron
|
|
6
|
+
module Transport
|
|
7
|
+
class FayeClient
|
|
8
|
+
attr_accessor :url
|
|
9
|
+
attr_accessor :queue
|
|
10
|
+
attr_accessor :responses
|
|
11
|
+
|
|
12
|
+
# Instantiate a new instance of the client
|
|
13
|
+
#
|
|
14
|
+
# @param scheme [String] http or https
|
|
15
|
+
# @param host [String] The host to be communicated with
|
|
16
|
+
# @param port [String] The port number the server runs on
|
|
17
|
+
# @param path [String] The path to the server, optional
|
|
18
|
+
def initialize(scheme, host, port, path) # TODO: Add options hash for other options
|
|
19
|
+
@scheme = scheme
|
|
20
|
+
@host = host
|
|
21
|
+
@path = path
|
|
22
|
+
@port = port
|
|
23
|
+
@url = "#{scheme}://#{host}:#{port}#{path}"
|
|
24
|
+
@queue = {}
|
|
25
|
+
@responses = []
|
|
26
|
+
@retries = 3
|
|
27
|
+
@retry_counts = {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Starts EventMachine in a new thread if it isn't already running
|
|
31
|
+
def ensure_em_running
|
|
32
|
+
Thread.new { EM.run } unless EM.reactor_running?
|
|
33
|
+
sleep 0.1 until EM.reactor_running?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Sends a request to the @url and adds it to the request queue
|
|
37
|
+
#
|
|
38
|
+
# @param body [String]
|
|
39
|
+
def request(body)
|
|
40
|
+
# Make sure eventmachine is running
|
|
41
|
+
ensure_em_running
|
|
42
|
+
|
|
43
|
+
# Make the request
|
|
44
|
+
req = EventMachine::HttpRequest.new(
|
|
45
|
+
@url,
|
|
46
|
+
:connect_timeout => Minicron.config['client']['connect_timeout'],
|
|
47
|
+
:inactivity_timeout => Minicron.config['client']['inactivity_timeout']
|
|
48
|
+
).post(:body => body)
|
|
49
|
+
|
|
50
|
+
# Generate an id for the request
|
|
51
|
+
req_id = Digest::MD5.hexdigest(body.to_s)
|
|
52
|
+
|
|
53
|
+
# Put the request in the queue
|
|
54
|
+
queue[req_id] = req
|
|
55
|
+
|
|
56
|
+
# Set up the retry count for this request if it didn't already exist
|
|
57
|
+
@retry_counts[req_id] ||= 0
|
|
58
|
+
|
|
59
|
+
# Did the request succeed? If so remove it from the queue
|
|
60
|
+
req.callback do
|
|
61
|
+
@responses.push({
|
|
62
|
+
:status => req.response_header.status,
|
|
63
|
+
:header => req.response_header,
|
|
64
|
+
:body => req.response
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
queue.delete(req_id)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# If not retry the request up to @retries times
|
|
71
|
+
req.errback do |error|
|
|
72
|
+
@responses.push({
|
|
73
|
+
:status => req.response_header.status,
|
|
74
|
+
:header => req.response_header,
|
|
75
|
+
:body => req.response
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
if @retry_counts[req_id] < @retries
|
|
79
|
+
@retry_counts[req_id] += 1
|
|
80
|
+
request(body)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Blocks until all messages in the sending queue have completed
|
|
86
|
+
def ensure_delivery
|
|
87
|
+
# Keep waiting until the queue is empty but only if we need to
|
|
88
|
+
if queue.length > 0
|
|
89
|
+
until queue.length == 0
|
|
90
|
+
sleep 0.05
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Tidy up after we are done with the client
|
|
98
|
+
def tidy_up
|
|
99
|
+
EM.stop
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
require 'minicron/alert'
|
|
2
|
+
require 'minicron/hub/models/host'
|
|
3
|
+
require 'minicron/hub/models/job'
|
|
4
|
+
require 'minicron/hub/models/execution'
|
|
5
|
+
require 'minicron/hub/models/job_execution_output'
|
|
6
|
+
|
|
7
|
+
module Minicron
|
|
8
|
+
module Transport
|
|
9
|
+
# An extension to the Faye server to store some of the data it receives
|
|
10
|
+
#
|
|
11
|
+
# TODO: A lot of this need more validation checks and error handling
|
|
12
|
+
# currently it's just assumed the correct data is passed and the server
|
|
13
|
+
# can crash if it isn't
|
|
14
|
+
class FayeJobHandler
|
|
15
|
+
# Called by Faye when a message is recieved
|
|
16
|
+
#
|
|
17
|
+
# @param message [Hash] The message data
|
|
18
|
+
# @param request the rack request object
|
|
19
|
+
# @param callback
|
|
20
|
+
def incoming(message, request, callback)
|
|
21
|
+
segments = message['channel'].split('/')
|
|
22
|
+
|
|
23
|
+
# Is it a job messages
|
|
24
|
+
if segments[1] == 'job'
|
|
25
|
+
data = message['data']['message']
|
|
26
|
+
|
|
27
|
+
# Is it a setup message?
|
|
28
|
+
if segments[3] == 'status' && data['action'] == 'SETUP'
|
|
29
|
+
message = handle_setup(request, message, segments)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Is it a start message?
|
|
33
|
+
if segments[4] == 'status' && data[0..4] == 'START'
|
|
34
|
+
handle_start(request, message, segments)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Is it job output?
|
|
38
|
+
if segments[4] == 'output'
|
|
39
|
+
message = handle_output(request, message, segments)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Is it a finish message?
|
|
43
|
+
if segments[4] == 'status' && data[0..5] == 'FINISH'
|
|
44
|
+
handle_finish(request, message, segments)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Is it an exit message?
|
|
48
|
+
if segments[4] == 'status' && data[0..3] == 'EXIT'
|
|
49
|
+
handle_exit(request, message, segments)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Return the message back to faye
|
|
54
|
+
callback.call(message)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Handle SETUP messages
|
|
58
|
+
#
|
|
59
|
+
# @param request the rack request object
|
|
60
|
+
# @param message [Hash] the decoded message sent with the request
|
|
61
|
+
# @param segments [Hash] the message channel split by /
|
|
62
|
+
def handle_setup(request, message, segments)
|
|
63
|
+
data = message['data']['message']
|
|
64
|
+
|
|
65
|
+
# Try and find the host
|
|
66
|
+
host = Minicron::Hub::Host.where(:fqdn => data['fqdn']).first
|
|
67
|
+
|
|
68
|
+
# Create it if it didn't exist!
|
|
69
|
+
if not host
|
|
70
|
+
host = Minicron::Hub::Host.create(
|
|
71
|
+
:name => data['hostname'],
|
|
72
|
+
:fqdn => data['fqdn'],
|
|
73
|
+
:host => request.ip
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Generate a new SSH key - TODO: add passphrase
|
|
77
|
+
key = Minicron.generate_ssh_key('host', host.id, host.fqdn)
|
|
78
|
+
|
|
79
|
+
# And finally we store the public key in te db with the host for convenience
|
|
80
|
+
Minicron::Hub::Host.where(:id => host.id).update_all(
|
|
81
|
+
:public_key => key.ssh_public_key
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Validate or create the job
|
|
86
|
+
job = Minicron::Hub::Job.where(:job_hash => segments[2]).first_or_create do |j|
|
|
87
|
+
j.job_hash = segments[2]
|
|
88
|
+
j.command = data['command']
|
|
89
|
+
j.host_id = host.id
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Create an execution for this job
|
|
93
|
+
execution = Minicron::Hub::Execution.create(
|
|
94
|
+
:job_id => job.id
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Alter the response channel to include the execution id for the
|
|
98
|
+
# client to use in later requests
|
|
99
|
+
segments[3] = "#{job.id}-#{execution.id}/status"
|
|
100
|
+
message['channel'] = segments.join('/')
|
|
101
|
+
|
|
102
|
+
# And finally return the message
|
|
103
|
+
message
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Handle START messages
|
|
107
|
+
#
|
|
108
|
+
# @param request the rack request object
|
|
109
|
+
# @param message [Hash] the decoded message sent with the request
|
|
110
|
+
# @param segments [Hash] the message channel split by /
|
|
111
|
+
def handle_start(request, message, segments)
|
|
112
|
+
data = message['data']['message']
|
|
113
|
+
|
|
114
|
+
# Update the execution and add the start time
|
|
115
|
+
Minicron::Hub::Execution.where(:id => segments[3]).update_all(
|
|
116
|
+
:started_at => data[6..-1]
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Handle job output
|
|
121
|
+
#
|
|
122
|
+
# @param request the rack request object
|
|
123
|
+
# @param message [Hash] the decoded message sent with the request
|
|
124
|
+
# @param segments [Hash] the message channel split by /
|
|
125
|
+
def handle_output(request, message, segments)
|
|
126
|
+
data = message['data']['message']
|
|
127
|
+
ts = message['data']['ts']
|
|
128
|
+
seq = message['data']['seq']
|
|
129
|
+
|
|
130
|
+
# Store the job execution output
|
|
131
|
+
output = Minicron::Hub::JobExecutionOutput.create(
|
|
132
|
+
:execution_id => segments[3],
|
|
133
|
+
:output => data,
|
|
134
|
+
:timestamp => ts,
|
|
135
|
+
:seq => seq
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Append the id to the message so we can use it on the frontend
|
|
139
|
+
message['data']['job_execution_output_id'] = output.id
|
|
140
|
+
|
|
141
|
+
# And finally return the message
|
|
142
|
+
message
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Handle FINISH messages
|
|
146
|
+
#
|
|
147
|
+
# @param request the rack request object
|
|
148
|
+
# @param message [Hash] the decoded message sent with the request
|
|
149
|
+
# @param segments [Hash] the message channel split by /
|
|
150
|
+
def handle_finish(request, message, segments)
|
|
151
|
+
data = message['data']['message']
|
|
152
|
+
|
|
153
|
+
# Update the execution and add the finish time
|
|
154
|
+
Minicron::Hub::Execution.where(:id => segments[3]).update_all(
|
|
155
|
+
:finished_at => data[7..-1]
|
|
156
|
+
)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Handle EXIT messages
|
|
160
|
+
#
|
|
161
|
+
# @param request the rack request object
|
|
162
|
+
# @param message [Hash] the decoded message sent with the request
|
|
163
|
+
# @param segments [Hash] the message channel split by /
|
|
164
|
+
def handle_exit(request, message, segments)
|
|
165
|
+
data = message['data']['message']
|
|
166
|
+
|
|
167
|
+
# Update the execution and add the exit status
|
|
168
|
+
Minicron::Hub::Execution.where(:id => segments[3]).update_all(
|
|
169
|
+
:exit_status => data[5..-1]
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# If the exit status was above 0 we need to trigger a failure alert
|
|
173
|
+
if data[5..-1].to_i > 0
|
|
174
|
+
alert = Minicron::Alert.new
|
|
175
|
+
alert.send_all(
|
|
176
|
+
:kind => 'fail',
|
|
177
|
+
:execution_id => segments[3],
|
|
178
|
+
:job_id => segments[2]
|
|
179
|
+
)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'thin'
|
|
2
|
+
require 'rack'
|
|
3
|
+
require 'faye'
|
|
4
|
+
require 'minicron/transport/faye/extensions/job_handler'
|
|
5
|
+
|
|
6
|
+
module Minicron
|
|
7
|
+
module Transport
|
|
8
|
+
class FayeServer
|
|
9
|
+
attr_reader :server
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
# Load the Faye thin adapter, this needs to happen first
|
|
13
|
+
Faye::WebSocket.load_adapter('thin')
|
|
14
|
+
|
|
15
|
+
# Show debug verbose output if requested
|
|
16
|
+
if Minicron.config['global']['verbose']
|
|
17
|
+
log = Logger.new(STDOUT)
|
|
18
|
+
log.level = Logger::DEBUG
|
|
19
|
+
Faye.logger = log
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Set up our Faye rack app
|
|
23
|
+
@server = Faye::RackAdapter.new(
|
|
24
|
+
:mount => '', # This is relative to the map faye_path set in server.rb
|
|
25
|
+
:timeout => 25
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@server.add_extension(Minicron::Transport::FayeJobHandler.new)
|
|
29
|
+
|
|
30
|
+
# Add all the events we want to listen out for
|
|
31
|
+
add_faye_events
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
def add_faye_events
|
|
36
|
+
@server.on(:handshake) do |client_id|
|
|
37
|
+
p [:handshake, client_id] if Minicron.config['global']['verbose']
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@server.on(:subscribe) do |client_id, channel|
|
|
41
|
+
p [:subscribe, client_id, channel] if Minicron.config['global']['verbose']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@server.on(:unsubscribe) do |client_id, channel|
|
|
45
|
+
p [:unsubscribe, client_id, channel] if Minicron.config['global']['verbose']
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@server.on(:publish) do |client_id, channel, data|
|
|
49
|
+
p [:published, client_id, channel, data] if Minicron.config['global']['verbose']
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@server.on(:disconnect) do |client_id|
|
|
53
|
+
p [:disconnect, client_id] if Minicron.config['global']['verbose']
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'thin'
|
|
2
|
+
require 'rack'
|
|
3
|
+
|
|
4
|
+
module Minicron
|
|
5
|
+
module Transport
|
|
6
|
+
# Used to mangage the web server minicron runs on
|
|
7
|
+
class Server
|
|
8
|
+
attr_reader :server
|
|
9
|
+
|
|
10
|
+
# Starts the thin server
|
|
11
|
+
#
|
|
12
|
+
# @param host [String] the host e.g 0.0.0.0
|
|
13
|
+
# @param port [Integer]
|
|
14
|
+
# @param path [String] The absolute path to the server e.g /server
|
|
15
|
+
def start!(host, port, path)
|
|
16
|
+
return false if running?
|
|
17
|
+
|
|
18
|
+
# Start the faye or rails apps depending on the path
|
|
19
|
+
server = Thin::Server.new(host, port) do
|
|
20
|
+
use Rack::CommonLogger
|
|
21
|
+
use Rack::ShowExceptions
|
|
22
|
+
|
|
23
|
+
# The 'hub', aka our sinatra web interface
|
|
24
|
+
map '/' do
|
|
25
|
+
require Minicron::LIB_PATH + '/minicron/hub/app'
|
|
26
|
+
use Minicron::Hub::ExceptionHandling
|
|
27
|
+
run Minicron::Hub::App.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Set the path faye should start relative to
|
|
31
|
+
faye_path = path == '/' ? '/faye' : "#{path}/faye"
|
|
32
|
+
|
|
33
|
+
# The faye server the server and browser clients talk to
|
|
34
|
+
map faye_path do
|
|
35
|
+
require Minicron::LIB_PATH + '/minicron/transport/faye/server'
|
|
36
|
+
run Minicron::Transport::FayeServer.new.server
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
server.start
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Stops the thin server if it's running
|
|
45
|
+
# @return [Boolean] whether the server was stopped or not
|
|
46
|
+
def stop!
|
|
47
|
+
return false unless running? && server != nil
|
|
48
|
+
|
|
49
|
+
server.stop
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns a bool based on whether
|
|
54
|
+
# @return [Boolean]
|
|
55
|
+
def running?
|
|
56
|
+
return false unless server != nil
|
|
57
|
+
|
|
58
|
+
server.running?
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|