1
|
define([
|
2
|
'dojo/_base/connect',
|
3
|
'dojo/on',
|
4
|
'dijit/registry',
|
5
|
'stabile/grid',
|
6
|
'stabile/stores',
|
7
|
'stabile/formatters',
|
8
|
'steam2/models/Server',
|
9
|
'stabile/ui_update',
|
10
|
// for nodes.html
|
11
|
'dojo/parser',
|
12
|
'dijit/form/Form',
|
13
|
'dijit/form/FilteringSelect',
|
14
|
'dijit/form/Button',
|
15
|
'dojo/date',
|
16
|
'dojo/date/locale'
|
17
|
|
18
|
],function(connect, on, registry, grid, stores, formatters, Server, ui_update, parser, Form, FilteringSelect){
|
19
|
|
20
|
var sibFormatter = function (item) {
|
21
|
var sib = "";
|
22
|
if (item.status != "shutoff" && item.status != "asleep") {
|
23
|
sib += "<button type=\"button\" title=\"terminal\" class=\"action_button terminal_icon\" " +
|
24
|
"onclick=\"w = window.open('/stabile/nodes?action=terminal&mac=" + item.mac + "', '" + item.mac + "'" +
|
25
|
"); w.focus(); return false;" +
|
26
|
"\"><span>terminal</span></button>";
|
27
|
}
|
28
|
if ((item.ipmiip && item.ipmiip!="--") || (item.amtip && item.amtip!="--")) {
|
29
|
sib += " <button type=\"button\" title=\"sol\" class=\"action_button sol_icon\" " +
|
30
|
"onclick=\"w = window.open('/stabile/nodes?action=sol&mac=" + item.mac + "', 'SOL: " + item.mac + "'" +
|
31
|
"); w.focus(); return false;" +
|
32
|
"\"><span>SOL</span></button>";
|
33
|
}
|
34
|
return sib;
|
35
|
};
|
36
|
|
37
|
var nodes = {
|
38
|
_inited: false,
|
39
|
|
40
|
grid: {},
|
41
|
|
42
|
/** object name - for reflective lookup */
|
43
|
name: 'nodes',
|
44
|
|
45
|
store: null,
|
46
|
|
47
|
sortInfo: 2,
|
48
|
|
49
|
storeQuery: { mac: '*'},
|
50
|
|
51
|
structure : [
|
52
|
{
|
53
|
field: '_item',
|
54
|
name: ' ',
|
55
|
width: '60px',
|
56
|
steamid: 'terminal',
|
57
|
formatter: sibFormatter
|
58
|
},
|
59
|
{
|
60
|
field: 'name',
|
61
|
name: 'Name',
|
62
|
width: 'auto'
|
63
|
},
|
64
|
{
|
65
|
field: 'status',
|
66
|
name: 'Status',
|
67
|
width: '70px',
|
68
|
formatter: function(value, rowId){
|
69
|
var item = this.grid.getItem(rowId);
|
70
|
var heartbeat = item.timestamp * 1000; /*from secs to ms*/
|
71
|
var localized = dojo.date.locale.format(new Date(heartbeat), {formatLength: 'medium'});
|
72
|
var maintsleep = (item.maintenance && item.maintenance=='1' && value=='asleep')?' *':'';
|
73
|
return dojo.string.substitute('<span title="Heartbeat: ${0}">${1}</span>', [localized, value + maintsleep]);
|
74
|
}
|
75
|
},
|
76
|
{
|
77
|
field: 'ip',
|
78
|
name: "IP",
|
79
|
width: "80px"
|
80
|
},
|
81
|
{
|
82
|
field: 'identity',
|
83
|
name: 'Identity <a href="https://www.origo.io/info/stabiledocs/web/nodes/hypervisor" rel="help" target="_blank" class="irigo-tooltip">help</a>',
|
84
|
width: "70px"
|
85
|
},
|
86
|
{
|
87
|
field:'cpucores',
|
88
|
name:"Cores",
|
89
|
width: "40px",
|
90
|
cellStyles: "text-align:right;",
|
91
|
formatter: function(val, rowIdx, cell) {
|
92
|
var item = this.grid.getItem(rowIdx);
|
93
|
return val*item.cpucount;
|
94
|
}
|
95
|
},
|
96
|
{
|
97
|
field: 'cpuload',
|
98
|
name: "Load",
|
99
|
width: "40px",
|
100
|
cellStyles: "text-align:right;",
|
101
|
formatter: function(val, rowIdx, cell) {
|
102
|
var item = this.grid.getItem(rowIdx);
|
103
|
return ((item.status=="running" || item.status=="maintenance")?val:"--");
|
104
|
}
|
105
|
},
|
106
|
{
|
107
|
field: 'vms',
|
108
|
name: "VMs",
|
109
|
width: "32px",
|
110
|
cellStyles: "text-align:right;"
|
111
|
},
|
112
|
{
|
113
|
field: 'storfree',
|
114
|
name:"Free stor (MB)",
|
115
|
formatter: formatters.kbytes2mbs,
|
116
|
cellStyles: "text-align:right;",
|
117
|
width: "85px"
|
118
|
},
|
119
|
{
|
120
|
field: 'memfree',
|
121
|
name:"Free mem (MB)",
|
122
|
formatter: formatters.kbytes2mbs,
|
123
|
cellStyles: "text-align:right;",
|
124
|
width: "85px"
|
125
|
},
|
126
|
{
|
127
|
field: 'memtotal',
|
128
|
name: "Total mem (MB)",
|
129
|
formatter: formatters.kbytes2mbs,
|
130
|
cellStyles: "text-align:right;",
|
131
|
width: "90px"
|
132
|
},
|
133
|
{
|
134
|
field: 'action',
|
135
|
name: 'Action <a href="//www.origo.io/info/stabiledocs/web/nodes/actions" rel="help" target="_blank" class="irigo-tooltip">help</a>',
|
136
|
width: 'auto',
|
137
|
formatter: function(val, rowIdx, cell) {
|
138
|
var item = this.grid.getItem(rowIdx);
|
139
|
return nodes.getActionButtons(item);
|
140
|
}
|
141
|
}
|
142
|
],
|
143
|
|
144
|
dialogStructure : [
|
145
|
{ field: "name", name: "Name", type: "dijit.form.TextBox" },
|
146
|
{ field: "status", name: "Status", type: "dijit.form.TextBox" , attrs : {readonly :"readonly"} },
|
147
|
{ field: "mac", name: "Mac address", type: "dijit.form.TextBox" , attrs: {"readonly":"true"}},
|
148
|
{ field: "stortotal", name: "Total node storage (MB)", type: "dijit.form.TextBox" , attrs: {"disabled":"true"}},
|
149
|
{ field: "storfree", name: "Free node storage (MB)", type: "dijit.form.TextBox" , attrs: {"disabled":"true"}},
|
150
|
{ field: "ipmiip", name: "IPMI IP address", type: "dijit.form.TextBox" , attrs: {"readonly":"true"}},
|
151
|
{ field: "amtip", name: "AMT IP address", type: "dijit.form.TextBox" , attrs: {"readonly":"true"}},
|
152
|
{ field: "cpuname", name: "Cpu name", type: "dijit.form.TextBox",
|
153
|
style: "width: 200px;",
|
154
|
attrs: {"disabled":"true"} },
|
155
|
{ field: "vmvcpus", name: "Active vCPU's", type: "dijit.form.TextBox" , attrs : {readonly :"readonly"} },
|
156
|
{
|
157
|
formatter: function(node){
|
158
|
if(node.status != 'shutoff' && node.vms>0 && node.vmuuids){
|
159
|
var doms = node.vmuuids.split(/, {0,1}/);
|
160
|
var domnames = node.vmnames.split(/, {0,1}/);
|
161
|
var domusers = node.vmusers.split(/, {0,1}/);
|
162
|
var serverStandIn;
|
163
|
var serverEditLink = "";
|
164
|
for (var i in doms) {
|
165
|
//serverStandIn = {uuid:doms[i],name:domnames[i],user:domusers[i]};
|
166
|
//serverEditLink += Server.getEditDialogLink(serverStandIn) + " ";
|
167
|
serverEditLink += '<a nohref="#nodes" title="User: ' + domusers[i] + '" onclick="servers.grid.dialog.show(stores.servers.fetchItemByIdentity({identity: \'' + doms[i] + '\'}));">' + domnames[i] + '</a> ';
|
168
|
}
|
169
|
return '<td>Servers</td><td>' + serverEditLink + '</td>';
|
170
|
} else {
|
171
|
return '<td>Servers</td><td>No running servers</td>';
|
172
|
}
|
173
|
}
|
174
|
},
|
175
|
{ field: "nfsroot", name: "NFS root", type: "dijit.form.TextBox" , attrs : {readonly :"readonly"} },
|
176
|
{ field: "kernel", name: "Kernel", type: "dijit.form.TextBox" , attrs : {readonly :"readonly"} }
|
177
|
],
|
178
|
|
179
|
canSort: function(index){
|
180
|
if(index === 4){ // hypervisor
|
181
|
return false;
|
182
|
}
|
183
|
return true;
|
184
|
},
|
185
|
|
186
|
getActionButtons : function(item, include_save){
|
187
|
var type = this.name;
|
188
|
var name = item.name;
|
189
|
function actionButton(args){
|
190
|
args.name = name;
|
191
|
args.type = type;
|
192
|
return grid.actionButton(args);
|
193
|
}
|
194
|
// var store = stores.nodes;
|
195
|
|
196
|
// var id = store.getValue(item, 'mac');
|
197
|
// var status = store.getValue(item, 'status');
|
198
|
|
199
|
var id = item.mac;
|
200
|
var status = item.status;
|
201
|
var vms = item.vms;
|
202
|
var amtip = item.amtip;
|
203
|
if (!amtip || amtip === "--") amtip = item.ipmiip;
|
204
|
|
205
|
var delete_button = (item.identity=='local_kvm')?'':actionButton({'action':"delete", 'id':id, 'confirm':true});
|
206
|
var reboot_button = (item.identity=='local_kvm')?'':actionButton({'action':"reboot", 'id':id});
|
207
|
var shutdown_button = (item.identity=='local_kvm')?'':actionButton({'action':"shutdown", 'id':id});
|
208
|
var reset_button = actionButton({'action':"reset", 'id':id, 'confirm':true});
|
209
|
var unjoin_button = (item.identity=='local_kvm')?'':actionButton({'action':"unjoin", 'id':id});
|
210
|
var reload_button = actionButton({'action':"reload", 'id':id});
|
211
|
var sleep_button = (item.identity=='local_kvm')?'':actionButton({'action':"sleep", 'id':id});
|
212
|
var wake_button = (item.identity=='local_kvm')?'':actionButton({'action':"wake", 'id':id});
|
213
|
var maintenance_button = actionButton({'action':"maintenance", 'id':id});
|
214
|
var carryon_button = actionButton({'action':"carryon", 'id':id});
|
215
|
var evacuate_button = actionButton({'action':"evacuate", 'id':id});
|
216
|
var save = include_save ? grid.saveButton(type) : "";
|
217
|
var buttons = "";
|
218
|
|
219
|
if(status === "running"){
|
220
|
if (vms == 0) {
|
221
|
buttons += reboot_button;
|
222
|
buttons += shutdown_button;
|
223
|
buttons += unjoin_button;
|
224
|
buttons += sleep_button;
|
225
|
}
|
226
|
buttons += reload_button;
|
227
|
buttons += maintenance_button;
|
228
|
}
|
229
|
else if(status === "shutdown"){
|
230
|
buttons += wake_button;
|
231
|
buttons += delete_button;
|
232
|
if (amtip && amtip!="--") buttons += reset_button;
|
233
|
}
|
234
|
else if(status === "inactive"){
|
235
|
buttons += wake_button;
|
236
|
buttons += delete_button;
|
237
|
if (amtip && amtip!="--") buttons += reset_button;
|
238
|
// buttons += maintenance_button;
|
239
|
}
|
240
|
else if(status === "asleep"){
|
241
|
buttons += wake_button;
|
242
|
}
|
243
|
else if(status === "maintenance"){
|
244
|
if (vms == 0) {
|
245
|
buttons += reboot_button;
|
246
|
buttons += shutdown_button;
|
247
|
buttons += unjoin_button;
|
248
|
buttons += sleep_button;
|
249
|
if (amtip && amtip!="--") buttons += reset_button;
|
250
|
} else {
|
251
|
buttons += evacuate_button;
|
252
|
}
|
253
|
buttons += reload_button;
|
254
|
buttons += carryon_button;
|
255
|
}
|
256
|
else if(status === "reboot"){
|
257
|
buttons += delete_button;
|
258
|
}
|
259
|
else if(status === "waking"){
|
260
|
buttons += '<img height="18px" alt="waking" src="/stabile/static/img/loader.gif"></img>';
|
261
|
buttons += delete_button;
|
262
|
if (amtip && amtip!="--") buttons += reset_button;
|
263
|
}
|
264
|
else if(status === "sleeping"){
|
265
|
buttons += '<img height="18px" alt="waking" src="/stabile/static/img/loader.gif"></img>';
|
266
|
buttons += delete_button;
|
267
|
if (amtip && amtip!="--") buttons += reset_button;
|
268
|
}
|
269
|
else if(status === "shuttingdown"){
|
270
|
buttons += '<img height="18px" alt="waking" src="/stabile/static/img/loader.gif"></img>';
|
271
|
buttons += delete_button;
|
272
|
if (amtip && amtip!="--") buttons += reset_button;
|
273
|
}
|
274
|
else if(status === "joining" || status === "unjoining" || status === "unjoin" || status === "reload" || status === "reloading"){
|
275
|
buttons += '<img height="18px" alt="waking" src="/stabile/static/img/loader.gif"></img>';
|
276
|
buttons += delete_button;
|
277
|
if (amtip && amtip!="--") buttons += reset_button;
|
278
|
}
|
279
|
|
280
|
else{
|
281
|
console.error("unknown status", status);
|
282
|
}
|
283
|
buttons += save;
|
284
|
return buttons;
|
285
|
},
|
286
|
|
287
|
onPostRender: function(){
|
288
|
//nodes.updateSums();
|
289
|
// FIXME: item not loaded when servers dialog is used before this...
|
290
|
// uncommenting for now
|
291
|
//console.log(dijit.byId('defaultidentity'));
|
292
|
//nodes.setDefaultNodeIdentity(dijit.byId('defaultidentity').item, stores.nodeIdentities);
|
293
|
nodes.setDefaultNodeIdentity();
|
294
|
},
|
295
|
|
296
|
onDialogButtons : function(item){
|
297
|
var stortotal_field = dijit.byId('stortotal');
|
298
|
var stortotal = this.store.getValue(item, 'stortotal');
|
299
|
stortotal_field.set('value', formatters.kbytes2mbs(stortotal));
|
300
|
var storfree_field = dijit.byId('storfree');
|
301
|
var storfree = this.store.getValue(item, 'storfree');
|
302
|
storfree_field.set('value', formatters.kbytes2mbs(storfree));
|
303
|
}
|
304
|
};
|
305
|
|
306
|
nodes.setDefaultNodeIdentity = function(){
|
307
|
// summary: gets the default node identity and sets the value
|
308
|
// of the filtering select.
|
309
|
|
310
|
var nodeIdtyFilteringSelect = registry.byId('defaultidentity');
|
311
|
// If dojo not been initialized, i.e. we are loading via jQuery
|
312
|
if (typeof nodeIdtyFilteringSelect == 'undefined') {
|
313
|
nodeIdtyFilteringSelect = new FilteringSelect({
|
314
|
id: "defaultidentity",
|
315
|
name: "defaultidentity",
|
316
|
store: stores.nodeIdentities,
|
317
|
searchAttr: "name"
|
318
|
}, "defaultidentity").startup();
|
319
|
};
|
320
|
|
321
|
var nodeSleepAfterFilteringSelect = dijit.byId('sleepafter');
|
322
|
if (typeof nodeSleepAfterFilteringSelect == 'undefined') {
|
323
|
nodeSleepAfterFilteringSelect = new FilteringSelect({
|
324
|
id: "sleepafter",
|
325
|
name: "sleepafter"
|
326
|
}, "sleepafter").startup(function(){console.log("started...");});
|
327
|
};
|
328
|
|
329
|
stores.nodeIdentities.fetch({
|
330
|
query: {identity:'default'},
|
331
|
onItem: function(defaultItem){
|
332
|
nodeIdtyFilteringSelect.set('value', defaultItem.id);
|
333
|
nodeIdtyFilteringSelect.set('disabled', false);
|
334
|
|
335
|
nodeSleepAfterFilteringSelect.set('value', defaultItem.sleepafter);
|
336
|
nodeSleepAfterFilteringSelect.set('disabled', false);
|
337
|
}
|
338
|
});
|
339
|
};
|
340
|
|
341
|
nodes.saveDefaultNodeIdentity = function(){
|
342
|
var sleepafter = dijit.byId("sleepafter").value;
|
343
|
var hypervisorId = dijit.byId('defaultidentity').get('displayedValue');
|
344
|
dojo.xhrGet(
|
345
|
{
|
346
|
url: "/stabile/nodes?action=setdefaultnodeidentity&hid=" + hypervisorId + "&sleepafter=" + sleepafter,
|
347
|
load: function(response) {
|
348
|
// FIXME: clean up this when ready at the server side
|
349
|
IRIGO.toaster([{
|
350
|
message: response,
|
351
|
type: "message",
|
352
|
duration: 5000
|
353
|
}
|
354
|
]);
|
355
|
stores.nodeIdentities.close();
|
356
|
nodes.setDefaultNodeIdentity();
|
357
|
}
|
358
|
});
|
359
|
};
|
360
|
|
361
|
|
362
|
|
363
|
nodes.init = function(){
|
364
|
if (nodes._inited === true) return;
|
365
|
else nodes._inited = true;
|
366
|
|
367
|
this.setDefaultNodeIdentity();
|
368
|
|
369
|
nodes.store = stores.nodes;
|
370
|
nodes.domnode = "nodes-grid";
|
371
|
nodes.grid = grid.create(nodes);
|
372
|
nodes.grid.startup();
|
373
|
|
374
|
function handleSelectNodesTab(e){
|
375
|
if(e.id == 'nodes'){
|
376
|
nodes.grid.refresh();
|
377
|
}
|
378
|
}
|
379
|
dojo.subscribe('tabContainer-selectChild', null, handleSelectNodesTab);
|
380
|
|
381
|
dojo.subscribe("nodes:update", function(task){
|
382
|
if (task.uuid || task.mac) nodes.grid.refreshRow(task);
|
383
|
else nodes.grid.refresh();
|
384
|
});
|
385
|
|
386
|
connect.connect(this.grid, '_onFetchComplete', this, function(rows){
|
387
|
this.updateSums(rows);
|
388
|
});
|
389
|
|
390
|
};
|
391
|
|
392
|
nodes.updateSums = function() {
|
393
|
dojo.xhrGet({
|
394
|
url : "/stabile/nodes?action=stats",
|
395
|
handleAs : "json",
|
396
|
load : function(response, ioArgs) {
|
397
|
/* Handle a successful callback here */
|
398
|
//alert (100*response.cpuloadavg);
|
399
|
var memf = 0;
|
400
|
if (response.memtotalsum > 0) memf = 100-100*response.memfreesum / response.memtotalsum;
|
401
|
//if (dogauge) updateGauges(memf, 100*response.cpuloadavg, 100*response.storused/(response.storused+response.storfree));
|
402
|
var statssummary =
|
403
|
"Nodes: " + response.avgs.nodestotal + "  Cores: " + response.avgs.corestotal + "  Memory: " +
|
404
|
Math.round((response.avgs.memtotalsum - response.avgs.memfreesum)/1024) + " (" + Math.round(response.avgs.memtotalsum/1024) + ") MB"
|
405
|
" Load: " + Math.round(response.avgs.cpuloadavg*100)/100;
|
406
|
var storsummary = response.stortext;
|
407
|
|
408
|
document.getElementById("statsbox").innerHTML = statssummary;
|
409
|
document.getElementById("storagestatsbox").innerHTML = storsummary;
|
410
|
return response;
|
411
|
},
|
412
|
error : function(response, ioArgs) {
|
413
|
console.log("An error occurrerd.", response, ioArgs);
|
414
|
//return response;
|
415
|
}
|
416
|
});
|
417
|
}
|
418
|
|
419
|
window.nodes = nodes;
|
420
|
return nodes;
|
421
|
});
|
422
|
|
423
|
|
424
|
|
425
|
|