]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/VNCConsole.js
copy ha/GroupSelector.js from manager to manager6
[pve-manager.git] / www / manager6 / VNCConsole.js
1 Ext.define('PVE.noVncConsole', {
2 extend: 'Ext.panel.Panel',
3 alias: 'widget.pveNoVncConsole',
4
5 nodename: undefined,
6
7 vmid: undefined,
8
9 consoleType: undefined, // lxc or kvm
10
11 initComponent : function() {
12 var me = this;
13
14 if (!me.nodename) {
15 throw "no node name specified";
16 }
17
18 if (!me.consoleType) {
19 throw "no console type specified";
20 }
21
22 if (!me.vmid && me.consoleType !== 'shell') {
23 throw "no VM ID specified";
24 }
25
26 // always use same iframe, to avoid running several noVnc clients
27 // at same time (to avoid performance problems)
28 var box = Ext.create('widget.uxiframe', { id: "vncconsole" });
29
30 Ext.apply(me, {
31 layout: { type: 'fit' },
32 border: false,
33 items: box,
34 listeners: {
35 show: function() {
36 var url = '/?console=' + me.consoleType + '&novnc=1&node=' + me.nodename + '&resize=scale';
37 if (me.vmid) {
38 url += '&vmid='+ me.vmid;
39 }
40 box.load(url);
41 }
42 }
43 });
44
45 me.callParent();
46 }
47 });
48
49 PVE_vnc_console_event = function(appletid, action, err) {
50 //console.log("TESTINIT param1 " + appletid + " action " + action);
51
52 if (action === "error") {
53 var compid = appletid.replace("-vncapp", "");
54 var comp = Ext.getCmp(compid);
55
56 if (!comp || !comp.vmid || !comp.toplevel) {
57 return;
58 }
59
60 comp.detectMigratedVM();
61 }
62
63 return;
64 };
65
66 Ext.define('PVE.VNCConsole', {
67 extend: 'Ext.panel.Panel',
68 alias: ['widget.pveVNCConsole'],
69
70 novnc: false,
71
72 last_novnc_state: undefined,
73 last_novnc_msg: undefined,
74
75 detectMigratedVM: function() {
76 var me = this;
77
78 if (!me.vmid) {
79 return;
80 }
81
82 // try to detect migrated VM
83 PVE.Utils.API2Request({
84 url: '/cluster/resources',
85 method: 'GET',
86 success: function(response) {
87 var list = response.result.data;
88 Ext.Array.each(list, function(item) {
89 if (item.type === 'qemu' && item.vmid == me.vmid) {
90 if (item.node !== me.nodename) {
91 me.nodename = item.node;
92 me.url = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncproxy";
93 me.wsurl = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncwebsocket";
94 me.reloadApplet();
95 }
96 return false; // break
97 }
98 });
99 }
100 });
101 },
102
103 initComponent : function() {
104 var me = this;
105
106 if (!me.url) {
107 throw "no url specified";
108 }
109
110 var myid = me.id + "-vncapp";
111
112 me.appletID = myid;
113
114 var box;
115
116 if (me.novnc) {
117 if (!me.wsurl) {
118 throw "no web socket url specified";
119 }
120 box = Ext.create('widget.uxiframe', { id: myid });
121 } else {
122 box = Ext.create('Ext.Component', { border: false, html: "" });
123 }
124
125 var resize_window = function() {
126 //console.log("resize");
127
128 var aw;
129 var ah;
130 var applet;
131
132 if (me.novnc) {
133 var novnciframe = box.getFrame();
134 // noVNC_canvas
135 var innerDoc = novnciframe.contentDocument || novnciframe.contentWindow.document;
136 aw = innerDoc.getElementById('noVNC_canvas').width;
137 ah = innerDoc.getElementById('noVNC_canvas').height + 8;
138
139 var novnc_state = innerDoc.getElementById('noVNC_status_state').innerHTML;
140 var novnc_msg = innerDoc.getElementById('noVNC_status_msg').innerHTML;
141
142 if (novnc_state !== me.last_novnc_state || novnc_msg !== me.last_novnc_msg) {
143 me.last_novnc_state = novnc_state;
144 me.last_novnc_msg = novnc_msg;
145
146 if (novnc_state !== 'normal') {
147 PVE.Utils.setErrorMask(box, novnc_msg || 'unknown');
148 } else {
149 PVE.Utils.setErrorMask(box); // clear mask
150 }
151
152 if (novnc_state === 'disconnected') {
153 me.detectMigratedVM();
154 }
155 }
156
157 } else {
158 applet = Ext.getDom(myid);
159
160 // try again when dom element is available
161 if (!(applet && Ext.isFunction(applet.getPreferredSize))) {
162 return Ext.Function.defer(resize_window, 1000);
163 }
164
165 var ps = applet.getPreferredSize();
166 aw = ps.width;
167 ah = ps.height;
168 }
169
170 if (aw < 640) { aw = 640; }
171 if (ah < 400) { ah = 400; }
172
173 var tbar = me.getDockedItems("[dock=top]")[0];
174 var tbh = tbar ? tbar.getHeight() : 0;
175
176 var oh;
177 var ow;
178
179 //console.log("size0 " + aw + " " + ah + " tbh " + tbh);
180
181 if (window.innerHeight) {
182 oh = window.innerHeight;
183 ow = window.innerWidth;
184 } else if (document.documentElement &&
185 document.documentElement.clientHeight) {
186 oh = document.documentElement.clientHeight;
187 ow = document.documentElement.clientWidth;
188 } else if (document.body) {
189 oh = document.body.clientHeight;
190 ow = document.body.clientWidth;
191 } else {
192 throw "can't get window size";
193 }
194
195 if (!me.novnc) {
196 Ext.fly(applet).setSize(aw, ah + tbh);
197 }
198
199 var offsetw = aw - ow;
200 var offseth = ah + tbh - oh;
201
202 if (offsetw !== 0 || offseth !== 0) {
203 //console.log("try resize by " + offsetw + " " + offseth);
204 try { window.resizeBy(offsetw, offseth); } catch (e) {}
205 }
206
207 Ext.Function.defer(resize_window, 1000);
208 };
209
210 var resize_box = function() {
211 if (me.novnc) {
212 throw "implement me";
213 } else {
214 var applet = Ext.getDom(myid);
215
216 if ((applet && Ext.isFunction(applet.getPreferredSize))) {
217 var ps = applet.getPreferredSize();
218 Ext.fly(applet).setSize(ps.width, ps.height);
219 }
220 }
221
222 Ext.Function.defer(resize_box, 1000);
223 };
224
225 var start_vnc_viewer = function(param) {
226
227 if (me.novnc) {
228
229 var pveparams = Ext.urlEncode({
230 port: param.port,
231 vncticket: param.ticket
232 });
233
234 var urlparams = Ext.urlEncode({
235 encrypt: 1,
236 path: "api2/json" + me.wsurl + "?" + pveparams,
237 password: param.ticket
238 });
239 box.load('/novnc/vnc_pve.html?' + urlparams);
240
241 } else {
242
243 var cert = param.cert;
244 cert = cert.replace(/\n/g, "|");
245
246 box.update({
247 id: myid,
248 border: false,
249 tag: 'applet',
250 code: 'com.tigervnc.vncviewer.VncViewer',
251 archive: '/vncterm/VncViewer.jar',
252 // NOTE: set size to '100%' - else resize does not work
253 width: "100%",
254 height: "100%",
255 cn: [
256 {tag: 'param', name: 'id', value: myid},
257 {tag: 'param', name: 'PORT', value: param.port},
258 {tag: 'param', name: 'PASSWORD', value: param.ticket},
259 {tag: 'param', name: 'USERNAME', value: param.user},
260 {tag: 'param', name: 'Show Controls', value: 'No'},
261 {tag: 'param', name: 'Offer Relogin', value: 'No'},
262 {tag: 'param', name: 'PVECert', value: cert}
263 ]
264 });
265 }
266
267 if (me.toplevel) {
268 Ext.Function.defer(resize_window, 1000);
269 } else {
270 Ext.Function.defer(resize_box, 1000);
271 }
272 };
273
274 Ext.apply(me, {
275 layout: 'fit',
276 border: false,
277 autoScroll: me.toplevel ? false : true,
278 items: box,
279 reloadApplet: function() {
280 var params = Ext.apply({}, me.params);
281 if (me.novnc) {
282 params.websocket = 1;
283 }
284 PVE.Utils.API2Request({
285 url: me.url,
286 params: params,
287 method: me.method || 'POST',
288 failure: function(response, opts) {
289 box.update(gettext('Error') + ' ' + response.htmlStatus);
290 },
291 success: function(response, opts) {
292 start_vnc_viewer(response.result.data);
293 }
294 });
295 }
296 });
297
298 me.callParent();
299
300 if (me.toplevel) {
301 me.on("render", me.reloadApplet);
302 } else {
303 me.on("show", me.reloadApplet);
304 me.on("hide", function() { box.update(""); });
305 }
306 }
307 });
308
309 Ext.define('PVE.KVMConsole', {
310 extend: 'PVE.VNCConsole',
311 alias: ['widget.pveKVMConsole'],
312
313 initComponent : function() {
314 var me = this;
315
316 if (!me.nodename) {
317 throw "no node name specified";
318 }
319
320 if (!me.vmid) {
321 throw "no VM ID specified";
322 }
323
324 var baseUrl = "/nodes/" + me.nodename + "/qemu/" + me.vmid;
325
326 var vm_command = function(cmd, params, reload_applet) {
327 PVE.Utils.API2Request({
328 params: params,
329 url: baseUrl + "/status/" + cmd,
330 method: 'POST',
331 waitMsgTarget: me,
332 failure: function(response, opts) {
333 Ext.Msg.alert('Error', response.htmlStatus);
334 },
335 success: function() {
336 if (reload_applet) {
337 Ext.Function.defer(me.reloadApplet, 1000, me);
338 }
339 }
340 });
341 };
342
343 var tbar = [
344 {
345 text: gettext('Start'),
346 handler: function() {
347 vm_command("start", {}, 1);
348 }
349 },
350 {
351 text: gettext('Shutdown'),
352 handler: function() {
353 var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
354 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
355 if (btn !== 'yes') {
356 return;
357 }
358 vm_command('shutdown');
359 });
360 }
361 },
362 {
363 text: gettext('Stop'),
364 handler: function() {
365 var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
366 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
367 if (btn !== 'yes') {
368 return;
369 }
370 vm_command("stop");
371 });
372 }
373 },
374 {
375 xtype: 'pveQemuSendKeyMenu',
376 nodename: me.nodename,
377 vmid: me.vmid
378 },
379 {
380 text: gettext('Reset'),
381 handler: function() {
382 var msg = Ext.String.format(gettext("Do you really want to reset VM {0}?"), me.vmid);
383 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
384 if (btn !== 'yes') {
385 return;
386 }
387 vm_command("reset");
388 });
389 }
390 },
391 {
392 text: gettext('Suspend'),
393 handler: function() {
394 var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), me.vmid);
395 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
396 if (btn !== 'yes') {
397 return;
398 }
399 vm_command("suspend");
400 });
401 }
402 },
403 {
404 text: gettext('Resume'),
405 handler: function() {
406 vm_command("resume");
407 }
408 },
409 // Note: no migrate here, because we can't display migrate log
410 {
411 text: gettext('Console'),
412 handler: function() {
413 PVE.Utils.openVNCViewer('kvm', me.vmid, me.nodename, me.vmname, me.novnc);
414 }
415 },
416 '->',
417 {
418 text: gettext('Refresh'),
419 hidden: me.novnc ? true : false,
420 handler: function() {
421 var applet = Ext.getDom(me.appletID);
422 applet.sendRefreshRequest();
423 }
424 },
425 {
426 text: gettext('Reload'),
427 handler: function () {
428 me.reloadApplet();
429 }
430 }
431 ];
432
433
434 Ext.apply(me, {
435 tbar: tbar,
436 url: baseUrl + "/vncproxy",
437 wsurl: baseUrl + "/vncwebsocket"
438 });
439
440 me.callParent();
441 }
442 });
443
444 Ext.define('PVE.LxcConsole', {
445 extend: 'PVE.VNCConsole',
446 alias: ['widget.pveLxcConsole'],
447
448 initComponent : function() {
449 var me = this;
450
451 if (!me.nodename) {
452 throw "no node name specified";
453 }
454
455 if (!me.vmid) {
456 throw "no VM ID specified";
457 }
458
459 var baseUrl = "/nodes/" + me.nodename + "/lxc/" + me.vmid;
460
461 var vm_command = function(cmd, params, reload_applet) {
462 PVE.Utils.API2Request({
463 params: params,
464 url: baseUrl + "/status/" + cmd,
465 waitMsgTarget: me,
466 method: 'POST',
467 failure: function(response, opts) {
468 Ext.Msg.alert('Error', response.htmlStatus);
469 },
470 success: function() {
471 if (reload_applet) {
472 Ext.Function.defer(me.reloadApplet, 1000, me);
473 }
474 }
475 });
476 };
477
478 var tbar = [
479 {
480 text: gettext('Start'),
481 handler: function() {
482 vm_command("start");
483 }
484 },
485 {
486 text: gettext('Shutdown'),
487 handler: function() {
488 var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
489 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
490 if (btn !== 'yes') {
491 return;
492 }
493 vm_command("shutdown");
494 });
495 }
496 },
497 {
498 text: gettext('Stop'),
499 handler: function() {
500 var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
501 Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
502 if (btn !== 'yes') {
503 return;
504 }
505 vm_command("stop");
506 });
507 }
508 },
509 // Note: no migrate here, because we can't display migrate log
510 '->',
511 {
512 text: gettext('Refresh'),
513 hidden: me.novnc ? true : false,
514 handler: function() {
515 var applet = Ext.getDom(me.appletID);
516 applet.sendRefreshRequest();
517 }
518 },
519 {
520 text: gettext('Reload'),
521 handler: function () {
522 me.reloadApplet();
523 }
524 }
525 ];
526
527 Ext.apply(me, {
528 tbar: tbar,
529 url: baseUrl + "/vncproxy",
530 wsurl: baseUrl + "/vncwebsocket"
531 });
532
533 me.callParent();
534 }
535 });
536
537 Ext.define('PVE.Shell', {
538 extend: 'PVE.VNCConsole',
539 alias: ['widget.pveShell'],
540
541 ugradeSystem: false, // set to true to run "apt-get dist-upgrade"
542
543 initComponent : function() {
544 var me = this;
545
546 if (!me.nodename) {
547 throw "no node name specified";
548 }
549
550 var tbar = [ '->' ];
551
552 if (!me.novnc) {
553 tbar.push({
554 text: gettext('Refresh'),
555 handler: function() {
556 var applet = Ext.getDom(me.appletID);
557 applet.sendRefreshRequest();
558 }
559 });
560 }
561
562 if (!me.ugradeSystem) {
563 // we dont want to restart the upgrade script
564 tbar.push({
565 text: gettext('Reload'),
566 handler: function () { me.reloadApplet(); }
567 });
568 }
569
570 tbar.push({
571 text: gettext('Shell'),
572 handler: function() {
573 PVE.Utils.openVNCViewer('shell', undefined, me.nodename, undefined, me.novnc);
574 }
575 });
576
577 var baseUrl = "/nodes/" + me.nodename;
578
579 Ext.apply(me, {
580 tbar: tbar,
581 url: baseUrl + "/vncshell",
582 wsurl: baseUrl + "/vncwebsocket"
583 });
584
585 if (me.ugradeSystem) {
586 me.params = { upgrade: 1 };
587 }
588
589 me.callParent();
590 }
591 });