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