--- /dev/null
+Ext.define('PVE.noVncConsole', {
+ extend: 'Ext.panel.Panel',
+ alias: 'widget.pveNoVncConsole',
+
+ nodename: undefined,
+
+ vmid: undefined,
+
+ consoleType: undefined, // lxc or kvm
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!me.consoleType) {
+ throw "no console type specified";
+ }
+
+ if (!me.vmid && me.consoleType !== 'shell') {
+ throw "no VM ID specified";
+ }
+
+ // always use same iframe, to avoid running several noVnc clients
+ // at same time (to avoid performance problems)
+ var box = Ext.create('widget.uxiframe', { id: "vncconsole" });
+
+ Ext.apply(me, {
+ layout: { type: 'fit' },
+ border: false,
+ items: box,
+ listeners: {
+ show: function() {
+ var url = '/?console=' + me.consoleType + '&novnc=1&node=' + me.nodename + '&resize=scale';
+ if (me.vmid) {
+ url += '&vmid='+ me.vmid;
+ }
+ box.load(url);
+ }
+ }
+ });
+
+ me.callParent();
+ }
+});
+
+PVE_vnc_console_event = function(appletid, action, err) {
+ //console.log("TESTINIT param1 " + appletid + " action " + action);
+
+ if (action === "error") {
+ var compid = appletid.replace("-vncapp", "");
+ var comp = Ext.getCmp(compid);
+
+ if (!comp || !comp.vmid || !comp.toplevel) {
+ return;
+ }
+
+ comp.detectMigratedVM();
+ }
+
+ return;
+ };
+
+Ext.define('PVE.VNCConsole', {
+ extend: 'Ext.panel.Panel',
+ alias: ['widget.pveVNCConsole'],
+
+ novnc: false,
+
+ last_novnc_state: undefined,
+ last_novnc_msg: undefined,
+
+ detectMigratedVM: function() {
+ var me = this;
+
+ if (!me.vmid) {
+ return;
+ }
+
+ // try to detect migrated VM
+ PVE.Utils.API2Request({
+ url: '/cluster/resources',
+ method: 'GET',
+ success: function(response) {
+ var list = response.result.data;
+ Ext.Array.each(list, function(item) {
+ if (item.type === 'qemu' && item.vmid == me.vmid) {
+ if (item.node !== me.nodename) {
+ me.nodename = item.node;
+ me.url = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncproxy";
+ me.wsurl = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncwebsocket";
+ me.reloadApplet();
+ }
+ return false; // break
+ }
+ });
+ }
+ });
+ },
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.url) {
+ throw "no url specified";
+ }
+
+ var myid = me.id + "-vncapp";
+
+ me.appletID = myid;
+
+ var box;
+
+ if (me.novnc) {
+ if (!me.wsurl) {
+ throw "no web socket url specified";
+ }
+ box = Ext.create('widget.uxiframe', { id: myid });
+ } else {
+ box = Ext.create('Ext.Component', { border: false, html: "" });
+ }
+
+ var resize_window = function() {
+ //console.log("resize");
+
+ var aw;
+ var ah;
+ var applet;
+
+ if (me.novnc) {
+ var novnciframe = box.getFrame();
+ // noVNC_canvas
+ var innerDoc = novnciframe.contentDocument || novnciframe.contentWindow.document;
+ aw = innerDoc.getElementById('noVNC_canvas').width;
+ ah = innerDoc.getElementById('noVNC_canvas').height + 8;
+
+ var novnc_state = innerDoc.getElementById('noVNC_status_state').innerHTML;
+ var novnc_msg = innerDoc.getElementById('noVNC_status_msg').innerHTML;
+
+ if (novnc_state !== me.last_novnc_state || novnc_msg !== me.last_novnc_msg) {
+ me.last_novnc_state = novnc_state;
+ me.last_novnc_msg = novnc_msg;
+
+ if (novnc_state !== 'normal') {
+ PVE.Utils.setErrorMask(box, novnc_msg || 'unknown');
+ } else {
+ PVE.Utils.setErrorMask(box); // clear mask
+ }
+
+ if (novnc_state === 'disconnected') {
+ me.detectMigratedVM();
+ }
+ }
+
+ } else {
+ applet = Ext.getDom(myid);
+
+ // try again when dom element is available
+ if (!(applet && Ext.isFunction(applet.getPreferredSize))) {
+ return Ext.Function.defer(resize_window, 1000);
+ }
+
+ var ps = applet.getPreferredSize();
+ aw = ps.width;
+ ah = ps.height;
+ }
+
+ if (aw < 640) { aw = 640; }
+ if (ah < 400) { ah = 400; }
+
+ var tbar = me.getDockedItems("[dock=top]")[0];
+ var tbh = tbar ? tbar.getHeight() : 0;
+
+ var oh;
+ var ow;
+
+ //console.log("size0 " + aw + " " + ah + " tbh " + tbh);
+
+ if (window.innerHeight) {
+ oh = window.innerHeight;
+ ow = window.innerWidth;
+ } else if (document.documentElement &&
+ document.documentElement.clientHeight) {
+ oh = document.documentElement.clientHeight;
+ ow = document.documentElement.clientWidth;
+ } else if (document.body) {
+ oh = document.body.clientHeight;
+ ow = document.body.clientWidth;
+ } else {
+ throw "can't get window size";
+ }
+
+ if (!me.novnc) {
+ Ext.fly(applet).setSize(aw, ah + tbh);
+ }
+
+ var offsetw = aw - ow;
+ var offseth = ah + tbh - oh;
+
+ if (offsetw !== 0 || offseth !== 0) {
+ //console.log("try resize by " + offsetw + " " + offseth);
+ try { window.resizeBy(offsetw, offseth); } catch (e) {}
+ }
+
+ Ext.Function.defer(resize_window, 1000);
+ };
+
+ var resize_box = function() {
+ if (me.novnc) {
+ throw "implement me";
+ } else {
+ var applet = Ext.getDom(myid);
+
+ if ((applet && Ext.isFunction(applet.getPreferredSize))) {
+ var ps = applet.getPreferredSize();
+ Ext.fly(applet).setSize(ps.width, ps.height);
+ }
+ }
+
+ Ext.Function.defer(resize_box, 1000);
+ };
+
+ var start_vnc_viewer = function(param) {
+
+ if (me.novnc) {
+
+ var pveparams = Ext.urlEncode({
+ port: param.port,
+ vncticket: param.ticket
+ });
+
+ var urlparams = Ext.urlEncode({
+ encrypt: 1,
+ path: "api2/json" + me.wsurl + "?" + pveparams,
+ password: param.ticket
+ });
+ box.load('/novnc/vnc_pve.html?' + urlparams);
+
+ } else {
+
+ var cert = param.cert;
+ cert = cert.replace(/\n/g, "|");
+
+ box.update({
+ id: myid,
+ border: false,
+ tag: 'applet',
+ code: 'com.tigervnc.vncviewer.VncViewer',
+ archive: '/vncterm/VncViewer.jar',
+ // NOTE: set size to '100%' - else resize does not work
+ width: "100%",
+ height: "100%",
+ cn: [
+ {tag: 'param', name: 'id', value: myid},
+ {tag: 'param', name: 'PORT', value: param.port},
+ {tag: 'param', name: 'PASSWORD', value: param.ticket},
+ {tag: 'param', name: 'USERNAME', value: param.user},
+ {tag: 'param', name: 'Show Controls', value: 'No'},
+ {tag: 'param', name: 'Offer Relogin', value: 'No'},
+ {tag: 'param', name: 'PVECert', value: cert}
+ ]
+ });
+ }
+
+ if (me.toplevel) {
+ Ext.Function.defer(resize_window, 1000);
+ } else {
+ Ext.Function.defer(resize_box, 1000);
+ }
+ };
+
+ Ext.apply(me, {
+ layout: 'fit',
+ border: false,
+ autoScroll: me.toplevel ? false : true,
+ items: box,
+ reloadApplet: function() {
+ var params = Ext.apply({}, me.params);
+ if (me.novnc) {
+ params.websocket = 1;
+ }
+ PVE.Utils.API2Request({
+ url: me.url,
+ params: params,
+ method: me.method || 'POST',
+ failure: function(response, opts) {
+ box.update(gettext('Error') + ' ' + response.htmlStatus);
+ },
+ success: function(response, opts) {
+ start_vnc_viewer(response.result.data);
+ }
+ });
+ }
+ });
+
+ me.callParent();
+
+ if (me.toplevel) {
+ me.on("render", me.reloadApplet);
+ } else {
+ me.on("show", me.reloadApplet);
+ me.on("hide", function() { box.update(""); });
+ }
+ }
+});
+
+Ext.define('PVE.KVMConsole', {
+ extend: 'PVE.VNCConsole',
+ alias: ['widget.pveKVMConsole'],
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!me.vmid) {
+ throw "no VM ID specified";
+ }
+
+ var baseUrl = "/nodes/" + me.nodename + "/qemu/" + me.vmid;
+
+ var vm_command = function(cmd, params, reload_applet) {
+ PVE.Utils.API2Request({
+ params: params,
+ url: baseUrl + "/status/" + cmd,
+ method: 'POST',
+ waitMsgTarget: me,
+ failure: function(response, opts) {
+ Ext.Msg.alert('Error', response.htmlStatus);
+ },
+ success: function() {
+ if (reload_applet) {
+ Ext.Function.defer(me.reloadApplet, 1000, me);
+ }
+ }
+ });
+ };
+
+ var tbar = [
+ {
+ text: gettext('Start'),
+ handler: function() {
+ vm_command("start", {}, 1);
+ }
+ },
+ {
+ text: gettext('Shutdown'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command('shutdown');
+ });
+ }
+ },
+ {
+ text: gettext('Stop'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command("stop");
+ });
+ }
+ },
+ {
+ xtype: 'pveQemuSendKeyMenu',
+ nodename: me.nodename,
+ vmid: me.vmid
+ },
+ {
+ text: gettext('Reset'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to reset VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command("reset");
+ });
+ }
+ },
+ {
+ text: gettext('Suspend'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command("suspend");
+ });
+ }
+ },
+ {
+ text: gettext('Resume'),
+ handler: function() {
+ vm_command("resume");
+ }
+ },
+ // Note: no migrate here, because we can't display migrate log
+ {
+ text: gettext('Console'),
+ handler: function() {
+ PVE.Utils.openVNCViewer('kvm', me.vmid, me.nodename, me.vmname, me.novnc);
+ }
+ },
+ '->',
+ {
+ text: gettext('Refresh'),
+ hidden: me.novnc ? true : false,
+ handler: function() {
+ var applet = Ext.getDom(me.appletID);
+ applet.sendRefreshRequest();
+ }
+ },
+ {
+ text: gettext('Reload'),
+ handler: function () {
+ me.reloadApplet();
+ }
+ }
+ ];
+
+
+ Ext.apply(me, {
+ tbar: tbar,
+ url: baseUrl + "/vncproxy",
+ wsurl: baseUrl + "/vncwebsocket"
+ });
+
+ me.callParent();
+ }
+});
+
+Ext.define('PVE.LxcConsole', {
+ extend: 'PVE.VNCConsole',
+ alias: ['widget.pveLxcConsole'],
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!me.vmid) {
+ throw "no VM ID specified";
+ }
+
+ var baseUrl = "/nodes/" + me.nodename + "/lxc/" + me.vmid;
+
+ var vm_command = function(cmd, params, reload_applet) {
+ PVE.Utils.API2Request({
+ params: params,
+ url: baseUrl + "/status/" + cmd,
+ waitMsgTarget: me,
+ method: 'POST',
+ failure: function(response, opts) {
+ Ext.Msg.alert('Error', response.htmlStatus);
+ },
+ success: function() {
+ if (reload_applet) {
+ Ext.Function.defer(me.reloadApplet, 1000, me);
+ }
+ }
+ });
+ };
+
+ var tbar = [
+ {
+ text: gettext('Start'),
+ handler: function() {
+ vm_command("start");
+ }
+ },
+ {
+ text: gettext('Shutdown'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command("shutdown");
+ });
+ }
+ },
+ {
+ text: gettext('Stop'),
+ handler: function() {
+ var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
+ Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ vm_command("stop");
+ });
+ }
+ },
+ // Note: no migrate here, because we can't display migrate log
+ '->',
+ {
+ text: gettext('Refresh'),
+ hidden: me.novnc ? true : false,
+ handler: function() {
+ var applet = Ext.getDom(me.appletID);
+ applet.sendRefreshRequest();
+ }
+ },
+ {
+ text: gettext('Reload'),
+ handler: function () {
+ me.reloadApplet();
+ }
+ }
+ ];
+
+ Ext.apply(me, {
+ tbar: tbar,
+ url: baseUrl + "/vncproxy",
+ wsurl: baseUrl + "/vncwebsocket"
+ });
+
+ me.callParent();
+ }
+});
+
+Ext.define('PVE.Shell', {
+ extend: 'PVE.VNCConsole',
+ alias: ['widget.pveShell'],
+
+ ugradeSystem: false, // set to true to run "apt-get dist-upgrade"
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ var tbar = [ '->' ];
+
+ if (!me.novnc) {
+ tbar.push({
+ text: gettext('Refresh'),
+ handler: function() {
+ var applet = Ext.getDom(me.appletID);
+ applet.sendRefreshRequest();
+ }
+ });
+ }
+
+ if (!me.ugradeSystem) {
+ // we dont want to restart the upgrade script
+ tbar.push({
+ text: gettext('Reload'),
+ handler: function () { me.reloadApplet(); }
+ });
+ }
+
+ tbar.push({
+ text: gettext('Shell'),
+ handler: function() {
+ PVE.Utils.openVNCViewer('shell', undefined, me.nodename, undefined, me.novnc);
+ }
+ });
+
+ var baseUrl = "/nodes/" + me.nodename;
+
+ Ext.apply(me, {
+ tbar: tbar,
+ url: baseUrl + "/vncshell",
+ wsurl: baseUrl + "/vncwebsocket"
+ });
+
+ if (me.ugradeSystem) {
+ me.params = { upgrade: 1 };
+ }
+
+ me.callParent();
+ }
+});