diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 77449aa0..2688fd0e 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -128,6 +128,7 @@ JSSRC= \ qemu/Config.js \ qemu/CreateWizard.js \ qemu/USBEdit.js \ + qemu/AgentIPView.js \ lxc/Summary.js \ lxc/Network.js \ lxc/Resources.js \ diff --git a/www/manager6/panel/GuestStatusView.js b/www/manager6/panel/GuestStatusView.js index 3039a1d5..5f6360ae 100644 --- a/www/manager6/panel/GuestStatusView.js +++ b/www/manager6/panel/GuestStatusView.js @@ -1,6 +1,7 @@ Ext.define('PVE.panel.GuestStatusView', { extend: 'PVE.panel.StatusView', alias: 'widget.pveGuestStatusView', + mixins: ['Proxmox.Mixin.CBind'], height: 300, @@ -84,6 +85,18 @@ Ext.define('PVE.panel.GuestStatusView', { return PVE.Utils.render_size_usage(used,max); } } + }, + { + xtype: 'box', + height: 15 + }, + { + itemId: 'ips', + xtype: 'pveAgentIPView', + cbind: { + rstore: '{rstore}', + pveSelNode: '{pveSelNode}' + } } ], @@ -106,6 +119,8 @@ Ext.define('PVE.panel.GuestStatusView', { me.callParent(); if (me.pveSelNode.data.type !== 'lxc') { me.remove(me.getComponent('swap')); + } else { + me.remove(me.getComponent('ips')); } me.getComponent('node').updateValue(me.pveSelNode.data.node); } diff --git a/www/manager6/qemu/AgentIPView.js b/www/manager6/qemu/AgentIPView.js new file mode 100644 index 00000000..ecc091f1 --- /dev/null +++ b/www/manager6/qemu/AgentIPView.js @@ -0,0 +1,212 @@ +Ext.define('PVE.window.IPInfo', { + extend: 'Ext.window.Window', + width: 600, + title: gettext('Guest Agent Network Information'), + height: 300, + layout: { + type: 'fit' + }, + modal: true, + items: [ + { + xtype: 'grid', + emptyText: gettext('No network information'), + columns: [ + { + dataIndex: 'name', + text: gettext('Name'), + flex: 3 + }, + { + dataIndex: 'hardware-address', + text: gettext('MAC address'), + width: 140 + }, + { + dataIndex: 'ip-addresses', + text: gettext('IP address'), + align: 'right', + flex: 4, + renderer: function(val) { + if (!Ext.isArray(val)) { + return ''; + } + var ips = []; + val.forEach(function(ip) { + var addr = ip['ip-address']; + var pref = ip.prefix; + if (addr && pref) { + ips.push(addr + '/' + pref); + } + }); + return ips.join('
'); + } + } + ] + } + ] +}); + +Ext.define('PVE.qemu.AgentIPView', { + extend: 'Ext.container.Container', + xtype: 'pveAgentIPView', + + layout: { + type: 'hbox', + align: 'top' + }, + + nics: [], + + items: [ + { + xtype: 'box', + html: ' IPs' + }, + { + xtype: 'container', + flex: 1, + layout: { + type: 'vbox', + align: 'right', + pack: 'end' + }, + items: [ + { + xtype: 'label', + flex: 1, + itemId: 'ipBox', + style: { + 'text-align': 'right' + } + }, + { + xtype: 'button', + itemId: 'moreBtn', + hidden: true, + ui: 'default-toolbar', + handler: function(btn) { + var me = this.up('pveAgentIPView'); + + var win = Ext.create('PVE.window.IPInfo'); + win.down('grid').getStore().setData(me.nics); + win.show(); + }, + text: gettext('More') + } + ] + } + ], + + getDefaultIps: function(nics) { + var me = this; + var ips = []; + nics.forEach(function(nic) { + if (nic['hardware-address'] && + nic['hardware-address'] != '00:00:00:00:00:00') { + + var nic_ips = nic['ip-addresses'] || []; + nic_ips.forEach(function(ip) { + var p = ip['ip-address']; + // show 2 ips at maximum + if (ips.length < 2) { + ips.push(p); + } + }); + } + }); + + return ips; + }, + + startIPStore: function(store, records, success) { + var me = this; + var agentRec = store.getById('agent'); + /*jslint confusion: true*/ + /* value is number and string */ + me.agent = (agentRec && agentRec.data.value === 1); + me.running = (store.getById('status').data.value === 'running'); + /*jslint confusion: false*/ + + if (me.agent && me.running && me.ipStore.isStopped) { + me.ipStore.startUpdate(); + } + me.updateStatus(); + }, + + updateStatus: function(unsuccessful) { + var me = this; + var text = gettext('No network information'); + var more = false; + if (unsuccessful) { + text = gettext('Guest Agent not running'); + } else if (me.agent && me.running) { + if (Ext.isArray(me.nics)) { + more = true; + var ips = me.getDefaultIps(me.nics); + if (ips.length !== 0) { + text = ips.join('
'); + } + } else if (me.nics && me.nics.error) { + var msg = gettext('Cannot get info from Guest Agent
Error: {0}'); + text = Ext.String.format(text, me.nics.error.desc); + } + } else if (me.agent) { + text = gettext('Guest Agent not running'); + } else { + text = gettext('No Guest Agent configured'); + } + + var ipBox = me.down('#ipBox'); + ipBox.update(text); + + var moreBtn = me.down('#moreBtn'); + moreBtn.setVisible(more); + }, + + initComponent: function() { + var me = this; + + if (!me.rstore) { + throw 'rstore not given'; + } + + if (!me.pveSelNode) { + throw 'pveSelNode not given'; + } + + var nodename = me.pveSelNode.data.node; + var vmid = me.pveSelNode.data.vmid; + + me.ipStore = Ext.create('Proxmox.data.UpdateStore', { + interval: 10000, + storeid: 'pve-qemu-agent-' + vmid, + method: 'POST', + proxy: { + type: 'proxmox', + url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces' + } + }); + + me.callParent(); + + me.mon(me.ipStore, 'load', function(store, records, success) { + if (records && records.length) { + me.nics = records[0].data.result; + } else { + me.nics = undefined; + } + me.updateStatus(!success); + }); + + me.on('destroy', me.ipStore.stopUpdate); + + // if we already have info about the vm, use it immediately + if (me.rstore.getCount()) { + me.startIPStore(me.rstore, me.rstore.getData(), false); + } + + // check if the guest agent is there on every statusstore load + me.mon(me.rstore, 'load', me.startIPStore, me); + } +}); diff --git a/www/manager6/qemu/Summary.js b/www/manager6/qemu/Summary.js index 73d273ac..18977bf4 100644 --- a/www/manager6/qemu/Summary.js +++ b/www/manager6/qemu/Summary.js @@ -96,7 +96,7 @@ Ext.define('PVE.qemu.Summary', { items: [ { width: 770, - height: 300, + height: 330, layout: { type: 'hbox', align: 'stretch'