]>
Commit | Line | Data |
---|---|---|
68931742 DC |
1 | Ext.define('pve-rrd-datastore', { |
2 | extend: 'Ext.data.Model', | |
3 | fields: [ | |
4 | 'used', | |
5 | 'total', | |
6 | 'read_ios', | |
7 | 'read_bytes', | |
8 | 'write_ios', | |
9 | 'write_bytes', | |
10 | 'io_ticks', | |
11 | { | |
12 | name: 'io_delay', calculate: function(data) { | |
13 | let ios = 0; | |
14 | if (data.read_ios !== undefined) { ios += data.read_ios; } | |
15 | if (data.write_ios !== undefined) { ios += data.write_ios; } | |
16 | if (data.io_ticks === undefined) { | |
17 | return undefined; | |
18 | } else if (ios === 0) { | |
19 | return 0; | |
20 | } | |
21 | return (data.io_ticks*1000.0)/ios; | |
22 | }, | |
23 | }, | |
24 | { type: 'date', dateFormat: 'timestamp', name: 'time' }, | |
25 | ], | |
26 | }); | |
27 | ||
28 | Ext.define('PBS.DataStoreInfo', { | |
29 | extend: 'Ext.panel.Panel', | |
30 | alias: 'widget.pbsDataStoreInfo', | |
31 | ||
32 | viewModel: { | |
33 | data: { | |
34 | countstext: '', | |
35 | usage: {}, | |
36 | stillbad: 0, | |
37 | removedbytes: 0, | |
38 | mountpoint: "", | |
39 | }, | |
40 | }, | |
41 | ||
42 | controller: { | |
43 | xclass: 'Ext.app.ViewController', | |
44 | ||
45 | onLoad: function(store, data, success) { | |
46 | if (!success) return; | |
47 | let me = this; | |
48 | let vm = me.getViewModel(); | |
49 | ||
50 | let counts = store.getById('counts').data.value; | |
51 | let storage = store.getById('storage').data.value; | |
52 | ||
53 | let used = Proxmox.Utils.format_size(storage.used); | |
54 | let total = Proxmox.Utils.format_size(storage.total); | |
55 | let percent = 100*storage.used/storage.total; | |
56 | if (storage.total === 0) { | |
57 | percent = 0; | |
58 | } | |
59 | let used_percent = `${percent.toFixed(2)}%`; | |
60 | ||
61 | let usage = used_percent + ' (' + | |
62 | Ext.String.format(gettext('{0} of {1}'), | |
63 | used, total) + ')'; | |
64 | vm.set('usagetext', usage); | |
65 | vm.set('usage', storage.used/storage.total); | |
66 | ||
67 | let gcstatus = store.getById('gc-status').data.value; | |
68 | ||
69 | let dedup = (gcstatus['index-data-bytes'] || 0)/ | |
70 | (gcstatus['disk-bytes'] || Infinity); | |
71 | ||
72 | let countstext = function(count) { | |
73 | return `${count[0]} ${gettext('Groups')}, ${count[1]} ${gettext('Snapshots')}`; | |
74 | }; | |
75 | ||
76 | vm.set('ctcount', countstext(counts.ct || [0, 0])); | |
77 | vm.set('vmcount', countstext(counts.vm || [0, 0])); | |
78 | vm.set('hostcount', countstext(counts.host || [0, 0])); | |
79 | vm.set('deduplication', dedup.toFixed(2)); | |
80 | vm.set('stillbad', gcstatus['still-bad']); | |
81 | vm.set('removedbytes', Proxmox.Utils.format_size(gcstatus['removed-bytes'])); | |
82 | }, | |
83 | ||
84 | startStore: function() { this.store.startUpdate(); }, | |
85 | stopStore: function() { this.store.stopUpdate(); }, | |
86 | ||
87 | init: function(view) { | |
88 | let me = this; | |
89 | let datastore = encodeURIComponent(view.datastore); | |
90 | me.store = Ext.create('Proxmox.data.ObjectStore', { | |
91 | interval: 5*1000, | |
92 | url: `/api2/json/admin/datastore/${datastore}/status`, | |
93 | }); | |
94 | me.store.on('load', me.onLoad, me); | |
95 | }, | |
96 | }, | |
97 | ||
98 | listeners: { | |
99 | activate: 'startStore', | |
100 | destroy: 'stopStore', | |
101 | deactivate: 'stopStore', | |
102 | }, | |
103 | ||
104 | defaults: { | |
105 | xtype: 'pmxInfoWidget', | |
106 | }, | |
107 | ||
108 | bodyPadding: 20, | |
109 | ||
110 | items: [ | |
111 | { | |
1f092c78 | 112 | iconCls: 'fa fa-fw fa-hdd-o', |
68931742 DC |
113 | title: gettext('Usage'), |
114 | bind: { | |
115 | data: { | |
116 | usage: '{usage}', | |
117 | text: '{usagetext}', | |
118 | }, | |
119 | }, | |
120 | }, | |
121 | { | |
122 | xtype: 'box', | |
123 | html: `<b>${gettext('Backup Count')}</b>`, | |
124 | padding: '10 0 5 0', | |
125 | }, | |
126 | { | |
1f092c78 | 127 | iconCls: 'fa fa-fw fa-cube', |
68931742 DC |
128 | title: gettext('CT'), |
129 | printBar: false, | |
130 | bind: { | |
131 | data: { | |
132 | text: '{ctcount}', | |
133 | }, | |
134 | }, | |
135 | }, | |
136 | { | |
1f092c78 | 137 | iconCls: 'fa fa-fw fa-building', |
68931742 DC |
138 | title: gettext('Host'), |
139 | printBar: false, | |
140 | bind: { | |
141 | data: { | |
142 | text: '{hostcount}', | |
143 | }, | |
144 | }, | |
145 | }, | |
146 | { | |
1f092c78 | 147 | iconCls: 'fa fa-fw fa-desktop', |
68931742 DC |
148 | title: gettext('VM'), |
149 | printBar: false, | |
150 | bind: { | |
151 | data: { | |
152 | text: '{vmcount}', | |
153 | }, | |
154 | }, | |
155 | }, | |
156 | { | |
157 | xtype: 'box', | |
158 | html: `<b>${gettext('Stats from last Garbage Collection')}</b>`, | |
159 | padding: '10 0 5 0', | |
160 | }, | |
161 | { | |
1f092c78 | 162 | iconCls: 'fa fa-fw fa-compress', |
a12388d1 | 163 | title: gettext('Deduplication Factor'), |
68931742 DC |
164 | printBar: false, |
165 | bind: { | |
166 | data: { | |
167 | text: '{deduplication}', | |
168 | }, | |
169 | }, | |
170 | }, | |
171 | { | |
1f092c78 | 172 | iconCls: 'fa fa-fw fa-trash-o', |
68931742 DC |
173 | title: gettext('Removed Bytes'), |
174 | printBar: false, | |
175 | bind: { | |
176 | data: { | |
177 | text: '{removedbytes}', | |
178 | }, | |
179 | }, | |
180 | }, | |
181 | { | |
1f092c78 | 182 | iconCls: 'fa critical fa-fw fa-exclamation-triangle', |
68931742 DC |
183 | title: gettext('Bad Chunks'), |
184 | printBar: false, | |
185 | bind: { | |
186 | data: { | |
187 | text: '{stillbad}', | |
188 | }, | |
189 | visible: '{stillbad}', | |
190 | }, | |
191 | }, | |
192 | ], | |
193 | }); | |
194 | ||
195 | Ext.define('PBS.DataStoreSummary', { | |
196 | extend: 'Ext.panel.Panel', | |
197 | alias: 'widget.pbsDataStoreSummary', | |
198 | mixins: ['Proxmox.Mixin.CBind'], | |
199 | ||
200 | layout: 'column', | |
201 | scrollable: true, | |
202 | ||
203 | bodyPadding: 5, | |
204 | defaults: { | |
205 | columnWidth: 1, | |
206 | padding: 5, | |
207 | }, | |
208 | ||
209 | tbar: ['->', { xtype: 'proxmoxRRDTypeSelector' }], | |
210 | ||
211 | items: [ | |
212 | { | |
213 | xtype: 'container', | |
214 | height: 300, | |
215 | layout: { | |
216 | type: 'hbox', | |
217 | align: 'stretch', | |
218 | }, | |
219 | items: [ | |
220 | { | |
221 | xtype: 'pbsDataStoreInfo', | |
222 | flex: 1, | |
223 | padding: '0 10 0 0', | |
224 | cbind: { | |
225 | title: '{datastore}', | |
226 | datastore: '{datastore}', | |
227 | }, | |
228 | }, | |
229 | { | |
230 | xtype: 'pbsDataStoreNotes', | |
231 | flex: 1, | |
232 | cbind: { | |
233 | datastore: '{datastore}', | |
234 | }, | |
235 | }, | |
236 | ], | |
237 | }, | |
238 | { | |
239 | xtype: 'proxmoxRRDChart', | |
240 | title: gettext('Storage usage (bytes)'), | |
241 | fields: ['total', 'used'], | |
242 | fieldTitles: [gettext('Total'), gettext('Storage usage')], | |
243 | }, | |
244 | { | |
245 | xtype: 'proxmoxRRDChart', | |
246 | title: gettext('Transfer Rate (bytes/second)'), | |
247 | fields: ['read_bytes', 'write_bytes'], | |
248 | fieldTitles: [gettext('Read'), gettext('Write')], | |
249 | }, | |
250 | { | |
251 | xtype: 'proxmoxRRDChart', | |
252 | title: gettext('Input/Output Operations per Second (IOPS)'), | |
253 | fields: ['read_ios', 'write_ios'], | |
254 | fieldTitles: [gettext('Read'), gettext('Write')], | |
255 | }, | |
256 | { | |
257 | xtype: 'proxmoxRRDChart', | |
258 | title: gettext('IO Delay (ms)'), | |
259 | fields: ['io_delay'], | |
260 | fieldTitles: [gettext('IO Delay')], | |
261 | }, | |
262 | ], | |
263 | ||
264 | listeners: { | |
265 | activate: function() { this.rrdstore.startUpdate(); }, | |
266 | deactivate: function() { this.rrdstore.stopUpdate(); }, | |
267 | destroy: function() { this.rrdstore.stopUpdate(); }, | |
268 | }, | |
269 | ||
270 | initComponent: function() { | |
271 | let me = this; | |
272 | ||
273 | me.rrdstore = Ext.create('Proxmox.data.RRDStore', { | |
274 | rrdurl: "/api2/json/admin/datastore/" + me.datastore + "/rrd", | |
275 | model: 'pve-rrd-datastore', | |
276 | }); | |
277 | ||
278 | me.callParent(); | |
279 | ||
280 | Proxmox.Utils.API2Request({ | |
281 | url: `/config/datastore/${me.datastore}`, | |
282 | waitMsgTarget: me.down('pbsDataStoreInfo'), | |
283 | success: function(response) { | |
284 | let path = Ext.htmlEncode(response.result.data.path); | |
285 | me.down('pbsDataStoreInfo').setTitle(`${me.datastore} (${path})`); | |
286 | me.down('pbsDataStoreNotes').setNotes(response.result.data.comment); | |
287 | }, | |
288 | }); | |
289 | ||
290 | me.query('proxmoxRRDChart').forEach((chart) => { | |
291 | chart.setStore(me.rrdstore); | |
292 | }); | |
293 | ||
294 | me.down('pbsDataStoreInfo').relayEvents(me, ['activate', 'deactivate']); | |
295 | }, | |
296 | }); |