From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id AF6908923D for ; Mon, 17 Oct 2022 16:30:12 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 9943020610 for ; Mon, 17 Oct 2022 16:30:12 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Mon, 17 Oct 2022 16:30:11 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 76A2C44A05; Mon, 17 Oct 2022 16:30:09 +0200 (CEST) Message-ID: Date: Mon, 17 Oct 2022 16:30:07 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Thunderbird/106.0 Content-Language: en-US To: Proxmox VE development discussion , Aaron Lauterer References: <20220706130126.282308-1-a.lauterer@proxmox.com> <20220706130126.282308-5-a.lauterer@proxmox.com> From: Dominik Csapak In-Reply-To: <20220706130126.282308-5-a.lauterer@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.082 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment NICE_REPLY_A -0.001 Looks like a legit reply (A) POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_2 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_4 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH manager v2 4/4] ui: osd: add details window X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Oct 2022 14:30:12 -0000 comments inline: On 7/6/22 15:01, Aaron Lauterer wrote: > This new windows provides more detailes about an OSD such as: > * PID > * Memory usage > * various metadata that could be of interest > * list of phyiscal disks used for the main disk, db and wal with > additional infos about the volumes for each > > A new 'Details' button is added to the OSD overview and a double click > on an OSD will also open this new window. > > The componend defines the items in the initComponent instead of > following a fully declarative approach. This is because we need to pass > the same store to multiple Proxmox.ObjectGrids. > > Signed-off-by: Aaron Lauterer > --- > changes since v2: > - adapting API urls > - renaming me.url to me.baseUrl > > www/manager6/Makefile | 1 + > www/manager6/ceph/OSD.js | 26 +++ > www/manager6/ceph/OSDDetails.js | 289 ++++++++++++++++++++++++++++++++ > 3 files changed, 316 insertions(+) > create mode 100644 www/manager6/ceph/OSDDetails.js > > diff --git a/www/manager6/Makefile b/www/manager6/Makefile > index d16770b1..2535aaea 100644 > --- a/www/manager6/Makefile > +++ b/www/manager6/Makefile > @@ -179,6 +179,7 @@ JSSRC= \ > ceph/Log.js \ > ceph/Monitor.js \ > ceph/OSD.js \ > + ceph/OSDDetails.js \ > ceph/Pool.js \ > ceph/ServiceList.js \ > ceph/Services.js \ > diff --git a/www/manager6/ceph/OSD.js b/www/manager6/ceph/OSD.js > index 78f226ff..75855f95 100644 > --- a/www/manager6/ceph/OSD.js > +++ b/www/manager6/ceph/OSD.js > @@ -481,6 +481,20 @@ Ext.define('PVE.node.CephOsdTree', { > }); > }, > > + run_details: function(view, rec) { > + if (rec.data.host && rec.data.type === 'osd' && rec.data.id >= 0) { > + this.details(); > + } > + }, > + > + details: function() { > + let vm = this.getViewModel(); > + Ext.create('PVE.CephOsdDetails', { > + nodename: vm.get('osdhost'), > + osdid: vm.get('osdid'), > + }).show(); > + }, > + > set_selection_status: function(tp, selection) { > if (selection.length < 1) { > return; > @@ -593,6 +607,9 @@ Ext.define('PVE.node.CephOsdTree', { > stateId: 'grid-ceph-osd', > rootVisible: false, > useArrows: true, > + listeners: { > + itemdblclick: 'run_details', > + }, > > columns: [ > { > @@ -733,6 +750,15 @@ Ext.define('PVE.node.CephOsdTree', { > '', > ], > }, > + { > + text: gettext('Details'), > + iconCls: 'fa fa-info-circle', > + disabled: true, > + bind: { > + disabled: '{!isOsd}', > + }, > + handler: 'details', > + }, > { > text: gettext('Start'), > iconCls: 'fa fa-play', > diff --git a/www/manager6/ceph/OSDDetails.js b/www/manager6/ceph/OSDDetails.js > new file mode 100644 > index 00000000..738aa227 > --- /dev/null > +++ b/www/manager6/ceph/OSDDetails.js > @@ -0,0 +1,289 @@ > +Ext.define('pve-osd-details-devices', { > + extend: 'Ext.data.Model', > + fields: ['device', 'type', 'devices', 'size', 'support_discard', 'dev_node'], > + idProperty: 'device', > +}); > + > +Ext.define('PVE.CephOsdDetails', { > + extend: 'Ext.window.Window', > + alias: ['widget.pveCephOsdDetails'], > + > + mixins: ['Proxmox.Mixin.CBind'], > + > + cbindData: function() { > + let me = this; > + me.baseUrl = `/nodes/${me.nodename}/ceph/osd/${me.osdid}`; > + return { > + title: `${gettext('Details')}: OSD ${me.osdid}`, > + }; > + }, > + > + viewModel: { > + data: { > + device: '', > + }, > + }, > + > + modal: true, > + width: 650, > + minHeight: 250, > + resizable: true, > + cbind: { > + title: '{title}', > + }, > + > + layout: { > + type: 'vbox', > + align: 'stretch', > + }, > + defaults: { > + layout: 'fit', > + border: false, > + }, > + > + controller: { > + xclass: 'Ext.app.ViewController', > + > + reload: function() { > + let view = this.getView(); > + > + Proxmox.Utils.API2Request({ > + url: `${view.baseUrl}/metadata`, > + waitMsgTarget: view, > + method: 'GET', > + failure: function(response, opts) { > + Proxmox.Utils.setErrorMask(view, response.htmlStatus); the 'view' here is the whole window, in case of an error, we even mask the 'close' button. better use the tabpanel, or wrap the toolbar + tabpanel in a panel which you can then use > + }, > + success: function(response, opts) { > + let d = response.result.data; > + let map_data = function(data) { > + return Object.keys(data).sort().map(x => ({ key: x, value: data[x] })); > + }; > + let osdData = map_data(d.osd); map_data is only used once, so it could be done inline? > + d.bdev.device = 'block'; wouldn't it make sense to do that in the api? > + let devData = [d.bdev]; > + if (d.db) { > + d.db.device = 'db'; same here? > + devData.push(d.db); > + } > + if (d.wal) { > + d.wal.device = 'wal'; and here? > + devData.push(d.wal); also seeing this, wouldn't it make sense to just return a 'devices' array from the api instead of building it here in the ui? i know it's not very likely that we get another device type, but since we are now inventing it, shouldn't it match with what we expect in the gui? (one could argue that having it the current way makes for a nicer api, since i can directly access the properties... mhmm) > + } > + view.osdStore.loadData(osdData); > + let devices = view.lookup('devices'); > + let deviceStore = devices.getStore(); > + deviceStore.loadData(devData); > + > + view.lookup('osdGeneral').rstore.fireEvent('load', view.osdStore, osdData, true); > + view.lookup('osdNetwork').rstore.fireEvent('load', view.osdStore, osdData, true); > + > + // select 'block' device automatically on first load > + if (devices.getSelection().length === 0) { > + devices.setSelection(deviceStore.findRecord('device', 'block')); > + } > + }, > + }); > + }, > + > + showDevInfo: function(grid, selected) { > + let view = this.getView(); > + if (selected[0]) { > + let device = selected[0].data.device; > + this.getViewModel().set('device', device); > + > + let detailStore = view.lookup('volumeDetails'); > + detailStore.rstore.getProxy().setUrl(`api2/json${view.baseUrl}/lv-info`); > + detailStore.rstore.getProxy().setExtraParams({ 'type': device }); > + detailStore.reload(); > + } > + }, > + > + init: function() { > + let me = this; > + let view = me.getView(); > + view.lookup('osdGeneral').down('tableview').enableTextSelection=true; > + view.lookup('osdNetwork').down('tableview').enableTextSelection=true; > + view.lookup('volumeDetails').down('tableview').enableTextSelection=true; AFAIR, these can be specified on the grid with 'viewConfig', e.g. having the following in the grid config: viewConfig: { enableTextSelection: true, }, > + > + me.reload(); > + }, > + > + control: { > + 'grid[reference=devices]': { > + selectionchange: 'showDevInfo', > + }, > + }, > + }, > + tbar: [ > + { > + text: gettext('Reload'), > + iconCls: 'fa fa-refresh', > + handler: 'reload', > + }, > + ], > + initComponent: function() { > + let me = this; > + > + me.osdStore = Ext.create('Proxmox.data.ObjectStore'); > + > + Ext.applyIf(me, { > + items: [ > + { > + xtype: 'tabpanel', > + reference: 'detailsTabs', > + items: [ > + { > + xtype: 'proxmoxObjectGrid', > + reference: 'osdGeneral', > + tooltip: gettext('Various information about the OSD'), > + rstore: me.osdStore, > + title: gettext('General'), > + gridRows: [ > + { > + xtype: 'text', > + name: 'version', > + text: gettext('Version'), > + }, > + { > + xtype: 'text', > + name: 'hostname', > + text: gettext('Hostname'), > + }, > + { > + xtype: 'text', > + name: 'osd_data', > + text: gettext('OSD data path'), > + }, > + { > + xtype: 'text', > + name: 'osd_objectstore', > + text: gettext('OSD object store'), > + }, > + { > + xtype: 'text', > + name: 'mem_usage', > + text: gettext('Memory usage'), > + renderer: Proxmox.Utils.render_size, > + }, > + { > + xtype: 'text', > + name: 'pid', > + text: `${gettext('Process ID')} (PID)`, > + }, > + ], > + }, > + { > + xtype: 'proxmoxObjectGrid', > + reference: 'osdNetwork', > + tooltip: gettext('Addresses and ports used by the OSD service'), > + rstore: me.osdStore, > + title: gettext('Network'), > + gridRows: [ > + { > + xtype: 'text', > + name: 'front_addr', > + text: `${gettext('Front Address')}
(Client & Monitor)`, > + renderer: PVE.Utils.render_ceph_osd_addr, > + }, > + { > + xtype: 'text', > + name: 'hb_front_addr', > + text: gettext('Heartbeat Front Address'), > + renderer: PVE.Utils.render_ceph_osd_addr, > + }, > + { > + xtype: 'text', > + name: 'back_addr', > + text: `${gettext('Back Address')}
(OSD)`, > + renderer: PVE.Utils.render_ceph_osd_addr, > + }, > + { > + xtype: 'text', > + name: 'hb_back_addr', > + text: gettext('Heartbeat Back Address'), > + renderer: PVE.Utils.render_ceph_osd_addr, > + }, > + ], > + }, > + { > + xtype: 'panel', > + title: 'Devices', > + tooltip: gettext('Physical devices used by the OSD'), > + items: [ > + { > + xtype: 'grid', > + border: false, > + reference: 'devices', > + store: { > + model: 'pve-osd-details-devices', > + }, > + columns: { > + items: [ > + { text: gettext('Name'), dataIndex: 'device' }, > + { text: gettext('Type'), dataIndex: 'type' }, > + { > + text: gettext('Physical Devices'), > + dataIndex: 'devices', > + }, > + { > + text: gettext('Size'), > + dataIndex: 'size', > + renderer: Proxmox.Utils.render_size, > + }, > + { > + text: 'Discard', > + dataIndex: 'support_discard', > + hidden: true, > + }, > + { > + text: gettext('Device node'), > + dataIndex: 'dev_node', > + hidden: true, > + }, > + ], > + defaults: { > + tdCls: 'pointer', > + flex: 1, > + }, > + }, > + }, > + { > + xtype: 'proxmoxObjectGrid', > + reference: 'volumeDetails', > + maskOnLoad: true, > + bind: { > + title: Ext.String.format( > + gettext('Volume Details for {0}'), > + '{device}', > + ), > + }, > + rows: { > + creation_time: { > + header: gettext('Creation time'), > + }, > + lv_name: { > + header: gettext('LV Name'), > + }, > + lv_path: { > + header: gettext('LV Path'), > + }, > + lv_uuid: { > + header: gettext('LV UUID'), > + }, > + vg_name: { > + header: gettext('VG Name'), > + }, > + }, > + url: 'nodes/', //placeholder will be set when device is selected > + }, > + ], > + }, > + ], > + }, > + ], > + }); > + > + me.callParent(); > + }, > +});