[pve-devel] [PATCH manager 2/2] lxc: show IPs in summary view
Dominik Csapak
d.csapak at proxmox.com
Wed Dec 4 10:25:13 CET 2024
high level comments/questions (i know they're not you're patches exactly, but still):
* maybe it would be better to integrate this into the AgentIPView for vms?
AFAICS the code is very similar and probably just needs a few adaptions
to work there too (url,parsing, etc.)
I'm not opposed to have two components, but then we should at least have
a good reason in the commit message why this was not done, e.g.
the data structures are too different, or something like that
* IMHO we should keep the columns consistent between VMs and Containers,
So either we change the AgentIPView to name/mac/ipv4/ipv6 too
or we combine the ipv4/ipv6 here
some comments inline:
On 12/2/24 11:46, Gabriel Goller wrote:
> modelled after the QEMU Guest Agent UI. We only show the first
> non-loopback IP on the summary page itself.
>
> Originally-by: Leo Nunner <l.nunner at proxmox.com>
> [GG: increase status panel height]
> Signed-off-by: Gabriel Goller <g.goller at proxmox.com>
> ---
> www/manager6/Makefile | 1 +
> www/manager6/lxc/ContainerIPView.js | 194 ++++++++++++++++++++++++++
> www/manager6/panel/GuestStatusView.js | 12 +-
> www/manager6/panel/GuestSummary.js | 2 +-
> 4 files changed, 207 insertions(+), 2 deletions(-)
> create mode 100644 www/manager6/lxc/ContainerIPView.js
>
> diff --git a/www/manager6/Makefile b/www/manager6/Makefile
> index c94a5cdfbf70..203a9d19cefc 100644
> --- a/www/manager6/Makefile
> +++ b/www/manager6/Makefile
> @@ -201,6 +201,7 @@ JSSRC= \
> lxc/ResourceEdit.js \
> lxc/Resources.js \
> lxc/MultiMPEdit.js \
> + lxc/ContainerIPView.js \
> menu/MenuItem.js \
> menu/TemplateMenu.js \
> ceph/CephInstallWizard.js \
> diff --git a/www/manager6/lxc/ContainerIPView.js b/www/manager6/lxc/ContainerIPView.js
> new file mode 100644
> index 000000000000..69b107af3243
> --- /dev/null
> +++ b/www/manager6/lxc/ContainerIPView.js
> @@ -0,0 +1,194 @@
> +Ext.define('PVE.window.ContainerIPInfo', {
> + extend: 'Ext.window.Window',
> + width: 600,
> + title: gettext('Container Network Information'),
> + height: 300,
> + layout: {
> + type: 'fit',
> + },
> + modal: true,
> + items: [
> + {
> + xtype: 'grid',
> + store: {},
> + emptyText: gettext('No network information'),
> + columns: [
> + {
> + dataIndex: 'name',
> + text: gettext('Name'),
> + flex: 2,
> + },
> + {
> + dataIndex: 'hwaddr',
> + text: gettext('MAC address'),
> + width: 140,
> + },
> + {
> + dataIndex: 'inet',
> + text: gettext('IPv4 address'),
> + align: 'right',
> + flex: 3,
> + },
> + {
> + dataIndex: 'inet6',
> + text: gettext('IPv6 address'),
> + align: 'right',
> + flex: 4,
> + },
> + ],
> + },
> + ],
> +});
> +
> +Ext.define('PVE.lxc.IPView', {
> + extend: 'Ext.container.Container',
> + xtype: 'pveContainerIPView',
> +
> + layout: {
> + type: 'hbox',
> + align: 'top',
> + },
> +
> + items: [
> + {
> + xtype: 'box',
> + html: '<i class="fa fa-exchange"></i> 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) {
> + let view = this.up('pveContainerIPView');
> +
> + var win = Ext.create('PVE.window.ContainerIPInfo');
> + win.down('grid').getStore().setData(view.ifaces);
> + win.show();
> + },
> + text: gettext('More'),
> + },
> + ],
> + },
> + ],
> +
> + getDefaultIps: function(ifaces) {
> + var me = this;
> + var ips = [];
> + ifaces.forEach(function(iface) {
> + // We only want to show the first non-loopback interface
> + if (!ips.length &&
> + iface.data.hwaddr &&
> + iface.data.hwaddr !== '00:00:00:00:00:00' &&
> + iface.data.hwaddr !== '0:0:0:0:0:0') {
> + ips.push(iface.data.inet);
> + ips.push(iface.data.inet6);
> + }
> + });
> +
> + return ips;
> + },
> +
> + startIPStore: function(store, records, success) {
> + var me = this;
> + let state = store.getById('status');
> +
> + me.running = state && state.data.value === 'running';
> +
> + var caps = Ext.state.Manager.get('GuiCap');
> +
> + if (!caps.vms['VM.Monitor']) {
the api call for getting the interfaces does not really need this permission?
the api only needs 'vm.audit' for this information, so this check should reflect that
> + var errorText = gettext("Requires '{0}' Privileges");
> + me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
> + return;
> + }
> +
> + if (me.running && me.ipStore.isStopped) {
> + me.ipStore.startUpdate();
> + } else if (me.ipStore.isStopped) {
> + me.updateStatus();
> + }
> + },
> +
> + updateStatus: function(unsuccessful, defaulttext) {
> + var me = this;
> + var text = defaulttext || gettext('No network information');
> + var more = false;
> + if (Ext.isArray(me.ifaces) && me.ifaces.length) {
> + more = true;
> + var ips = me.getDefaultIps(me.ifaces);
> + if (ips.length !== 0) {
> + text = ips.join('<br>');
> + }
> + }
> +
> + 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: 'lxc-interfaces-' + vmid,
> + method: 'GET',
> + proxy: {
> + type: 'proxmox',
> + url: '/api2/json/nodes/' + nodename + '/lxc/' + vmid + '/interfaces',
> + },
> + });
> +
> + me.callParent();
> +
> + me.mon(me.ipStore, 'load', function(store, records, success) {
> + if (records && records.length) {
> + me.ifaces = records;
> + } else {
> + me.ifaces = undefined;
> + }
> + me.updateStatus(!success);
> + });
> +
> + me.on('destroy', me.ipStore.stopUpdate, me.ipStore);
> +
> + // if we already have info about the guest, 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/panel/GuestStatusView.js b/www/manager6/panel/GuestStatusView.js
> index 6401811c73bb..250c7ed117fa 100644
> --- a/www/manager6/panel/GuestStatusView.js
> +++ b/www/manager6/panel/GuestStatusView.js
> @@ -146,7 +146,7 @@ Ext.define('PVE.panel.GuestStatusView', {
> height: 15,
> },
> {
> - itemId: 'ips',
> + itemId: 'agentIPs',
> xtype: 'pveAgentIPView',
> cbind: {
> rstore: '{rstore}',
> @@ -155,6 +155,16 @@ Ext.define('PVE.panel.GuestStatusView', {
> disabled: '{isLxc}',
> },
> },
> + {
> + itemId: 'ctIPS',
> + xtype: 'pveContainerIPView',
> + cbind: {
> + rstore: '{rstore}',
> + pveSelNode: '{pveSelNode}',
> + hidden: '{!isLxc}',
> + disabled: '{!isLxc}',
> + },
> + },
> ],
>
> updateTitle: function() {
> diff --git a/www/manager6/panel/GuestSummary.js b/www/manager6/panel/GuestSummary.js
> index 1565db3f658d..2186967f62da 100644
> --- a/www/manager6/panel/GuestSummary.js
> +++ b/www/manager6/panel/GuestSummary.js
> @@ -54,7 +54,7 @@ Ext.define('PVE.guest.Summary', {
> items = [
> {
> xtype: 'container',
> - height: 300,
> + height: 370,
> layout: {
> type: 'hbox',
> align: 'stretch',
More information about the pve-devel
mailing list