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,280 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
(function() {
|
4
|
+
// Taken from http://stackoverflow.com/a/1830844/483271
|
5
|
+
function isNumeric(value) {
|
6
|
+
return !isNaN(parseFloat(value)) && isFinite(value);
|
7
|
+
}
|
8
|
+
|
9
|
+
// Normalise expression values, such as the string equivelants of months/days
|
10
|
+
function normaliseExpressionValue(value) {
|
11
|
+
var mappings = {
|
12
|
+
'jan': '1',
|
13
|
+
'feb': '2',
|
14
|
+
'mar': '3',
|
15
|
+
'apr': '4',
|
16
|
+
'may': '5',
|
17
|
+
'jun': '6',
|
18
|
+
'jul': '7',
|
19
|
+
'aug': '8',
|
20
|
+
'sep': '9',
|
21
|
+
'oct': '10',
|
22
|
+
'nov': '11',
|
23
|
+
'dec': '12',
|
24
|
+
'sun': '0',
|
25
|
+
'mon': '1',
|
26
|
+
'tue': '2',
|
27
|
+
'wed': '3',
|
28
|
+
'thu': '4',
|
29
|
+
'fri': '5',
|
30
|
+
'sat': '6'
|
31
|
+
};
|
32
|
+
|
33
|
+
// If it was found in the mappings object return it
|
34
|
+
if (typeof mappings[value.toLowerCase()] !== 'undefined') {
|
35
|
+
return mappings[value.toLowerCase()];
|
36
|
+
}
|
37
|
+
|
38
|
+
return value;
|
39
|
+
}
|
40
|
+
|
41
|
+
// Used to parse the schedule on view load and update the GUI with those values
|
42
|
+
function parseSchedule(schedule) {
|
43
|
+
// Split the schedule into its 5 parts based on whitespace
|
44
|
+
var expression = schedule.split(' ');
|
45
|
+
|
46
|
+
// Loop every value in the expression
|
47
|
+
for (var i = 0; i < expression.length; i++) {
|
48
|
+
// If the value is '*' we don't need to do anything
|
49
|
+
if (expression[i] === '*') {
|
50
|
+
continue;
|
51
|
+
}
|
52
|
+
|
53
|
+
// Select the panel for this expression
|
54
|
+
var panel = Ember.$('#schedule-editor').find('.panel').eq(i);
|
55
|
+
|
56
|
+
// If it's a */n expression
|
57
|
+
if (expression[i].substr(0, 2) === '*/' && isNumeric(expression[i].substr(2))) {
|
58
|
+
// Show the correct tab
|
59
|
+
panel.find('.nav li:eq(1) a').tab('show');
|
60
|
+
|
61
|
+
// Set the value of the expression in the input box
|
62
|
+
panel.find('.tab-content .active input[type="number"]').val(expression[i].substr(2));
|
63
|
+
}
|
64
|
+
|
65
|
+
// If it's an each selected expression
|
66
|
+
// TODO: support range expression e.g 10-15
|
67
|
+
else if (isNumeric(expression[i]) || expression[i].split(',').length > 1 || expression[i].split('-').length > 1) {
|
68
|
+
var value,
|
69
|
+
range,
|
70
|
+
selected = [],
|
71
|
+
split_by_comma = expression[i].split(',');
|
72
|
+
|
73
|
+
// Show the correct tab
|
74
|
+
panel.find('.nav li').last().find('a').tab('show');
|
75
|
+
|
76
|
+
// If it's just a plain number add it to selected array and we're done
|
77
|
+
if (isNumeric(expression[i])) {
|
78
|
+
selected.push(expression[i]);
|
79
|
+
}
|
80
|
+
|
81
|
+
// If it's a group of values then we need to split them up and handle them
|
82
|
+
else if (split_by_comma.length > 0) {
|
83
|
+
for (var j = 0; j < split_by_comma.length; j++) {
|
84
|
+
// If it was a range expresssion convert it to a csv format
|
85
|
+
if (split_by_comma[j].split('-').length > 1) {
|
86
|
+
range = split_by_comma[j].split('-');
|
87
|
+
|
88
|
+
// Loop every value in the range and add it to the selected array
|
89
|
+
for (var pos = parseInt(range[0]); pos <= parseInt(range[1]); pos++) {
|
90
|
+
selected.push(pos.toString());
|
91
|
+
}
|
92
|
+
// If it was just a normal csv expression
|
93
|
+
} else {
|
94
|
+
selected.push(normaliseExpressionValue(split_by_comma[j]));
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// Loop every value in the selected array and 'check' it
|
100
|
+
panel.find('.tab-content .active input[type="checkbox"]').each(function(k, v) {
|
101
|
+
// Get the 'value' of the checkbox
|
102
|
+
var $this = Ember.$(this);
|
103
|
+
value = $this.data('value');
|
104
|
+
|
105
|
+
// Should it be checked?
|
106
|
+
if (selected.indexOf(value.toString()) >= 0) {
|
107
|
+
$this[0].checked = true;
|
108
|
+
$this.closest('label').addClass('active');
|
109
|
+
}
|
110
|
+
});
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
// Finally set the schedule in the schedule input textbox
|
115
|
+
updateScheduleInput(schedule);
|
116
|
+
}
|
117
|
+
|
118
|
+
// Helper to set the value of the schedule input textbox when it has been updated
|
119
|
+
function updateScheduleInput(value) {
|
120
|
+
Ember.$('#schedule-input').find('input').val(value);
|
121
|
+
}
|
122
|
+
|
123
|
+
// Called when updates made to the cron GUI, this will update the schedule record
|
124
|
+
function handleUpdate(self, $this) {
|
125
|
+
// Get the schedule
|
126
|
+
var schedule = self.get('schedule');
|
127
|
+
|
128
|
+
// The 'id' of the event which we use to defer the type
|
129
|
+
// it's either the href with the # stripped off if it's a
|
130
|
+
// tab click or the actual id attribute of the element
|
131
|
+
var id;
|
132
|
+
|
133
|
+
// If the href exists we can assume it's a tab
|
134
|
+
if (typeof $this.attr('href') !== 'undefined') {
|
135
|
+
id = $this.attr('href').substr(1);
|
136
|
+
} else {
|
137
|
+
id = $this.attr('id');
|
138
|
+
|
139
|
+
// If it's a checkbox set the id to it's parents parent
|
140
|
+
if ($this.attr('type') === 'checkbox') {
|
141
|
+
id = $this.closest('.tab-pane').attr('id');
|
142
|
+
}
|
143
|
+
|
144
|
+
// If it's a every-n-value then strip off the -value
|
145
|
+
else if (id.substr(-6) === '-value') {
|
146
|
+
id = id.substr(0, id.length - 6);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
// Define the types of schedules we are searching for
|
151
|
+
var every_n = ['every-minute', 'every-hour', 'every-day-of-the-month', 'every-month', 'every-day-of-the-week'];
|
152
|
+
var every_n_type = ['every-n-minutes', 'every-n-hours'];
|
153
|
+
|
154
|
+
// Define the key/value vars used when the change to the schedule is set
|
155
|
+
var key, value = '';
|
156
|
+
|
157
|
+
// Is it an 'every n' i.e *
|
158
|
+
if (every_n.indexOf(id) >= 0) {
|
159
|
+
// Transform the id into a key for the schedule, replace - with _
|
160
|
+
key = id.substr(6).split('-').join('_');
|
161
|
+
value = '*';
|
162
|
+
}
|
163
|
+
|
164
|
+
// Is it any 'every n type' i.e */n
|
165
|
+
else if (every_n_type.indexOf(id) >= 0) {
|
166
|
+
// Transform the id into a key for the schedule, replace - with _ and strip the trailing s
|
167
|
+
key = id.substr(8, (id.length - 1) - 8).split('-').join('_');
|
168
|
+
|
169
|
+
// Set the value using the value of the input
|
170
|
+
value = '*/' + Ember.$('#' + id + '-value').val();
|
171
|
+
}
|
172
|
+
|
173
|
+
// Otherwise we can assume it's a each selected type
|
174
|
+
else {
|
175
|
+
// Transform the id into a key for the schedule, removing the every-selected-
|
176
|
+
// and replace- with _
|
177
|
+
key = id.substr(14).split('-').join('_');
|
178
|
+
|
179
|
+
// Loop every checkbox
|
180
|
+
Ember.$('#' + id).find('input[type="checkbox"]').each(function(k, v) {
|
181
|
+
// If the checkbox is checked add the value
|
182
|
+
if (v.checked === true) {
|
183
|
+
value += Ember.$(this).data('value') + ',';
|
184
|
+
}
|
185
|
+
});
|
186
|
+
|
187
|
+
// If no value has been set i.e no checkboxes are ticked, default to *
|
188
|
+
if (value.length === 0) {
|
189
|
+
value = '*';
|
190
|
+
// Otherwise we need to remove the trailing ,
|
191
|
+
} else {
|
192
|
+
if (value.substr(-1) === ',') {
|
193
|
+
value = value.substr(0, value.length - 1);
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
// Update the schedule
|
199
|
+
console.log('setting', key, value);
|
200
|
+
schedule.set(key, value);
|
201
|
+
|
202
|
+
// Update the schedule input text box
|
203
|
+
updateScheduleInput(schedule.get('formatted'));
|
204
|
+
}
|
205
|
+
|
206
|
+
Minicron.ScheduleEditorComponent = Ember.Component.extend({
|
207
|
+
didInsertElement: function() {
|
208
|
+
this.store = this.get('targetObject.store');
|
209
|
+
var self = this;
|
210
|
+
|
211
|
+
// Do we already have the schedule id? i.e we are editing a schedule
|
212
|
+
if (this.get('schedule_id')) {
|
213
|
+
// Look up the schedule
|
214
|
+
this.store.find('schedule', this.get('schedule_id')).then(function(schedule) {
|
215
|
+
self.set('schedule', schedule);
|
216
|
+
|
217
|
+
// Parse the schedule and display it in the GUI
|
218
|
+
parseSchedule(self.get('schedule.formatted'));
|
219
|
+
});
|
220
|
+
// If not we must be adding a new schedule
|
221
|
+
} else {
|
222
|
+
// Create a default schedule record
|
223
|
+
this.set('schedule', this.store.createRecord('schedule', {
|
224
|
+
minute: '*',
|
225
|
+
hour: '*',
|
226
|
+
day_of_the_month: '*',
|
227
|
+
month: '*',
|
228
|
+
day_of_the_week: '*'
|
229
|
+
}));
|
230
|
+
|
231
|
+
// Parse the schedule and display it in the GUI
|
232
|
+
parseSchedule(this.get('schedule.formatted'));
|
233
|
+
}
|
234
|
+
|
235
|
+
// Update our reference to 'this' so we can pass it to the update handlers
|
236
|
+
self = this;
|
237
|
+
|
238
|
+
// Handle when one of the tabs or labels (checkboxes) is clicked in readonly mode
|
239
|
+
Ember.$('#schedule-editor').find('a[data-toggle="tab"], .btn-group > label').on('click', function(e) {
|
240
|
+
var $this = Ember.$(this);
|
241
|
+
|
242
|
+
if (self.get('read_only')) {
|
243
|
+
e.preventDefault();
|
244
|
+
|
245
|
+
// Is it a label (checkbox)? Then we want to stop the click event bubbling
|
246
|
+
// up the DOM so the label doesn't get highlighted
|
247
|
+
if ($this[0].nodeName === 'LABEL') {
|
248
|
+
return false;
|
249
|
+
}
|
250
|
+
} else {
|
251
|
+
// Only handle the update if it isn't a label (checkbox)
|
252
|
+
if ($this[0].nodeName !== 'LABEL') {
|
253
|
+
handleUpdate(self, $this);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
});
|
257
|
+
|
258
|
+
// Handle when one of the 'every n x' is inputs is changed
|
259
|
+
Ember.$('#schedule-editor').find('input[type="number"], input[type="checkbox"]').on('change', function(e) {
|
260
|
+
if (self.get('read_only')) {
|
261
|
+
e.preventDefault();
|
262
|
+
return false;
|
263
|
+
} else {
|
264
|
+
handleUpdate(self, Ember.$(this));
|
265
|
+
}
|
266
|
+
});
|
267
|
+
},
|
268
|
+
actions: {
|
269
|
+
save: function() {
|
270
|
+
this.sendAction('save', {
|
271
|
+
job_id: this.get('job_id'),
|
272
|
+
schedule: this.get('schedule')
|
273
|
+
});
|
274
|
+
},
|
275
|
+
cancel: function(schedule) {
|
276
|
+
this.sendAction('cancel', schedule);
|
277
|
+
}
|
278
|
+
}
|
279
|
+
});
|
280
|
+
})();
|
@@ -0,0 +1,35 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
(function() {
|
4
|
+
function deleteExecution(self, execution) {
|
5
|
+
var confirmation = "Are you sure want to delete this execution?";
|
6
|
+
|
7
|
+
if (window.confirm(confirmation)) {
|
8
|
+
// TODO: Do the same cascading delete that happens on the backend
|
9
|
+
// i.e deleting this execution also deletes the job execution output
|
10
|
+
execution.deleteRecord();
|
11
|
+
|
12
|
+
execution.save().then(function() {
|
13
|
+
self.transitionToRoute('executions');
|
14
|
+
}, function(response) {
|
15
|
+
execution.rollback();
|
16
|
+
console.log(response);
|
17
|
+
window.prompt('Error deleting execution, reason:', response.responseJSON.error);
|
18
|
+
});
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
Minicron.ExecutionIndexController = Ember.ObjectController.extend({
|
23
|
+
actions: {
|
24
|
+
delete: function(execution) {
|
25
|
+
deleteExecution(this, execution);
|
26
|
+
}
|
27
|
+
},
|
28
|
+
sortedOutput: (function() {
|
29
|
+
return Ember.ArrayProxy.createWithMixins(Ember.SortableMixin, {
|
30
|
+
sortProperties: ['seq'],
|
31
|
+
content: this.get('content.job_execution_outputs')
|
32
|
+
});
|
33
|
+
}).property('content.job_execution_outputs')
|
34
|
+
});
|
35
|
+
})();
|
@@ -0,0 +1,129 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
(function() {
|
4
|
+
function deleteHost(self, host) {
|
5
|
+
var confirmation = "Are you sure want to delete this host?\n\n";
|
6
|
+
confirmation += 'All associated data i.e jobs on this host and the jobs in this hosts crontab will be REMOVED!';
|
7
|
+
|
8
|
+
if (window.confirm(confirmation)) {
|
9
|
+
// TODO: Do the same cascading delete that happens on the backend
|
10
|
+
// i.e deleting jobs -> executions -> job_execution_outputs linked
|
11
|
+
// to this host
|
12
|
+
host.deleteRecord();
|
13
|
+
|
14
|
+
host.save().then(function() {
|
15
|
+
self.transitionToRoute('hosts');
|
16
|
+
}, function(response) {
|
17
|
+
host.rollback();
|
18
|
+
console.log(response);
|
19
|
+
window.prompt('Error deleting host, reason:', response.responseJSON.error);
|
20
|
+
});
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
function testConnection(self, host) {
|
25
|
+
self.set('test_connection', 'Testing..');
|
26
|
+
|
27
|
+
jQuery.getJSON('/api/hosts/' + host.id + '/test_ssh').done(function(data) {
|
28
|
+
// Could we at least connect to the host?
|
29
|
+
if (data.connect) {
|
30
|
+
// TODO: make this use a bootstrap model as a component
|
31
|
+
var results = 'Test Results\n\n';
|
32
|
+
results += 'connect: ' + data.connect + '\n';
|
33
|
+
results += 'crontab readable: ' + data.read + '\n';
|
34
|
+
results += 'crontab writeable: ' + data.write;
|
35
|
+
|
36
|
+
window.alert(results);
|
37
|
+
} else {
|
38
|
+
window.prompt('Failed to connect to host, reason:', data.responseJSON.error);
|
39
|
+
}
|
40
|
+
// If the actual ajax request failed
|
41
|
+
}).fail(function(xhr, status, error) {
|
42
|
+
console.log(xhr, status, error);
|
43
|
+
window.prompt('Failed to connect to API, reason:', xhr.responseJSON.error);
|
44
|
+
}).always(function() {
|
45
|
+
self.set('test_connection', 'Test Connection');
|
46
|
+
});
|
47
|
+
}
|
48
|
+
|
49
|
+
Minicron.HostsIndexController = Ember.ObjectController.extend({
|
50
|
+
actions: {
|
51
|
+
delete: function(host) {
|
52
|
+
deleteHost(this, host);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
});
|
56
|
+
|
57
|
+
Minicron.HostIndexController = Ember.ObjectController.extend({
|
58
|
+
test_connection: 'Test Connection',
|
59
|
+
actions: {
|
60
|
+
delete: function(host) {
|
61
|
+
deleteHost(this, host);
|
62
|
+
},
|
63
|
+
test: function(host) {
|
64
|
+
testConnection(this, host);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
});
|
68
|
+
|
69
|
+
Minicron.HostsNewController = Ember.Controller.extend({
|
70
|
+
actions: {
|
71
|
+
save: function() {
|
72
|
+
var self = this,
|
73
|
+
host = this.store.createRecord('host', {
|
74
|
+
name: this.get('name'),
|
75
|
+
fqdn: this.get('fqdn'),
|
76
|
+
host: this.get('host'),
|
77
|
+
port: this.get('port'),
|
78
|
+
public_key: this.get('public_key')
|
79
|
+
});
|
80
|
+
|
81
|
+
host.save().then(function(host) {
|
82
|
+
self.transitionToRoute('host', host);
|
83
|
+
// TODO: better error handling here
|
84
|
+
}).catch(function(host) {
|
85
|
+
window.alert('Error saving host!');
|
86
|
+
console.log(host);
|
87
|
+
});
|
88
|
+
},
|
89
|
+
cancel: function(host) {
|
90
|
+
this.transitionToRoute('hosts');
|
91
|
+
}
|
92
|
+
}
|
93
|
+
});
|
94
|
+
|
95
|
+
Minicron.HostEditController = Ember.ObjectController.extend({
|
96
|
+
test_connection: 'Test Connection',
|
97
|
+
actions: {
|
98
|
+
save: function() {
|
99
|
+
var self = this,
|
100
|
+
host = this.store.push('host', {
|
101
|
+
id: this.get('id'),
|
102
|
+
name: this.get('name'),
|
103
|
+
fqdn: this.get('fqdn'),
|
104
|
+
host: this.get('host'),
|
105
|
+
port: this.get('port'),
|
106
|
+
public_key: this.get('public_key')
|
107
|
+
});
|
108
|
+
|
109
|
+
host.save().then(function(host) {
|
110
|
+
self.transitionToRoute('host', host);
|
111
|
+
// TODO: better error handling here
|
112
|
+
}).catch(function(host) {
|
113
|
+
window.alert('Error saving host!');
|
114
|
+
console.log(host);
|
115
|
+
});
|
116
|
+
},
|
117
|
+
delete: function(host) {
|
118
|
+
deleteHost(this, host);
|
119
|
+
},
|
120
|
+
test: function(host) {
|
121
|
+
testConnection(this, host);
|
122
|
+
},
|
123
|
+
cancel: function(host) {
|
124
|
+
host.rollback();
|
125
|
+
this.transitionToRoute('host', host);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
});
|
129
|
+
})();
|
@@ -0,0 +1,109 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
(function() {
|
4
|
+
function deleteJob(self, job) {
|
5
|
+
var confirmation = "Are you sure want to delete this job?\n\n";
|
6
|
+
confirmation += 'All associated data will be deleted and it will be REMOVED from the host!';
|
7
|
+
|
8
|
+
if (window.confirm(confirmation)) {
|
9
|
+
// TODO: Do the same cascading delete that happens on the backend
|
10
|
+
// i.e deleting jobs -> executions -> job_execution_outputs linked
|
11
|
+
// to this job
|
12
|
+
job.deleteRecord();
|
13
|
+
|
14
|
+
job.save().then(function() {
|
15
|
+
self.transitionToRoute('jobs');
|
16
|
+
}, function(response) {
|
17
|
+
job.rollback();
|
18
|
+
console.log(response);
|
19
|
+
window.prompt('Error deleting job, reason:', response.responseJSON.error);
|
20
|
+
});
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
Minicron.JobsIndexController = Ember.ObjectController.extend({
|
25
|
+
actions: {
|
26
|
+
delete: function(job) {
|
27
|
+
deleteJob(this, job);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
});
|
31
|
+
|
32
|
+
Minicron.JobsNewController = Ember.ObjectController.extend({
|
33
|
+
save_button: 'Save',
|
34
|
+
job_name: null,
|
35
|
+
job_command: null,
|
36
|
+
actions: {
|
37
|
+
save: function() {
|
38
|
+
var self = this,
|
39
|
+
job = this.store.createRecord('job', {
|
40
|
+
name: this.get('job_name'),
|
41
|
+
command: this.get('job_command'),
|
42
|
+
});
|
43
|
+
// Let the user know the job is being saved
|
44
|
+
this.set('save_button', 'Saving..');
|
45
|
+
|
46
|
+
// Look up the host
|
47
|
+
this.store.find('host', this.get('id')).then(function(host) {
|
48
|
+
// Set the job relationship
|
49
|
+
job.set('host', host);
|
50
|
+
|
51
|
+
job.save().then(function(job) {
|
52
|
+
// Reset the save button text
|
53
|
+
self.set('save_button', 'Save');
|
54
|
+
|
55
|
+
self.transitionToRoute('job', job);
|
56
|
+
// TODO: better error handling here
|
57
|
+
}).catch(function(job) {
|
58
|
+
// Reset the save button text
|
59
|
+
self.set('save_button', 'Save');
|
60
|
+
|
61
|
+
window.alert('Error saving job!');
|
62
|
+
console.log(job);
|
63
|
+
});
|
64
|
+
});
|
65
|
+
},
|
66
|
+
cancel: function() {
|
67
|
+
this.transitionToRoute('jobs');
|
68
|
+
}
|
69
|
+
}
|
70
|
+
});
|
71
|
+
|
72
|
+
Minicron.JobIndexController = Ember.ObjectController.extend({
|
73
|
+
actions: {
|
74
|
+
delete: function(job) {
|
75
|
+
deleteJob(this, job);
|
76
|
+
},
|
77
|
+
test: function(job) {
|
78
|
+
testConnection(this, job);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
});
|
82
|
+
|
83
|
+
Minicron.JobEditController = Ember.ObjectController.extend({
|
84
|
+
actions: {
|
85
|
+
save: function() {
|
86
|
+
var self = this,
|
87
|
+
job = this.store.push('job', {
|
88
|
+
id: this.get('id'),
|
89
|
+
name: this.get('name')
|
90
|
+
});
|
91
|
+
|
92
|
+
job.save().then(function(job) {
|
93
|
+
self.transitionToRoute('job', job);
|
94
|
+
// TODO: better error handling here
|
95
|
+
}).catch(function(job) {
|
96
|
+
window.alert('Error saving job!');
|
97
|
+
console.log(job);
|
98
|
+
});
|
99
|
+
},
|
100
|
+
delete: function(job) {
|
101
|
+
deleteJob(this, job);
|
102
|
+
},
|
103
|
+
cancel: function(job) {
|
104
|
+
job.rollback();
|
105
|
+
this.transitionToRoute('job', job);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
});
|
109
|
+
})();
|