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,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
|