minicron 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,3 @@
|
|
1
|
+
<script type="text/x-handlebars" id="loading">
|
2
|
+
<img src="data:image/gif;base64,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"/>
|
3
|
+
</script>
|
@@ -0,0 +1,354 @@
|
|
1
|
+
<script type="text/x-handlebars" id="components/schedule-editor">
|
2
|
+
<form class="form-horizontal" role="form" {{action 'save' on='submit'}}>
|
3
|
+
<div class="panel-group" id="schedule-editor">
|
4
|
+
<div class="panel panel-default">
|
5
|
+
<a data-toggle="collapse" data-parent="#schedule-editor" href="#schedule-minute">
|
6
|
+
<div class="panel-heading">
|
7
|
+
<h4 class="panel-title">Minute</h4>
|
8
|
+
</div>
|
9
|
+
</a>
|
10
|
+
<div id="schedule-minute" class="panel-collapse collapse in">
|
11
|
+
<div class="panel-body">
|
12
|
+
<ul class="nav nav-tabs">
|
13
|
+
<li class="active"><a href="#every-minute" data-toggle="tab">every minute</a></li>
|
14
|
+
<li><a href="#every-n-minutes" data-toggle="tab">every n minutes</a></li>
|
15
|
+
<li><a href="#each-selected-minute" data-toggle="tab">each selected minute</a></li>
|
16
|
+
</ul>
|
17
|
+
|
18
|
+
<div class="tab-content">
|
19
|
+
<div class="tab-pane active" id="every-minute">The job will run every minute</div>
|
20
|
+
<div class="tab-pane" id="every-n-minutes">
|
21
|
+
The job will run every <input id="every-n-minutes-value" type="number" min="1" max="59" value="5" class="every-n" {{bind-attr disabled=read_only}}></span> minutes
|
22
|
+
</div>
|
23
|
+
<div class="tab-pane" id="each-selected-minute">
|
24
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
25
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="0"/>00</label>
|
26
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="1"/>01</label>
|
27
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="2"/>02</label>
|
28
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="3"/>03</label>
|
29
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="4"/>04</label>
|
30
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="5"/>05</label>
|
31
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="6"/>06</label>
|
32
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="7"/>07</label>
|
33
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="8"/>08</label>
|
34
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="9"/>09</label>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
38
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="10"/>10</label>
|
39
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="11"/>11</label>
|
40
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="12"/>12</label>
|
41
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="13"/>13</label>
|
42
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="14"/>14</label>
|
43
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="15"/>15</label>
|
44
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="16"/>16</label>
|
45
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="17"/>17</label>
|
46
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="18"/>18</label>
|
47
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="19"/>19</label>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
51
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="20"/>20</label>
|
52
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="21"/>21</label>
|
53
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="22"/>22</label>
|
54
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="23"/>23</label>
|
55
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="24"/>24</label>
|
56
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="25"/>25</label>
|
57
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="26"/>26</label>
|
58
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="27"/>27</label>
|
59
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="28"/>28</label>
|
60
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="29"/>29</label>
|
61
|
+
</div>
|
62
|
+
|
63
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
64
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="30"/>30</label>
|
65
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="31"/>31</label>
|
66
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="32"/>32</label>
|
67
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="33"/>33</label>
|
68
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="34"/>34</label>
|
69
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="35"/>35</label>
|
70
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="36"/>36</label>
|
71
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="37"/>37</label>
|
72
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="38"/>38</label>
|
73
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="39"/>39</label>
|
74
|
+
</div>
|
75
|
+
|
76
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
77
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="40"/>40</label>
|
78
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="41"/>41</label>
|
79
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="42"/>42</label>
|
80
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="43"/>43</label>
|
81
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="44"/>44</label>
|
82
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="45"/>45</label>
|
83
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="46"/>46</label>
|
84
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="47"/>47</label>
|
85
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="48"/>48</label>
|
86
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="49"/>49</label>
|
87
|
+
</div>
|
88
|
+
|
89
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
90
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="50"/>50</label>
|
91
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="51"/>51</label>
|
92
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="52"/>52</label>
|
93
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="53"/>53</label>
|
94
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="54"/>54</label>
|
95
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="55"/>55</label>
|
96
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="56"/>56</label>
|
97
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="57"/>57</label>
|
98
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="58"/>58</label>
|
99
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="59"/>59</label>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
</div>
|
103
|
+
</div>
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
<div class="panel panel-default">
|
107
|
+
<a data-toggle="collapse" data-parent="#schedule-editor" href="#schedule-hour">
|
108
|
+
<div class="panel-heading">
|
109
|
+
<h4 class="panel-title">Hour</h4>
|
110
|
+
</div>
|
111
|
+
</a>
|
112
|
+
<div id="schedule-hour" class="panel-collapse collapse">
|
113
|
+
<div class="panel-body">
|
114
|
+
<ul class="nav nav-tabs">
|
115
|
+
<li class="active"><a href="#every-hour" data-toggle="tab">every hour</a></li>
|
116
|
+
<li><a href="#every-n-hours" data-toggle="tab">every n hours</a></li>
|
117
|
+
<li><a href="#each-selected-hour" data-toggle="tab">each selected hour</a></li>
|
118
|
+
</ul>
|
119
|
+
|
120
|
+
<div class="tab-content">
|
121
|
+
<div class="tab-pane active" id="every-hour">The job will run every hour</div>
|
122
|
+
<div class="tab-pane" id="every-n-hours">
|
123
|
+
The job will run every <input id="every-n-hours-value" type="number" min="1" max="23" value="5" class="every-n" {{bind-attr disabled=read_only}}></span> hours
|
124
|
+
</div>
|
125
|
+
<div class="tab-pane" id="each-selected-hour">
|
126
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
127
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="0"/>00</label>
|
128
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="1"/>01</label>
|
129
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="2"/>02</label>
|
130
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="3"/>03</label>
|
131
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="4"/>04</label>
|
132
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="5"/>05</label>
|
133
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="6"/>06</label>
|
134
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="7"/>07</label>
|
135
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="8"/>08</label>
|
136
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="9"/>09</label>
|
137
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="10"/>10</label>
|
138
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="11"/>11</label>
|
139
|
+
</div>
|
140
|
+
|
141
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
142
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="12"/>12</label>
|
143
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="13"/>13</label>
|
144
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="14"/>14</label>
|
145
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="15"/>15</label>
|
146
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="16"/>16</label>
|
147
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="17"/>17</label>
|
148
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="18"/>18</label>
|
149
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="19"/>19</label>
|
150
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="20"/>20</label>
|
151
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="21"/>21</label>
|
152
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="22"/>22</label>
|
153
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="23"/>23</label>
|
154
|
+
</div>
|
155
|
+
</div>
|
156
|
+
</div>
|
157
|
+
</div>
|
158
|
+
</div>
|
159
|
+
</div>
|
160
|
+
<div class="panel panel-default">
|
161
|
+
<a data-toggle="collapse" data-parent="#schedule-editor" href="#schedule-dotm">
|
162
|
+
<div class="panel-heading">
|
163
|
+
<h4 class="panel-title">Day of the month</h4>
|
164
|
+
</div>
|
165
|
+
</a>
|
166
|
+
<div id="schedule-dotm" class="panel-collapse collapse">
|
167
|
+
<div class="panel-body">
|
168
|
+
<ul class="nav nav-tabs">
|
169
|
+
<li class="active"><a href="#every-day-of-the-month" data-toggle="tab">every day of the month</a></li>
|
170
|
+
<li><a href="#each-selected-day-of-the-month" data-toggle="tab">each selected day of the month</a></li>
|
171
|
+
</ul>
|
172
|
+
|
173
|
+
<div class="tab-content">
|
174
|
+
<div class="tab-pane active" id="every-day-of-the-month">The job will run every day of the month</div>
|
175
|
+
<div class="tab-pane" id="each-selected-day-of-the-month">
|
176
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
177
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="1"/>01</label>
|
178
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="2"/>02</label>
|
179
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="3"/>03</label>
|
180
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="4"/>04</label>
|
181
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="5"/>05</label>
|
182
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="6"/>06</label>
|
183
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="7"/>07</label>
|
184
|
+
</div>
|
185
|
+
|
186
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
187
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="8"/>08</label>
|
188
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="9"/>09</label>
|
189
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="10"/>10</label>
|
190
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="11"/>11</label>
|
191
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="12"/>12</label>
|
192
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="13"/>13</label>
|
193
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="14"/>14</label>
|
194
|
+
</div>
|
195
|
+
|
196
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
197
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="15"/>15</label>
|
198
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="16"/>16</label>
|
199
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="17"/>17</label>
|
200
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="18"/>18</label>
|
201
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="19"/>19</label>
|
202
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="20"/>20</label>
|
203
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="21"/>21</label>
|
204
|
+
</div>
|
205
|
+
|
206
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
207
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="22"/>22</label>
|
208
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="23"/>23</label>
|
209
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="24"/>24</label>
|
210
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="25"/>25</label>
|
211
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="26"/>26</label>
|
212
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="27"/>27</label>
|
213
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="28"/>28</label>
|
214
|
+
</div>
|
215
|
+
|
216
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
217
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="29"/>29</label>
|
218
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="30"/>30</label>
|
219
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="31"/>31</label>
|
220
|
+
</div>
|
221
|
+
</div>
|
222
|
+
</div>
|
223
|
+
</div>
|
224
|
+
</div>
|
225
|
+
</div>
|
226
|
+
<div class="panel panel-default">
|
227
|
+
<a data-toggle="collapse" data-parent="#schedule-editor" href="#schedule-month">
|
228
|
+
<div class="panel-heading">
|
229
|
+
<h4 class="panel-title">Month</h4>
|
230
|
+
</div>
|
231
|
+
</a>
|
232
|
+
<div id="schedule-month" class="panel-collapse collapse">
|
233
|
+
<div class="panel-body">
|
234
|
+
<ul class="nav nav-tabs">
|
235
|
+
<li class="active"><a href="#every-month" data-toggle="tab">every month</a></li>
|
236
|
+
<li><a href="#each-selected-month" data-toggle="tab">each selected month</a></li>
|
237
|
+
</ul>
|
238
|
+
|
239
|
+
<div class="tab-content">
|
240
|
+
<div class="tab-pane active" id="every-month">The job will run every month</div>
|
241
|
+
<div class="tab-pane" id="each-selected-month">
|
242
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
243
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="1"/>Jan</label>
|
244
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="2"/>Feb</label>
|
245
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="3"/>Mar</label>
|
246
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="4"/>Apr</label>
|
247
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="5"/>May</label>
|
248
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="6"/>Jun</label>
|
249
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="7"/>Jul</label>
|
250
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="8"/>Aug</label>
|
251
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="9"/>Sep</label>
|
252
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="10"/>Oct</label>
|
253
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="11"/>Nov</label>
|
254
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="12"/>Dec</label>
|
255
|
+
</div>
|
256
|
+
</div>
|
257
|
+
</div>
|
258
|
+
</div>
|
259
|
+
</div>
|
260
|
+
</div>
|
261
|
+
<div class="panel panel-default">
|
262
|
+
<a data-toggle="collapse" data-parent="#schedule-editor" href="#schedule-dotw">
|
263
|
+
<div class="panel-heading">
|
264
|
+
<h4 class="panel-title">Day of week</h4>
|
265
|
+
</div>
|
266
|
+
</a>
|
267
|
+
<div id="schedule-dotw" class="panel-collapse collapse">
|
268
|
+
<div class="panel-body">
|
269
|
+
<ul class="nav nav-tabs">
|
270
|
+
<li class="active"><a href="#every-day-of-the-week" data-toggle="tab">every day of the week</a></li>
|
271
|
+
<li><a href="#each-selected-day-of-the-week" data-toggle="tab">each selected day of the week</a></li>
|
272
|
+
</ul>
|
273
|
+
|
274
|
+
<div class="tab-content">
|
275
|
+
<div class="tab-pane active" id="every-day-of-the-week">The job will run every day of the week</div>
|
276
|
+
<div class="tab-pane" id="each-selected-day-of-the-week">
|
277
|
+
<div class="btn-group clearfix" data-toggle="buttons">
|
278
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="0"/>Sun</label>
|
279
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="1"/>Mon</label>
|
280
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="2"/>Tue</label>
|
281
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="3"/>Wed</label>
|
282
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="4"/>Thu</label>
|
283
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="5"/>Fri</label>
|
284
|
+
<label class="btn btn-primary"><input type="checkbox" data-value="6"/>Sat</label>
|
285
|
+
</div>
|
286
|
+
</div>
|
287
|
+
</div>
|
288
|
+
</div>
|
289
|
+
</div>
|
290
|
+
</div>
|
291
|
+
</div>
|
292
|
+
|
293
|
+
<div class="form-group">
|
294
|
+
<hr/>
|
295
|
+
<label class="col-sm-2 control-label">Schedule</label>
|
296
|
+
<div class="col-sm-10">
|
297
|
+
{{input value=job_id type="hidden"}}
|
298
|
+
{{input value=schedule_id type="hidden"}}
|
299
|
+
<span id="schedule-input">{{input value=formatted disabled="disabled" type="text" class="form-control"}}</span>
|
300
|
+
</div>
|
301
|
+
</div>
|
302
|
+
|
303
|
+
{{#unless read_only}}
|
304
|
+
<div class="form-group">
|
305
|
+
<div class="col-sm-offset-2 col-sm-10">
|
306
|
+
<button type="submit" class="btn btn-success">Save</button>
|
307
|
+
<button {{action 'cancel' schedule}} class="btn btn-danger">Cancel</button>
|
308
|
+
</div>
|
309
|
+
</div>
|
310
|
+
{{/unless}}
|
311
|
+
</form>
|
312
|
+
</script>
|
313
|
+
|
314
|
+
<script type="text/x-handlebars" id="schedule/index">
|
315
|
+
<header class="clearfix">
|
316
|
+
<h2 class="pull-left">Schedule #{{id}} for Job '{{job.name}}'</h2>
|
317
|
+
<a {{action 'delete' this}} class="pull-right btn btn-danger btn-sm">Delete</a>
|
318
|
+
{{#link-to 'schedule.edit' id class="pull-right btn btn-warning btn-sm"}}Edit{{/link-to}}
|
319
|
+
</header>
|
320
|
+
<hr/>
|
321
|
+
|
322
|
+
{{schedule-editor
|
323
|
+
save='save'
|
324
|
+
cancel='cancel'
|
325
|
+
job_id=job.id
|
326
|
+
schedule_id=id
|
327
|
+
read_only=true}}
|
328
|
+
</script>
|
329
|
+
|
330
|
+
<script type="text/x-handlebars" id="schedules/new">
|
331
|
+
<header>
|
332
|
+
<h2>Add New Schedule for Job '{{name}}'</h2>
|
333
|
+
</header>
|
334
|
+
<hr/>
|
335
|
+
|
336
|
+
{{schedule-editor
|
337
|
+
save='save'
|
338
|
+
cancel='cancel'
|
339
|
+
job_id=id}}
|
340
|
+
</script>
|
341
|
+
|
342
|
+
<script type="text/x-handlebars" id="schedule/edit">
|
343
|
+
<header class="clearfix">
|
344
|
+
<h2 class="pull-left">Edit Schedule #{{id}} for Job '{{job.name}}'</h2>
|
345
|
+
<a {{action 'delete' this}} class="pull-right btn btn-danger btn-sm">Delete</a>
|
346
|
+
</header>
|
347
|
+
<hr/>
|
348
|
+
|
349
|
+
{{schedule-editor
|
350
|
+
save='save'
|
351
|
+
cancel='cancel'
|
352
|
+
job_id=job.id
|
353
|
+
schedule_id=id}}
|
354
|
+
</script>
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'parse-cron'
|
3
|
+
require 'minicron/hub/models/schedule'
|
4
|
+
require 'minicron/hub/models/execution'
|
5
|
+
require 'minicron/alert'
|
6
|
+
|
7
|
+
module Minicron
|
8
|
+
# Used to monitor the executions in the database and look for any failures
|
9
|
+
# or missed executions based on the schedules minicron knows about
|
10
|
+
class Monitor
|
11
|
+
def initialize
|
12
|
+
@active = false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Establishes a database connection
|
16
|
+
def setup_db
|
17
|
+
case Minicron.config['database']['type']
|
18
|
+
when 'mysql'
|
19
|
+
# Establish a database connection
|
20
|
+
ActiveRecord::Base.establish_connection({
|
21
|
+
:adapter => 'mysql2',
|
22
|
+
:host => Minicron.config['database']['host'],
|
23
|
+
:database => Minicron.config['database']['database'],
|
24
|
+
:username => Minicron.config['database']['username'],
|
25
|
+
:password => Minicron.config['database']['password']
|
26
|
+
})
|
27
|
+
else
|
28
|
+
raise Exception, "The database #{Minicron.config['database']['type']} is not supported"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Starts the execution monitor in a new thread
|
33
|
+
def start!
|
34
|
+
# Activate the monitor
|
35
|
+
@active = true
|
36
|
+
|
37
|
+
# Establish a database connection
|
38
|
+
setup_db
|
39
|
+
|
40
|
+
# Start a thread for the monitor
|
41
|
+
@thread = Thread.new do
|
42
|
+
# Delay the start of the monitor loop for a moniter so we don't immediately
|
43
|
+
# send an alert for a job the system wasn't 'up' for
|
44
|
+
sleep 60
|
45
|
+
|
46
|
+
# While the monitor is active run it in a loop ~every minute
|
47
|
+
while @active do
|
48
|
+
# Get all the schedules
|
49
|
+
schedules = Minicron::Hub::Schedule.all
|
50
|
+
|
51
|
+
# Loop every schedule we know about
|
52
|
+
schedules.each do |schedule|
|
53
|
+
begin
|
54
|
+
monitor(schedule)
|
55
|
+
rescue Exception => e
|
56
|
+
if Minicron.config['global']['trace']
|
57
|
+
puts e.message
|
58
|
+
puts e.backtrace
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
sleep 60
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Stops the execution monitor
|
69
|
+
def stop!
|
70
|
+
@active = false
|
71
|
+
@thread.join
|
72
|
+
end
|
73
|
+
|
74
|
+
# Is the execution monitor running?
|
75
|
+
def running?
|
76
|
+
@active
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Handle the monitoring of a cron schedule
|
82
|
+
#
|
83
|
+
# @param schedule [Minicron::Hub::Schedule]
|
84
|
+
def monitor(schedule)
|
85
|
+
# Get an instance of the alert class
|
86
|
+
alert = Minicron::Alert.new
|
87
|
+
|
88
|
+
# Parse the cron expression
|
89
|
+
cron = CronParser.new(schedule.formatted)
|
90
|
+
|
91
|
+
# Find the time the cron was last expected to run
|
92
|
+
expected_at = cron.last(Time.now.utc)
|
93
|
+
|
94
|
+
# We need to wait until after a minute past the expected run time
|
95
|
+
if Time.now.utc > (expected_at + 60)
|
96
|
+
# Check if this execution was created inside a minute window
|
97
|
+
# starting when it was expected to run
|
98
|
+
check = Minicron::Hub::Execution.exists?(
|
99
|
+
:created_at => expected_at..(expected_at + 60),
|
100
|
+
:job_id => schedule.job_id
|
101
|
+
)
|
102
|
+
|
103
|
+
# If the check failed
|
104
|
+
unless check
|
105
|
+
alert.send_all(
|
106
|
+
:kind => 'miss',
|
107
|
+
:schedule_id => schedule.id,
|
108
|
+
:expected_at => expected_at,
|
109
|
+
:job_id => schedule.job_id,
|
110
|
+
:expected_at => expected_at
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|