1
|
define([
|
2
|
"dojo/_base/connect",
|
3
|
'dojo/on',
|
4
|
'dojo/dom',
|
5
|
'dojo/dom-construct',
|
6
|
'steam2/models/Server',
|
7
|
'steam2/statusColorMap',
|
8
|
'steam2/user',
|
9
|
'stabile/grid',
|
10
|
'stabile/stores',
|
11
|
'stabile/formatters',
|
12
|
'helpers/uuid',
|
13
|
'dojox/grid/cells/_base',
|
14
|
'dojo/string',
|
15
|
'dijit/form/Button',
|
16
|
'dijit/layout/BorderContainer',
|
17
|
'dijit/form/NumberSpinner'
|
18
|
|
19
|
], function(connect, on, dom, domConstruct, Server, statusColorMap, user, grid, stores){
|
20
|
|
21
|
var guacFormatter = function (item) {
|
22
|
if (item.status != "shutoff" && item.status != "inactive" && item.display == "vnc") {
|
23
|
var guac = "<button type=\"button\" title=\"console\" class=\"action_button console_icon\" " +
|
24
|
"onclick=\"steam2.models.Server.doAction(arguments[0], '" + item.uuid + "','start_html5_vnc_viewer');return false;" +
|
25
|
// "onclick=\"w = window.open('/guacamole/?uuid=" + item.uuid + "', '" + item.uuid + "'" +
|
26
|
// ",'" + "menubar=no,status=no,toolbar=no,addressbar=no,location=no,titlebar=no')" +
|
27
|
// "); w.focus(); return false;" +
|
28
|
"\"><span>console</span></button>";
|
29
|
return guac;
|
30
|
} else {
|
31
|
return "";
|
32
|
}
|
33
|
};
|
34
|
|
35
|
var servers = {
|
36
|
|
37
|
grid : {},
|
38
|
_searchQuery: "name:*",
|
39
|
_statusQuery: "status:all",
|
40
|
_inited: false,
|
41
|
storeQuery: "name:*",
|
42
|
model : function(args){
|
43
|
return dojo.mixin({
|
44
|
uuid: Math.uuid().toLowerCase(),
|
45
|
name: "",
|
46
|
user: user.username,
|
47
|
memory: "2048",
|
48
|
vcpu: "1",
|
49
|
image: "",
|
50
|
image2: "",
|
51
|
diskbus: "virtio",
|
52
|
cdrom: "--",
|
53
|
boot: "hd",
|
54
|
networkuuid1: "--",
|
55
|
nicmodel1: "virtio",
|
56
|
//nicmodel1: "rtl8139",
|
57
|
networkuuid2: "--",
|
58
|
// nicmodel2: ["rtl8139"],
|
59
|
status: "new",
|
60
|
mac: "",
|
61
|
port: 0
|
62
|
}, args || {});
|
63
|
},
|
64
|
|
65
|
// TODO: refactor should be on the model!
|
66
|
isPowered: function(item){
|
67
|
switch(item.status){
|
68
|
case "shutoff":
|
69
|
case "new":
|
70
|
case "inactive":
|
71
|
case "crashed":
|
72
|
case "destroying":
|
73
|
return false;
|
74
|
case "starting":
|
75
|
if(item.port && item.port){
|
76
|
return true;
|
77
|
}
|
78
|
// vnc is not ready here
|
79
|
return false;
|
80
|
default:
|
81
|
return true;
|
82
|
}
|
83
|
},
|
84
|
|
85
|
/** object name - for reflective lookup */
|
86
|
name : "servers",
|
87
|
store : null,
|
88
|
sortInfo: 3,
|
89
|
structure : [
|
90
|
{
|
91
|
field: '_item',
|
92
|
name: ' ',
|
93
|
width: '30px',
|
94
|
steamid: 'console',
|
95
|
formatter: guacFormatter,
|
96
|
hidden: user.is_readonly
|
97
|
},
|
98
|
{
|
99
|
field: 'name',
|
100
|
name: 'Name',
|
101
|
width: 'auto'
|
102
|
},
|
103
|
{
|
104
|
field: 'status',
|
105
|
name: 'Status <a href="https://www.origo.io/info/stabiledocs/web/servers/status" rel="help" target="_blank" class="irigo-tooltip">help</a>',
|
106
|
width: '100px',
|
107
|
formatter: function(val, rowIdx, cell) {
|
108
|
var t = '<span style="color:${color}">${val}</span>';
|
109
|
var color = statusColorMap.get(val);
|
110
|
// if(val != "inactive" && user.is_admin){
|
111
|
if(user.is_admin){
|
112
|
var store = this.grid.store;
|
113
|
var item = this.grid.getItem(rowIdx);
|
114
|
if (store.getValue(item, 'macname') && store.getValue(item, 'macname')!="--") {
|
115
|
val += " on " + store.getValue(item, 'macname');
|
116
|
}
|
117
|
}
|
118
|
return dojo.string.substitute(t, { color: color, val: val });
|
119
|
}
|
120
|
},
|
121
|
{
|
122
|
field: 'memory',
|
123
|
name: 'Mem (MB)',
|
124
|
width: '64px',
|
125
|
cellStyles: "text-align:right;",
|
126
|
type: dojox.grid.cells.Select,
|
127
|
options: ["256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "49152", "65536"]
|
128
|
},
|
129
|
{
|
130
|
field: 'vcpu',
|
131
|
name: 'VCPUs',
|
132
|
width: '48px',
|
133
|
cellStyles: "text-align:right;",
|
134
|
// editable:true,
|
135
|
type: dojox.grid.cells.Select,
|
136
|
options: ["1","2","3","4","8"]
|
137
|
},
|
138
|
{
|
139
|
field: 'imagename',
|
140
|
name: 'Image',
|
141
|
width: 'auto' },
|
142
|
{
|
143
|
field: 'imagetype',
|
144
|
name: 'Type',
|
145
|
width: '40px'
|
146
|
},
|
147
|
// { field: 'diskbus', name: 'Bus', width: '40px',
|
148
|
// editable: true,
|
149
|
// type: dojox.grid.cells.Select,
|
150
|
// options: ["ide", "scsi"]
|
151
|
// },
|
152
|
{
|
153
|
field: 'networkname1',
|
154
|
name: 'Connection',
|
155
|
width: '140px'
|
156
|
},
|
157
|
{
|
158
|
field: 'action',
|
159
|
name: 'Action <a href="https://www.origo.io/info/stabiledocs/web/servers/server-actions" rel="help" target="_blank" class="irigo-tooltip">help</a>',
|
160
|
width: 'auto',
|
161
|
formatter: function(val, rowIdx, cell) {
|
162
|
var item = this.grid.getItem(rowIdx);
|
163
|
return servers.getActionButtons(item);
|
164
|
},
|
165
|
hidden: user.is_readonly
|
166
|
}
|
167
|
],
|
168
|
|
169
|
dialogStructure : [
|
170
|
{
|
171
|
field:"name",
|
172
|
name: "Name",
|
173
|
type:"dijit.form.ValidationTextBox",
|
174
|
//attrs: {regExp: "[\\s\\w.-]+", required:true}
|
175
|
// attrs: {regExp: ".+", required:true, readonly: (user.is_readonly?"readonly":false)}
|
176
|
attrs: {regExp: ".+", required:false}
|
177
|
},
|
178
|
{
|
179
|
field: "status",
|
180
|
name: "Status",
|
181
|
type: "dijit.form.TextBox",
|
182
|
attrs: {readonly:"readonly"}
|
183
|
},
|
184
|
{
|
185
|
field: "uuid",
|
186
|
name: "UUID",
|
187
|
type: "dijit.form.TextBox",
|
188
|
attrs: {readonly:"readonly"}
|
189
|
},
|
190
|
// hmm. dijit.form.Select doesn't do any selection on the value from the item???
|
191
|
// Apparently the values must be of type string to do that.
|
192
|
// It works with filtering select
|
193
|
{
|
194
|
field:"memory",
|
195
|
name: "Memory",
|
196
|
type: "dijit.form.FilteringSelect",
|
197
|
style: "width: 55px;",
|
198
|
attrs: { store: "stores.memory", searchAttr:"memory" }
|
199
|
},
|
200
|
{
|
201
|
field:"vcpu",
|
202
|
name: "VCPUs",
|
203
|
type:"dijit.form.NumberSpinner",
|
204
|
style: "width: 55px;",
|
205
|
attrs:{ smallDelta:"1", constraints: "{min:1,max:8,places:0}"}
|
206
|
},
|
207
|
{
|
208
|
field:"diskbus",
|
209
|
name:"Bus",
|
210
|
type: "dijit.form.Select",
|
211
|
attrs:{ store: "stores.diskbus", searchAttr:"type" }
|
212
|
},
|
213
|
{
|
214
|
field:"cdrom",
|
215
|
name:"CD-rom",
|
216
|
type: "dijit.form.FilteringSelect",
|
217
|
extra: function(item){
|
218
|
return '<button type="button" id="mount_button" class="btn btn-xs btn-info" onclick="servers.mount()" style="font-size:80%; display:none;">Mount</button>';
|
219
|
},
|
220
|
attrs:{
|
221
|
store: "stores.cdroms", searchAttr:"name",
|
222
|
onChange: "if ((this.value != servers.grid.dialog.item.cdrom || this.value=='--') && servers.grid.dialog.item.status=='running') {" +
|
223
|
"$('#mount_button').text((this.value=='--')?'Unmount':'Mount').show(); }" +
|
224
|
"else {$('#mount_button').hide();};"
|
225
|
}
|
226
|
},
|
227
|
{
|
228
|
field:"boot",
|
229
|
name:"Boot",
|
230
|
type: "dijit.form.Select",
|
231
|
attrs:{store: "stores.bootDevices", searchAttr:"name"}
|
232
|
},
|
233
|
{
|
234
|
field: "user",
|
235
|
name: "User",
|
236
|
type: "dijit.form.FilteringSelect",
|
237
|
attrs: {
|
238
|
store: "stores.accounts",
|
239
|
searchAttr: "id",
|
240
|
required:"true",
|
241
|
query: "{privileges: /(a|u)/}"
|
242
|
// onChange: "stores.accounts.fetch({query: {privileges:'*m*'}}); stores.accounts.close();"
|
243
|
}
|
244
|
},
|
245
|
{
|
246
|
field:"mac",
|
247
|
name:'<span id="serverDialogNodeDialogLink">Node</span>',
|
248
|
type: "dijit.form.FilteringSelect",
|
249
|
restricted: true,
|
250
|
extra: function(item){
|
251
|
return '<button type="button" id="move_button" class="btn btn-xs btn-info" onclick="servers.move()" style="font-size:80%; display:none;">Move</button>';
|
252
|
},
|
253
|
attrs:{
|
254
|
store: "stores.nodes", searchAttr:"name", required: false,
|
255
|
onChange: "if (this.value != servers.grid.dialog.item.mac && servers.grid.dialog.item.status=='running')" +
|
256
|
" $('#move_button').show();" +
|
257
|
" else $('#move_button').hide();"
|
258
|
}
|
259
|
},
|
260
|
{
|
261
|
field: "locktonode",
|
262
|
name:"Lock to node",
|
263
|
type: "dijit.form.CheckBox",
|
264
|
restricted: true,
|
265
|
attrs:{onchange: "this.value=this.checked?'true':'false';"}
|
266
|
},
|
267
|
{
|
268
|
field:"image",
|
269
|
name:'<span id="serverDialogImageDialogLink">Image</a>',
|
270
|
type:"dijit.form.Select",
|
271
|
help: "servers/image",
|
272
|
attrs: {
|
273
|
store: "stores.unusedImages",
|
274
|
searchAttr: "name",
|
275
|
required:true,
|
276
|
onChange: "suffix=this.value.substr(this.value.lastIndexOf('.')+1); " +
|
277
|
"stores.nodeIdentities.fetch({query: {formats:'*' +suffix+ '*'}, onComplete: servers.updateNetworkInterfaces});"
|
278
|
}
|
279
|
},
|
280
|
{
|
281
|
field:"image2",
|
282
|
name:'<span id="serverDialogImage2DialogLink">Image2</span>',
|
283
|
type:"dijit.form.Select",
|
284
|
help: "servers/image-2",
|
285
|
attrs: {store: "stores.unusedImages2", searchAttr: "name"}
|
286
|
},
|
287
|
{
|
288
|
field: "networkuuid1",
|
289
|
name:'<span id="serverDialogNetwork1DialogLink">Connection</span>',
|
290
|
type: "dijit.form.Select",
|
291
|
required:true,
|
292
|
help: "servers/connection",
|
293
|
attrs: {store:"stores.unusedNetworks", searchAttr: "name"}
|
294
|
},
|
295
|
{
|
296
|
field: "networkuuid2",
|
297
|
name: '<span id="serverDialogNetwork2DialogLink">Connection2</span>',
|
298
|
type: "dijit.form.Select",
|
299
|
attrs: {store:"stores.unusedNetworks2", searchAttr: "name"}
|
300
|
},
|
301
|
{
|
302
|
field: "nicmodel1",
|
303
|
name:"NIC model",
|
304
|
type: "dijit.form.Select",
|
305
|
help: "servers/network-interface",
|
306
|
attrs: {store:"stores.networkInterfaces", searchAttr: "type", query: "{hypervisor: '*'}"}
|
307
|
},
|
308
|
{
|
309
|
field: "autostart",
|
310
|
name:"Auto-start",
|
311
|
type: "dijit.form.CheckBox",
|
312
|
restricted: true,
|
313
|
attrs:{onchange: "this.value=this.checked?'true':'false';"}
|
314
|
},
|
315
|
{
|
316
|
// HTML5 console
|
317
|
formatter: function(item){
|
318
|
if(item.status == "new" || user.is_readonly){
|
319
|
return "";
|
320
|
}
|
321
|
if(item.status != "new" && item.status != "shutoff" && item.status != "inactive" && item.macname){
|
322
|
return '<td><div>Console</div></td><td><div>' + guacFormatter(item) + '</div></td>';
|
323
|
} else {
|
324
|
return "";
|
325
|
}
|
326
|
}
|
327
|
},
|
328
|
/*
|
329
|
{
|
330
|
// tunnel - obsolete, disabled
|
331
|
formatter: function(item){
|
332
|
if(true || item.status == "new"){
|
333
|
return "";
|
334
|
}
|
335
|
|
336
|
var server = new steam2.models.Server(item);
|
337
|
|
338
|
var start = '<button type="button" id="tunnelStartButton" onclick="return false;" title="Start" class="action_button start_icon"><span>start</span></button>',
|
339
|
stop = '<button type="button" id="tunnelStopButton" onclick="return false;" title="Stop" class="action_button shutdown_icon"><span>stop</span></button>',
|
340
|
display = stores.servers.getValue(item, "display");
|
341
|
|
342
|
function getArgs(){
|
343
|
return {
|
344
|
remote_ip: item.macip,
|
345
|
remote_port: item.port,
|
346
|
host: window.location.host,
|
347
|
username: "irigo-" + user.get()
|
348
|
};
|
349
|
}
|
350
|
|
351
|
function addStartTunnelClickHandler(){
|
352
|
dojo.query('#tunnelStartButton').onclick(function(){
|
353
|
server._startTunnel();
|
354
|
return false;
|
355
|
});
|
356
|
}
|
357
|
|
358
|
function addStopTunnelClickHandler(){
|
359
|
dojo.query('#tunnelStopButton').onclick(function(){
|
360
|
server._stopTunnel();
|
361
|
return false;
|
362
|
});
|
363
|
}
|
364
|
|
365
|
// should be something like jquery live
|
366
|
dojo.connect(servers.grid, 'onDialog', function(){
|
367
|
addStopTunnelClickHandler();
|
368
|
addStartTunnelClickHandler();
|
369
|
});
|
370
|
|
371
|
dojo.connect(server, 'onTunnelConnect', function(){
|
372
|
if (dojo.byId('tunnelStatus')) dojo.byId('tunnelStatus').innerHTML = "Active ";
|
373
|
if (dojo.byId('tunnelButton')) dojo.byId('tunnelButton').innerHTML = stop;
|
374
|
if (dojo.byId('appletLabel')) dojo.byId("appletLabel").innerHTML = '<a href="' + display + '://127.0.0.1:' + server._tunnel.local_port + '">Java console</a>';
|
375
|
// // In dojo 1.6, the jquery.live is availble
|
376
|
// // change to that when available
|
377
|
addStopTunnelClickHandler();
|
378
|
});
|
379
|
|
380
|
dojo.connect(server, 'onTunnelDisconnect', function(){
|
381
|
if (dojo.byId('tunnelStatus')) dojo.byId('tunnelStatus').innerHTML = "Inactive ";
|
382
|
if (dojo.byId('tunnelButton')) dojo.byId('tunnelButton').innerHTML = start;
|
383
|
if (dojo.byId('appletLabel')) dojo.byId("appletLabel").innerHTML = "Java console";
|
384
|
if (dojo.byId('appletStatus')) dojo.byId("appletStatus").innerHTML = "Click on icon to launch";
|
385
|
addStartTunnelClickHandler();
|
386
|
});
|
387
|
|
388
|
return [
|
389
|
'<td>Tunnel<a href="https://www.origo.io/info/stabiledocs/web/servers/console/tunnel" rel="help" target="_blank" class="irigo-tooltip">help</a><span id="tunnelApplet" /></td>',
|
390
|
'<td>',
|
391
|
' <span id="tunnelStatus">', server.hasTunnel() ? 'Active' : 'Inactive',' </span>',
|
392
|
' <span id="tunnelButton">', server.hasTunnel() ? stop : start, '</span>',
|
393
|
' <img id="tunnel-loading-indicator" height="18px" alt="loading ..." style="display:none;vertical-align:bottom" src="/stabile/static/img/loader.gif" />',
|
394
|
'</td>'].join('');
|
395
|
}
|
396
|
},
|
397
|
*/
|
398
|
/*
|
399
|
{
|
400
|
// Console applet - obsolete, disabled
|
401
|
formatter: function(item){
|
402
|
if(true || item.status == "new"){
|
403
|
return "";
|
404
|
}
|
405
|
var server = new steam2.models.Server(item);
|
406
|
|
407
|
var handle = dojo.connect(servers.grid, 'onDialog', function(){
|
408
|
dojo.query('#startServerConsole').onclick(function(){
|
409
|
dojo.byId('tunnel-loading-indicator').style.display = 'inline';
|
410
|
server.startViewer();
|
411
|
});
|
412
|
dojo.disconnect(handle);
|
413
|
});
|
414
|
|
415
|
dojo.connect(server, 'onViewerStop', function(){
|
416
|
dojo.byId('tunnel-loading-indicator').style.display = 'none';
|
417
|
});
|
418
|
|
419
|
dojo.connect(server, 'onTunnelConnect', function(){
|
420
|
dojo.byId('tunnel-loading-indicator').style.display = 'none';
|
421
|
});
|
422
|
|
423
|
dojo.connect(server, 'onViewerStart', function(){
|
424
|
dojo.byId('tunnel-loading-indicator').style.display = 'none';
|
425
|
dojo.byId('appletStatus').innerHTML = "Started";
|
426
|
});
|
427
|
|
428
|
dojo.connect(server, 'onViewerStop', function(){
|
429
|
var elm = dojo.byId('appletStatus');
|
430
|
// NOTE: the dialog could be closed before the vnc window
|
431
|
if(elm){
|
432
|
elm.innerHTML = "Click on icon to launch";
|
433
|
}
|
434
|
});
|
435
|
|
436
|
return [
|
437
|
'<td>',
|
438
|
' <div id="consoleApplet">',
|
439
|
' <span id="appletLabel">Java console</span>',
|
440
|
' <a href="https://www.origo.io/info/stabiledocs/web/servers/console" rel="help" target="_blank" class="irigo-tooltip">help</a>',
|
441
|
' </div>',
|
442
|
'</td>',
|
443
|
'<td>',
|
444
|
' <span id="appletContainer">',
|
445
|
'<a href="#servers" id="startServerConsole">',
|
446
|
' <img src="/stabile/static/gfx/console-icon.png" height="48" width="48" style="vertical-align: middle; margin: 10px;" />',
|
447
|
'</a>',
|
448
|
' <img id="display-loading-indicator" height="18px" alt="loading ..." style="display:none;vertical-align:bottom" src="/stabile/static/img/loader.gif" />',
|
449
|
' </span>',
|
450
|
' <span id="appletStatus">Click on icon to launch</span>',
|
451
|
' (key mappings <a href="https://www.origo.io/info/stabiledocs/web/servers/console/key-mappings" rel="help" target="_blank" class="irigo-tooltip">help</a>)',
|
452
|
'</td>'].join('');
|
453
|
}
|
454
|
},
|
455
|
{
|
456
|
field: "keyboard",
|
457
|
name: "Keyboard layout",
|
458
|
type: "dijit.form.Select",
|
459
|
attrs: {store:"stores.rdpKeyboardLayouts", searchAttr: "lang"}
|
460
|
},
|
461
|
{
|
462
|
// Display display address
|
463
|
formatter: function(item){
|
464
|
if(item.status == "new"){
|
465
|
return "";
|
466
|
}
|
467
|
if(user.is_admin && item.status != "new" && item.macname){
|
468
|
// complicated because we need to fetch the IP asynchronously
|
469
|
// ensure that the dialog is shown
|
470
|
var macname = item.macname;
|
471
|
var handle = dojo.connect(servers.grid, "onDialog",function(){
|
472
|
var durl = (item.port < 5900 ? "rdp://":"vnc://") + item.macip + ":" + item.port;
|
473
|
dojo.byId('ip').innerHTML = "<a href=\"" + durl + "\">" + durl + "</a>";
|
474
|
dojo.disconnect(handle);
|
475
|
});
|
476
|
var ret = '<td><div id="iplabel">Display</div></td><td><div id="ip"></div></td>';
|
477
|
return ret;
|
478
|
}
|
479
|
return '<td><div id="iplabel"></div></td><td><div id="ip"></div></td>';
|
480
|
}
|
481
|
}
|
482
|
*/
|
483
|
],
|
484
|
|
485
|
updateNetworkInterfaces : function(items) {
|
486
|
var nicmodel1 = dijit.byId("nicmodel1");
|
487
|
nicmodel1.setStore(stores.networkInterfaces, nicmodel1.value, {query:{hypervisor: "*"+items[0].hypervisor[0]+"*"}});
|
488
|
// var nicmodel2 = dijit.byId("nicmodel2");
|
489
|
// nicmodel2.setStore(stores.networkInterfaces, nicmodel2.value, {query:{hypervisor: "*"+items[0].hypervisor+"*"}});
|
490
|
var image = dijit.byId('image');
|
491
|
var image2 = dijit.byId('image2');
|
492
|
if (image2.value) { // Images available for selection depend on first image
|
493
|
image2.setStore(stores.unusedImages2, image2.value, {query:{hypervisor: "*"+items[0].hypervisor[0]+"*" }});
|
494
|
}
|
495
|
},
|
496
|
|
497
|
dialogExtras : function(item){
|
498
|
return "";
|
499
|
},
|
500
|
|
501
|
mount: function(){
|
502
|
var item = servers.grid.dialog.item;
|
503
|
servers.store.setValue(item, 'action', 'mountcd');
|
504
|
var value = dijit.byId('cdrom').get('value');
|
505
|
servers.store.setValue(item, 'cdrom', value);
|
506
|
servers.store.save();
|
507
|
var res = servers.store.save();
|
508
|
},
|
509
|
|
510
|
move: function(){
|
511
|
var item = servers.grid.dialog.item;
|
512
|
servers.store.setValue(item, 'action', 'move');
|
513
|
var value = dijit.byId('mac').get('value');
|
514
|
servers.store.setValue(item, 'mac', value);
|
515
|
servers.store.setValue(item, 'status', 'moving');
|
516
|
servers.grid.dialog.hide();
|
517
|
var res = servers.store.save();
|
518
|
/* res[0].deferred.promise.then(function(e) {
|
519
|
console.log(e.message);
|
520
|
if (e.error) {
|
521
|
IRIGO.toast(e.message);
|
522
|
servers.grid.refresh();
|
523
|
}
|
524
|
}); */
|
525
|
},
|
526
|
|
527
|
getActionButtons : function(item, include_save){
|
528
|
if (user.is_readonly) return "";
|
529
|
|
530
|
var name = item.name;
|
531
|
var type = this.name;
|
532
|
|
533
|
function actionButton(args){
|
534
|
args.name = name;
|
535
|
args.type = type;
|
536
|
return grid.actionButton(args);
|
537
|
}
|
538
|
var id = item.uuid;//store.getValue(item, 'uuid');
|
539
|
var status = item.status;//store.getValue(item, 'status');
|
540
|
|
541
|
var start = actionButton({'action':"start", 'id':id});
|
542
|
var resume = actionButton({'action':"resume", 'id':id});
|
543
|
var suspend = actionButton({'action':"suspend", 'id':id});
|
544
|
var shutdown = actionButton({'action':"shutdown", title:'ACPI shutdown, <br />(Note: only works if supported by OS)', 'id':id, confirm:true});
|
545
|
var destroy = actionButton({'action':"destroy", 'id':id, title:'pull the plug', 'confirm':true});
|
546
|
var _delete = actionButton({'action':"delete", 'id':id, 'confirm':true});
|
547
|
var save = include_save ? grid.saveButton(type) : "";
|
548
|
var busy = ' <img height="18px" alt="busy" src="/stabile/static/img/loader.gif"> ';
|
549
|
|
550
|
switch(status){
|
551
|
case "running":
|
552
|
return suspend + shutdown + destroy + save;
|
553
|
|
554
|
case "starting":
|
555
|
case "nostate":
|
556
|
return busy + destroy + save;
|
557
|
|
558
|
case "paused":
|
559
|
return resume + destroy + save;
|
560
|
|
561
|
case "inactive":
|
562
|
return start + _delete + save;
|
563
|
case "crashed":
|
564
|
case "shutoff":
|
565
|
return start + _delete + save;
|
566
|
|
567
|
case "new":
|
568
|
return save;
|
569
|
|
570
|
case "upgrading":
|
571
|
case "suspending":
|
572
|
case "resuming":
|
573
|
case "shuttingdown":
|
574
|
return busy + destroy;
|
575
|
|
576
|
case "destroying":
|
577
|
return busy + destroy;
|
578
|
|
579
|
case "moving":
|
580
|
return busy;
|
581
|
|
582
|
default:
|
583
|
console.log("servers::getActionButtons", "unknown status: ", status);
|
584
|
return "";
|
585
|
}
|
586
|
},
|
587
|
|
588
|
// update the store to include the current server image
|
589
|
onBeforeDialog : function(item){
|
590
|
this.item = item;
|
591
|
stores.cdroms.close();
|
592
|
if(item.image && item.image){
|
593
|
stores.unusedImages.url = "/stabile/images?action=listimages&image=" +
|
594
|
escape(item.image);
|
595
|
stores.unusedImages.close();
|
596
|
}
|
597
|
else{
|
598
|
// update the store
|
599
|
stores.unusedImages.url = "/stabile/images?action=listimages";
|
600
|
stores.unusedImages.close();
|
601
|
}
|
602
|
if(item.image2 && item.image2){
|
603
|
stores.unusedImages2.url = "/stabile/images?action=listimages&image1=" +
|
604
|
escape(item.image) + "&image=" + escape(item.image2);
|
605
|
stores.unusedImages2.close();
|
606
|
}
|
607
|
else{
|
608
|
// update the store
|
609
|
stores.unusedImages2.url = "/stabile/images?action=listimages&image1=--";
|
610
|
stores.unusedImages2.close();
|
611
|
}
|
612
|
if(item.networkuuid1 && item.networkuuid1){
|
613
|
stores.unusedNetworks.url = "/stabile/networks?action=listnetworks&network=" +
|
614
|
escape(item.networkuuid1);
|
615
|
stores.unusedNetworks.close();
|
616
|
}
|
617
|
else{
|
618
|
// update the store
|
619
|
stores.unusedNetworks.url = "/stabile/networks?action=listnetworks";
|
620
|
stores.unusedNetworks.close();
|
621
|
}
|
622
|
if(item.networkuuid2 && item.networkuuid2){
|
623
|
stores.unusedNetworks2.url = "/stabile/networks?action=listnetworks&network=" +
|
624
|
escape(item.networkuuid1) + "&network1=" + escape(item.networkuuid2);
|
625
|
stores.unusedNetworks2.close();
|
626
|
}
|
627
|
else{
|
628
|
// update the store
|
629
|
stores.unusedNetworks2.url = "/stabile/networks?action=listnetworks";
|
630
|
stores.unusedNetworks2.close();
|
631
|
}
|
632
|
},
|
633
|
|
634
|
// onPostRender: function(){
|
635
|
// servers.updateSums();
|
636
|
// },
|
637
|
|
638
|
canSort: function(index){
|
639
|
if(index === 9){ // action
|
640
|
return false;
|
641
|
}
|
642
|
if(index === 1){
|
643
|
// status! Something bug in the dojo dropdown button.
|
644
|
// it doesn't stop the event onClicks although I have specified it!
|
645
|
// Tooltip clicks then triggers a sort, and removal of the tooltip content.
|
646
|
// Therefore returning false.
|
647
|
return false;
|
648
|
}
|
649
|
return true;
|
650
|
},
|
651
|
|
652
|
|
653
|
// FIXME: bad naming here
|
654
|
onDialogButtons : function(item){
|
655
|
// helpers
|
656
|
var hide = function(dijitId){
|
657
|
var elm = dijit.byId(dijitId);
|
658
|
elm && elm.set('style', 'display:none');
|
659
|
return elm;
|
660
|
};
|
661
|
var disable = function(dijitId){
|
662
|
var elm = dijit.byId(dijitId);
|
663
|
elm && elm.set('disabled', true);
|
664
|
return elm;
|
665
|
};
|
666
|
var enable = function(dijitId){
|
667
|
var elm = dijit.byId(dijitId);
|
668
|
elm && elm.set('disabled', false);
|
669
|
return elm;
|
670
|
};
|
671
|
var hideRow = function(domId){
|
672
|
// tr <- td <- input
|
673
|
dojo.query('#' + domId).parent().parent().style({display:"none"});
|
674
|
};
|
675
|
var showRow = function(domId){
|
676
|
dojo.query('#' + domId).parent().parent().style({display: "table-row"});
|
677
|
};
|
678
|
|
679
|
if(servers.isPowered(item) || user.is_readonly){
|
680
|
if (dijit.byId('dialogForm'))
|
681
|
dojo.forEach(dijit.byId('dialogForm').getChildren(), function(input){
|
682
|
if (input.id!='uuid') input.set('disabled', true);
|
683
|
});
|
684
|
}
|
685
|
else{
|
686
|
if (dijit.byId('dialogForm'))
|
687
|
dojo.forEach(dijit.byId('dialogForm').getChildren(), function(input){
|
688
|
input.set('disabled', false);
|
689
|
});
|
690
|
}
|
691
|
|
692
|
if (!user.is_readonly) {
|
693
|
// always enable renaming
|
694
|
enable('name');
|
695
|
enable('boot');
|
696
|
enable('autostart');
|
697
|
enable('locktonode');
|
698
|
//enable('mount_button');
|
699
|
}
|
700
|
if (user.is_admin) {
|
701
|
//enable('move_button');
|
702
|
// $('#move_button').show();
|
703
|
}
|
704
|
|
705
|
if (item.status == "new") {
|
706
|
$('#mount_button').hide();
|
707
|
disable('user');
|
708
|
} else {
|
709
|
if (item.status == "shutoff" && !user.is_readonly) {
|
710
|
enable('user');
|
711
|
} else {
|
712
|
disable('user');
|
713
|
}
|
714
|
}
|
715
|
|
716
|
var on_node = (new RegExp("\/mnt\/stabile\/node\/")).test(item.image)?true:false;
|
717
|
if (item.status == "new" || on_node) {
|
718
|
$('#move_button').hide();
|
719
|
disable('!($image =~ /\/$user\//)');
|
720
|
}
|
721
|
if(item.status == "running" && !user.is_readonly){
|
722
|
//enable('mount_button').set('style', 'display:inline');
|
723
|
enable('cdrom');
|
724
|
|
725
|
var kb = enable('keyboard');
|
726
|
if (kb) kb.set('value', 'en-us');
|
727
|
enable('mac');
|
728
|
if (user.is_admin) {
|
729
|
// $('#move_button').show();
|
730
|
} else {
|
731
|
$('#move_button').hide();
|
732
|
}
|
733
|
} else {
|
734
|
$('#mount_button').hide();
|
735
|
$('#move_button').hide();
|
736
|
}
|
737
|
|
738
|
if (servers.isPowered(item) && user.is_admin && !user.is_readonly) {
|
739
|
showRow('consoleApplet');
|
740
|
showRow('ip');
|
741
|
showRow('tunnelStatus');
|
742
|
} else {
|
743
|
hideRow('consoleApplet');
|
744
|
hideRow('ip');
|
745
|
hideRow('tunnelStatus');
|
746
|
}
|
747
|
|
748
|
if (item.display == "rdp" && servers.isPowered(item) && user.is_admin && !user.is_readonly){
|
749
|
showRow('keyboard');
|
750
|
}
|
751
|
else{
|
752
|
hideRow('keyboard');
|
753
|
}
|
754
|
}
|
755
|
};
|
756
|
|
757
|
|
758
|
servers.updateFilter = function(){
|
759
|
var query = this._searchQuery + " AND " + this._statusQuery;
|
760
|
this.grid.store.query = query;
|
761
|
this.grid.filter(query, /*rerender*/true);
|
762
|
};
|
763
|
|
764
|
servers.onSearchQueryChange = function(v){
|
765
|
if(v){
|
766
|
/*this._searchQuery = "name: '*" + v + "*'" +
|
767
|
" OR status: '" + v + "*'" +
|
768
|
" OR type: '" + v + "*'" +
|
769
|
" OR internalip: '" + v + "*'" +
|
770
|
" OR externalip: '" + v + "*'";*/
|
771
|
this._searchQuery = "name:" +v + "*";
|
772
|
}
|
773
|
else{
|
774
|
//this._searchQuery = "name: *";
|
775
|
this._searchQuery = "name:*";
|
776
|
}
|
777
|
this.updateFilter();
|
778
|
};
|
779
|
|
780
|
servers.onStatusFilterChange = function(value){
|
781
|
switch(value){
|
782
|
case "all":
|
783
|
//this._statusQuery = "uuid:*";
|
784
|
this._statusQuery = "status:all";
|
785
|
break;
|
786
|
default:
|
787
|
//this._statusQuery = "status:*" + value + '*';
|
788
|
this._statusQuery = "status:" + value;
|
789
|
}
|
790
|
this.updateFilter();
|
791
|
};
|
792
|
|
793
|
servers.init = function() {
|
794
|
if (servers._inited === true) return;
|
795
|
else servers._inited = true;
|
796
|
|
797
|
connect.connect(dijit.byId('servers_status_filter_select'), 'onChange', this, this.onStatusFilterChange);
|
798
|
connect.connect(dijit.byId('servers_search_query'), 'onChange', this, this.onSearchQueryChange);
|
799
|
|
800
|
servers.store = stores.servers;
|
801
|
servers.domnode = "servers-grid";
|
802
|
servers.grid = grid.create(servers);
|
803
|
|
804
|
connect.connect(this.grid, '_onFetchComplete', this, function(rows){
|
805
|
this.updateSums(rows);
|
806
|
if (!user.is_readonly) $("#serversNewButton").show();
|
807
|
});
|
808
|
|
809
|
//servers.grid.query = "uuid: '*'";
|
810
|
servers.grid.startup();
|
811
|
|
812
|
// ui update
|
813
|
dojo.subscribe("servers:update", function(task){
|
814
|
if(dijit.byId('createServerDialog')){ return;}
|
815
|
console.log("servers update", task);
|
816
|
if (task.uuid) {
|
817
|
servers.grid.refreshRow(task);
|
818
|
home.grid.refresh();
|
819
|
} else {
|
820
|
servers.grid.refresh();
|
821
|
home.grid.refresh();
|
822
|
}
|
823
|
var item = servers.grid.dialog.item;
|
824
|
if(!item || item.uuid !== task.uuid){
|
825
|
return;
|
826
|
}
|
827
|
if (dojo.byId('ip') && task.displayip && task.displayport) {
|
828
|
var disp = (task.displayport<5900?"rdp://":"vnc://");
|
829
|
|
830
|
// Why is the local_port arriving from the server?
|
831
|
// var durl = disp + task.displayip + ":" + task.displayport;
|
832
|
// changed -- Jakob
|
833
|
var durl = disp + task.displayip + ":" + task.displayport; //tunnel.getLocalPort();
|
834
|
dojo.byId('ip').innerHTML = "<a href=\"" + durl + "\">" + durl + "</a>";
|
835
|
item.port = task.displayport;
|
836
|
item.macip = task.displayip;
|
837
|
}
|
838
|
});
|
839
|
|
840
|
connect.connect(this.grid.dialog, 'show', this, function(item){
|
841
|
// summary: create dialog node link.
|
842
|
var self = this;
|
843
|
if(item.status != 'new'){
|
844
|
if(item.image && item.image != '--'){
|
845
|
domConstruct.place('<a id="serverDialogImageDialogLink" nohref="#servers">Image</a>', 'serverDialogImageDialogLink', 'replace');
|
846
|
on(dom.byId('serverDialogImageDialogLink'), 'click', function(){
|
847
|
self.grid.dialog.hide();
|
848
|
home.showImageDialog(item.image);
|
849
|
// stores.imagesByPath.fetchItemByIdentity({identity: item.image , onItem: function(item) {console.log("fetching", item); stores.images.fetchItemByIdentity({identity: item.uuid, onItem: function(image){window['images'].grid.dialog.show(image);}})}});
|
850
|
});
|
851
|
}
|
852
|
if(item.image2 && item.image2 != '--'){
|
853
|
domConstruct.place('<a id="serverDialogImage2DialogLink" nohref="#servers">Image2</a>', 'serverDialogImage2DialogLink', 'replace');
|
854
|
on(dom.byId('serverDialogImage2DialogLink'), 'click', function(){
|
855
|
self.grid.dialog.hide();
|
856
|
home.showImageDialog(item.image2);
|
857
|
// stores.imagesByPath.fetchItemByIdentity({identity: item.image2 , onItem: function(item){stores.images.fetchItemByIdentity({identity: item.uuid, onItem: function(image){window['images'].grid.dialog.show(image);}})}});
|
858
|
});
|
859
|
}
|
860
|
if(item.networkuuid1 && item.networkuuid1 != '--'){
|
861
|
domConstruct.place('<a id="serverDialogNetwork1DialogLink" nohref="#servers">Connection</a>', 'serverDialogNetwork1DialogLink', 'replace');
|
862
|
on(dom.byId('serverDialogNetwork1DialogLink'), 'click', function(){
|
863
|
self.grid.dialog.hide();
|
864
|
networks.grid.dialog.show(stores.networks.fetchItemByIdentity({identity: item.networkuuid1 }));
|
865
|
});
|
866
|
}
|
867
|
if(item.networkuuid2 && item.networkuuid2 != '--'){
|
868
|
domConstruct.place('<a id="serverDialogNetwork2DialogLink" nohref="#servers">Connection2</a>', 'serverDialogNetwork2DialogLink', 'replace');
|
869
|
on(dom.byId('serverDialogNetwork2DialogLink'), 'click', function(){
|
870
|
self.grid.dialog.hide();
|
871
|
networks.grid.dialog.show(stores.networks.fetchItemByIdentity({identity: item.networkuuid2 }));
|
872
|
});
|
873
|
}
|
874
|
if(user.is_admin && item.mac && item.mac != '--'){
|
875
|
domConstruct.place('<a id="serverDialogNodeDialogLink" nohref="#servers">Node</a>', 'serverDialogNodeDialogLink', 'replace');
|
876
|
on(dom.byId('serverDialogNodeDialogLink'), 'click', function(){
|
877
|
self.grid.dialog.hide();
|
878
|
nodes.grid.dialog.show(stores.nodes.fetchItemByIdentity({identity: item.mac }));
|
879
|
});
|
880
|
}
|
881
|
}
|
882
|
});
|
883
|
|
884
|
};
|
885
|
|
886
|
servers.updateSums = function(rows) {
|
887
|
var totalvcpus = 0;
|
888
|
var totalmemory = 0;
|
889
|
|
890
|
if (!rows) {
|
891
|
for(var i = 0; i < servers.grid.rowCount; i++){
|
892
|
sumit(servers.grid.getItem(i));
|
893
|
}
|
894
|
} else {
|
895
|
for(var i in rows){
|
896
|
sumit(rows[i]);
|
897
|
}
|
898
|
}
|
899
|
|
900
|
function sumit(item) {
|
901
|
if (item) {
|
902
|
if (item.status && item.status!="inactive" && item.status!="shutoff") {
|
903
|
totalvcpus += parseInt(item.vcpu);
|
904
|
totalmemory += parseInt(item.memory);
|
905
|
}
|
906
|
}
|
907
|
}
|
908
|
var vq = (user.vcpuquota==0)?'∞':Math.round(user.vcpuquota);
|
909
|
var memq = (user.memoryquota==0)?'∞': (Math.round(10*user.memoryquota /1024)/10);
|
910
|
document.getElementById("machines_sum").innerHTML =
|
911
|
'<span title="Quotas: ' + vq + ' VCPUs, ' + memq + ' GB memory">' +
|
912
|
"Total VCPUs: " + totalvcpus +
|
913
|
" Total memory: " + (Math.round(10*totalmemory /1024)/10) +
|
914
|
"</span>";
|
915
|
}
|
916
|
window.servers = servers;
|
917
|
return servers;
|
918
|
});
|
919
|
|
920
|
|