]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/ceph/OSD.js
ui: ceph/osd: hide Type column by default
[pve-manager.git] / www / manager6 / ceph / OSD.js
CommitLineData
4ea09218 1Ext.define('PVE.CephCreateOsd', {
9fccc702 2 extend: 'Proxmox.window.Edit',
4d3e918a 3 xtype: 'pveCephCreateOsd',
4ea09218
DM
4
5 subject: 'Ceph OSD',
6
7 showProgress: true,
8
35085f4a
TL
9 onlineHelp: 'pve_ceph_osds',
10
4ea09218 11 initComponent : function() {
4ea09218
DM
12 var me = this;
13
14 if (!me.nodename) {
15 throw "no node name specified";
16 }
17
d5e771ce 18 me.isCreate = true;
c474314e 19
4ea09218
DM
20 Ext.applyIf(me, {
21 url: "/nodes/" + me.nodename + "/ceph/osd",
9ad28182
DC
22 method: 'POST',
23 items: [
24 {
4d3e918a 25 xtype: 'inputpanel',
4c94e9de
DC
26 onGetValues: function(values) {
27 Object.keys(values || {}).forEach(function(name) {
28 if (values[name] === '') {
29 delete values[name];
30 }
31 });
32
33 return values;
34 },
4d3e918a
DC
35 column1: [
36 {
37 xtype: 'pveDiskSelector',
38 name: 'dev',
39 nodename: me.nodename,
40 diskType: 'unused',
41 fieldLabel: gettext('Disk'),
42 allowBlank: false
43 }
44 ],
45 column2: [
46 {
47 xtype: 'pveDiskSelector',
48 name: 'db_dev',
49 nodename: me.nodename,
50 diskType: 'journal_disks',
51 fieldLabel: gettext('DB Disk'),
52 value: '',
53 autoSelect: false,
54 allowBlank: true,
55 emptyText: 'use OSD disk',
56 listeners: {
57 change: function(field, val) {
58 me.down('field[name=db_size]').setDisabled(!val);
59 }
60 }
61 },
62 {
63 xtype: 'numberfield',
64 name: 'db_size',
65 fieldLabel: gettext('DB size') + ' (GiB)',
66 minValue: 1,
67 maxValue: 128*1024,
68 decimalPrecision: 2,
69 allowBlank: true,
70 disabled: true,
71 emptyText: gettext('Automatic')
72 }
73 ],
74 advancedColumn1: [
6c311f2c
DC
75 {
76 xtype: 'proxmoxcheckbox',
77 name: 'encrypted',
78 fieldLabel: gettext('Encrypt OSD')
79 },
80 ],
81 advancedColumn2: [
4d3e918a
DC
82 {
83 xtype: 'pveDiskSelector',
84 name: 'wal_dev',
85 nodename: me.nodename,
86 diskType: 'journal_disks',
87 fieldLabel: gettext('WAL Disk'),
88 value: '',
89 autoSelect: false,
90 allowBlank: true,
91 emptyText: 'use OSD/DB disk',
92 listeners: {
93 change: function(field, val) {
94 me.down('field[name=wal_size]').setDisabled(!val);
95 }
96 }
97 },
98 {
99 xtype: 'numberfield',
100 name: 'wal_size',
101 fieldLabel: gettext('WAL size') + ' (GiB)',
102 minValue: 0.5,
103 maxValue: 128*1024,
104 decimalPrecision: 2,
105 allowBlank: true,
106 disabled: true,
107 emptyText: gettext('Automatic')
108 }
109 ]
deca45c1
TL
110 },
111 {
112 xtype: 'displayfield',
113 padding: '5 0 0 0',
114 userCls: 'pve-hint',
115 value: 'Note: Ceph is not compatible with disks backed by a hardware ' +
116 'RAID controller. For details see ' +
117 '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_pveceph') + '">the reference documentation</a>.',
fddeb25b 118 }
4d3e918a
DC
119 ]
120 });
4ea09218 121
4d3e918a 122 me.callParent();
4ea09218
DM
123 }
124});
125
126Ext.define('PVE.CephRemoveOsd', {
9fccc702 127 extend: 'Proxmox.window.Edit',
4ea09218
DM
128 alias: ['widget.pveCephRemoveOsd'],
129
130 isRemove: true,
131
132 showProgress: true,
89cd5a3f
DC
133 method: 'DELETE',
134 items: [
135 {
896c0d50 136 xtype: 'proxmoxcheckbox',
89cd5a3f
DC
137 name: 'cleanup',
138 checked: true,
139 labelWidth: 130,
c56634f1 140 fieldLabel: gettext('Cleanup Disks')
89cd5a3f
DC
141 }
142 ],
4ea09218 143 initComponent : function() {
d5e771ce 144
4ea09218
DM
145 var me = this;
146
147 if (!me.nodename) {
148 throw "no node name specified";
149 }
150 if (me.osdid === undefined || me.osdid < 0) {
151 throw "no osdid specified";
152 }
153
d5e771ce 154 me.isCreate = true;
4ea09218 155
fb0e1813 156 me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
c474314e 157
4ea09218 158 Ext.applyIf(me, {
d5e771ce 159 url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
4ea09218
DM
160 });
161
162 me.callParent();
163 }
164});
165
166Ext.define('PVE.node.CephOsdTree', {
167 extend: 'Ext.tree.Panel',
168 alias: ['widget.pveNodeCephOsdTree'],
ba93a9c6 169 onlineHelp: 'chapter_pveceph',
3982a214
DC
170
171 viewModel: {
172 data: {
173 nodename: '',
174 flags: [],
175 maxversion: '0',
176 versions: {},
177 isOsd: false,
178 downOsd: false,
179 upOsd: false,
180 inOsd: false,
181 outOsd: false,
182 osdid: '',
183 osdhost: '',
184 }
185 },
186
187 controller: {
188 xclass: 'Ext.app.ViewController',
189
190 reload: function() {
191 var me = this.getView();
192 var vm = this.getViewModel();
193 var nodename = vm.get('nodename');
194 var sm = me.getSelectionModel();
195 Proxmox.Utils.API2Request({
196 url: "/nodes/" + nodename + "/ceph/osd",
197 waitMsgTarget: me,
198 method: 'GET',
199 failure: function(response, opts) {
200 var msg = response.htmlStatus;
201 PVE.Utils.showCephInstallOrMask(me, msg, nodename,
202 function(win){
203 me.mon(win, 'cephInstallWindowClosed', this.reload);
204 }
205 );
206 },
207 success: function(response, opts) {
208 var data = response.result.data;
209 var selected = me.getSelection();
210 var name;
211 if (selected.length) {
212 name = selected[0].data.name;
213 }
214 vm.set('versions', data.versions);
215 // extract max version
216 var maxversion = vm.get('maxversion');
217 Object.values(data.versions || {}).forEach(function(version) {
218 if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
219 maxversion = version;
220 }
221 });
222 vm.set('maxversion', maxversion);
223 sm.deselectAll();
224 me.setRootNode(data.root);
225 me.expandAll();
226 if (name) {
227 var node = me.getRootNode().findChild('name', name, true);
228 if (node) {
229 me.setSelection([node]);
230 }
231 }
232
233 var flags = data.flags.split(',');
234 vm.set('flags', flags);
235 var noout = flags.includes('noout');
236 me.down('#nooutBtn').setText(noout ? gettext("Unset noout") : gettext("Set noout"));
237 }
238 });
239 },
240
241 osd_cmd: function(comp) {
242 var me = this;
243 var vm = this.getViewModel();
244 var cmd = comp.cmd;
245 var params = comp.params || {};
246 var osdid = vm.get('osdid');
247
248 var doRequest = function() {
249 Proxmox.Utils.API2Request({
250 url: "/nodes/" + vm.get('osdhost') + "/ceph/osd/" + osdid + '/' + cmd,
251 waitMsgTarget: me.getView(),
252 method: 'POST',
253 params: params,
254 success: () => { me.reload(); },
255 failure: function(response, opts) {
256 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
257 }
258 });
259 };
260
261 if (cmd === 'scrub') {
262 Ext.MessageBox.defaultButton = params.deep === 1 ? 2 : 1;
263 Ext.Msg.show({
264 title: gettext('Confirm'),
265 icon: params.deep === 1 ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
266 msg: params.deep !== 1 ?
267 Ext.String.format(gettext("Scrub OSD.{0}"), osdid) :
268 Ext.String.format(gettext("Deep Scrub OSD.{0}"), osdid) +
269 "<br>Caution: This can reduce performance while it is running.",
270 buttons: Ext.Msg.YESNO,
271 callback: function(btn) {
272 if (btn !== 'yes') {
273 return;
274 }
275 doRequest();
276 }
277 });
278 } else {
279 doRequest();
280 }
281 },
282
283 create_osd: function() {
284 var me = this;
285 var vm = this.getViewModel();
286 Ext.create('PVE.CephCreateOsd', {
287 nodename: vm.get('nodename'),
288 taskDone: () => { me.reload(); }
289 }).show();
290 },
291
292 destroy_osd: function() {
293 var me = this;
294 var vm = this.getViewModel();
295 Ext.create('PVE.CephRemoveOsd', {
296 nodename: vm.get('osdhost'),
297 osdid: vm.get('osdid'),
298 taskDone: () => { me.reload(); }
299 }).show();
300 },
301
302 set_flag: function() {
303 var me = this;
304 var vm = this.getViewModel();
305 var flags = vm.get('flags');
306 Proxmox.Utils.API2Request({
307 url: "/nodes/" + vm.get('nodename') + "/ceph/flags/noout",
308 waitMsgTarget: me.getView(),
309 method: flags.includes('noout') ? 'DELETE' : 'POST',
310 failure: function(response, opts) {
311 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
312 },
313 success: () => { me.reload(); }
314 });
315 },
316
317 service_cmd: function(comp) {
318 var me = this;
319 var vm = this.getViewModel();
320 var cmd = comp.cmd || comp;
321 Proxmox.Utils.API2Request({
322 url: "/nodes/" + vm.get('osdhost') + "/ceph/" + cmd,
323 params: { service: "osd." + vm.get('osdid') },
324 waitMsgTarget: me.getView(),
325 method: 'POST',
326 success: function(response, options) {
327 var upid = response.result.data;
328 var win = Ext.create('Proxmox.window.TaskProgress', {
329 upid: upid,
330 taskDone: () => { me.reload(); }
331 });
332 win.show();
333 },
334 failure: function(response, opts) {
335 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
336 }
337 });
338 },
339
340 set_selection_status: function(tp, selection) {
341 if (selection.length < 1) {
342 return;
343 }
344 var rec = selection[0];
345 var vm = this.getViewModel();
346
347 var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
348
349 vm.set('isOsd', isOsd);
350 vm.set('downOsd', isOsd && rec.data.status === 'down');
351 vm.set('upOsd', isOsd && rec.data.status !== 'down');
352 vm.set('inOsd', isOsd && rec.data.in);
353 vm.set('outOsd', isOsd && !rec.data.in);
354 vm.set('osdid', isOsd ? rec.data.id : undefined);
355 vm.set('osdhost', isOsd ? rec.data.host : undefined);
356 vm.notify();
357 },
358
359 render_status: function(value, metaData, rec) {
360 if (!value) {
361 return value;
362 }
363 var inout = rec.data['in'] ? 'in' : 'out';
364 var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
365 'critical fa-arrow-circle-down';
366
367 var inouticon = rec.data['in'] ? 'good fa-circle' :
368 'warning fa-circle-o';
369
370 var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
371 inout + ' <i class="fa ' + inouticon + '"></i>';
372
373 return text;
374 },
375
376 render_wal: function(value, metaData, rec) {
377 if (!value &&
378 rec.data.osdtype === 'bluestore' &&
379 rec.data.type === 'osd') {
380 return 'N/A';
381 }
382 return value;
383 },
384
385 render_version: function(value, metadata, rec) {
386 var vm = this.getViewModel();
387 var versions = vm.get('versions');
388 var icon = "";
389 var version = value || "";
390 if (value && value != vm.get('maxversion')) {
391 icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
392 }
393
394 if (!value && rec.data.type == 'host') {
395 version = versions[rec.data.name] || Proxmox.Utils.unknownText;
396 }
397
398 return icon + version;
399 },
400
401 render_osd_val: function(value, metaData, rec) {
402 return (rec.data.type === 'osd') ? value : '';
403 },
a3368752
TL
404 render_osd_weight: function(value, metaData, rec) {
405 if (rec.data.type !== 'osd') {
406 return '';
407 }
408 return Ext.util.Format.number(value, '0.00###');
409 },
3982a214
DC
410
411 render_osd_size: function(value, metaData, rec) {
412 return this.render_osd_val(PVE.Utils.render_size(value), metaData, rec);
413 },
414
415 control: {
416 '#': {
417 selectionchange: 'set_selection_status'
418 }
419 },
420
421 init: function(view) {
422 var me = this;
423 var vm = this.getViewModel();
424
425 if (!view.pveSelNode.data.node) {
426 throw "no node name specified";
427 }
428
429 vm.set('nodename', view.pveSelNode.data.node);
430
431 me.callParent();
432 me.reload();
433 }
434 },
435
361aafd0
DC
436 stateful: true,
437 stateId: 'grid-ceph-osd',
3982a214
DC
438 rootVisible: false,
439 useArrows: true,
440
89cd5a3f
DC
441 columns: [
442 {
443 xtype: 'treecolumn',
444 text: 'Name',
445 dataIndex: 'name',
446 width: 150
447 },
448 {
449 text: 'Type',
450 dataIndex: 'type',
413ada0f 451 hidden: true,
89cd5a3f 452 align: 'right',
a3f146fc 453 width: 75
89cd5a3f 454 },
33a7e157
DC
455 {
456 text: gettext("Class"),
457 dataIndex: 'device_class',
458 align: 'right',
a3f146fc 459 width: 75
33a7e157 460 },
7d406f18
DC
461 {
462 text: "OSD Type",
463 dataIndex: 'osdtype',
464 align: 'right',
a3f146fc 465 width: 100
7d406f18
DC
466 },
467 {
468 text: "Bluestore Device",
469 dataIndex: 'blfsdev',
470 align: 'right',
a3f146fc 471 width: 75,
7d406f18
DC
472 hidden: true
473 },
474 {
475 text: "DB Device",
476 dataIndex: 'dbdev',
477 align: 'right',
a3f146fc 478 width: 75,
7d406f18
DC
479 hidden: true
480 },
481 {
482 text: "WAL Device",
483 dataIndex: 'waldev',
484 align: 'right',
3982a214 485 renderer: 'render_wal',
a3f146fc 486 width: 75,
7d406f18
DC
487 hidden: true
488 },
89cd5a3f
DC
489 {
490 text: 'Status',
491 dataIndex: 'status',
492 align: 'right',
3982a214 493 renderer: 'render_status',
a3f146fc 494 width: 120
89cd5a3f 495 },
e0297023
DC
496 {
497 text: gettext('Version'),
498 dataIndex: 'version',
a3f146fc 499 align: 'right',
3982a214 500 renderer: 'render_version'
e0297023 501 },
89cd5a3f
DC
502 {
503 text: 'weight',
504 dataIndex: 'crush_weight',
505 align: 'right',
a3368752 506 renderer: 'render_osd_weight',
a3f146fc 507 width: 90
89cd5a3f
DC
508 },
509 {
510 text: 'reweight',
511 dataIndex: 'reweight',
512 align: 'right',
a3368752 513 renderer: 'render_osd_weight',
89cd5a3f
DC
514 width: 90
515 },
516 {
35c9c3d6
TL
517 header: gettext('Used'),
518 columns: [
519 {
520 text: '%',
521 dataIndex: 'percent_used',
522 align: 'right',
523 renderer: function(value, metaData, rec) {
524 if (rec.data.type !== 'osd') {
525 return '';
526 }
527 return Ext.util.Format.number(value, '0.00');
528 },
529 width: 80
530 },
531 {
532 text: gettext('Total'),
533 dataIndex: 'total_space',
534 align: 'right',
535 renderer: 'render_osd_size',
536 width: 100
537 }
538 ]
89cd5a3f
DC
539 },
540 {
541 header: gettext('Latency (ms)'),
542 columns: [
543 {
544 text: 'Apply',
545 dataIndex: 'apply_latency_ms',
546 align: 'right',
3982a214 547 renderer: 'render_osd_val',
a3f146fc 548 width: 75
89cd5a3f
DC
549 },
550 {
551 text: 'Commit',
552 dataIndex: 'commit_latency_ms',
553 align: 'right',
3982a214 554 renderer: 'render_osd_val',
a3f146fc 555 width: 75
89cd5a3f
DC
556 }
557 ]
558 }
559 ],
4ea09218 560
4ea09218 561
3982a214
DC
562 tbar: {
563 items: [
564 {
565 text: gettext('Reload'),
566 iconCls: 'fa fa-refresh',
567 handler: 'reload'
568 },
a3f146fc 569 '-',
3982a214
DC
570 {
571 text: gettext('Create') + ': OSD',
572 handler: 'create_osd',
573 },
574 {
575 text: gettext('Set noout'),
576 itemId: 'nooutBtn',
577 handler: 'set_flag',
578 },
579 '->',
580 {
581 xtype: 'tbtext',
582 data: {
583 osd: undefined
4ea09218 584 },
3982a214
DC
585 bind: {
586 data: {
587 osd: "{osdid}"
e2924302 588 }
4ea09218 589 },
3982a214
DC
590 tpl: [
591 '<tpl if="osd">',
592 'osd.{osd}:',
593 '<tpl else>',
594 gettext('No OSD selected'),
595 '</tpl>'
596 ]
6f82e1b6 597 },
3982a214
DC
598 {
599 text: gettext('Start'),
600 iconCls: 'fa fa-play',
601 disabled: true,
602 bind: {
603 disabled: '{!downOsd}'
604 },
605 cmd: 'start',
606 handler: 'service_cmd'
607 },
608 {
609 text: gettext('Stop'),
610 iconCls: 'fa fa-stop',
611 disabled: true,
612 bind: {
613 disabled: '{!upOsd}'
614 },
615 cmd: 'stop',
616 handler: 'service_cmd'
617 },
618 {
619 text: gettext('Restart'),
620 iconCls: 'fa fa-refresh',
621 disabled: true,
622 bind: {
623 disabled: '{!upOsd}'
624 },
625 cmd: 'restart',
626 handler: 'service_cmd'
627 },
628 '-',
629 {
630 text: 'Out',
631 iconCls: 'fa fa-circle-o',
632 disabled: true,
633 bind: {
634 disabled: '{!inOsd}'
635 },
636 cmd: 'out',
637 handler: 'osd_cmd'
638 },
639 {
640 text: 'In',
641 iconCls: 'fa fa-circle',
642 disabled: true,
643 bind: {
644 disabled: '{!outOsd}'
645 },
646 cmd: 'in',
647 handler: 'osd_cmd'
648 },
649 '-',
650 {
3b0ae6b2 651 text: gettext('More'),
3982a214
DC
652 iconCls: 'fa fa-bars',
653 disabled: true,
654 bind: {
655 disabled: '{!isOsd}'
656 },
657 menu: [
658 {
659 text: gettext('Scrub'),
660 iconCls: 'fa fa-shower',
661 cmd: 'scrub',
662 handler: 'osd_cmd'
663 },
664 {
665 text: gettext('Deep Scrub'),
666 iconCls: 'fa fa-bath',
667 cmd: 'scrub',
668 params: {
669 deep: 1,
670 },
671 handler: 'osd_cmd'
672 },
673 {
674 text: gettext('Destroy'),
675 itemId: 'remove',
676 iconCls: 'fa fa-fw fa-trash-o',
677 bind: {
678 disabled: '{!downOsd}'
679 },
680 handler: 'destroy_osd'
681 }
682 ],
4ea09218 683 }
3982a214
DC
684 ]
685 },
686
687 fields: [
688 'name', 'type', 'status', 'host', 'in', 'id' ,
689 { type: 'number', name: 'reweight' },
690 { type: 'number', name: 'percent_used' },
691 { type: 'integer', name: 'bytes_used' },
692 { type: 'integer', name: 'total_space' },
693 { type: 'integer', name: 'apply_latency_ms' },
694 { type: 'integer', name: 'commit_latency_ms' },
695 { type: 'string', name: 'device_class' },
696 { type: 'string', name: 'osdtype' },
697 { type: 'string', name: 'blfsdev' },
698 { type: 'string', name: 'dbdev' },
699 { type: 'string', name: 'waldev' },
700 { type: 'string', name: 'version', calculate: function(data) {
701 return PVE.Utils.parse_ceph_version(data);
702 } },
703 { type: 'string', name: 'iconCls', calculate: function(data) {
704 var iconMap = {
705 host: 'fa-building',
706 osd: 'fa-hdd-o',
707 root: 'fa-server',
708 };
709 return 'fa x-fa-tree ' + iconMap[data.type];
710 } },
711 { type: 'number', name: 'crush_weight' }
712 ],
4ea09218 713});