]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/OSD.js
1 Ext
.define('PVE.CephCreateOsd', {
2 extend
: 'Proxmox.window.Edit',
3 xtype
: 'pveCephCreateOsd',
9 onlineHelp
: 'pve_ceph_osds',
11 initComponent: function() {
15 throw "no node name specified";
21 url
: "/nodes/" + me
.nodename
+ "/ceph/osd",
26 onGetValues: function(values
) {
27 Object
.keys(values
|| {}).forEach(function(name
) {
28 if (values
[name
] === '') {
37 xtype
: 'pmxDiskSelector',
39 nodename
: me
.nodename
,
41 fieldLabel
: gettext('Disk'),
47 xtype
: 'pmxDiskSelector',
49 nodename
: me
.nodename
,
50 diskType
: 'journal_disks',
51 fieldLabel
: gettext('DB Disk'),
55 emptyText
: 'use OSD disk',
57 change: function(field
, val
) {
58 me
.down('field[name=db_size]').setDisabled(!val
);
65 fieldLabel
: gettext('DB size') + ' (GiB)',
71 emptyText
: gettext('Automatic'),
76 xtype
: 'proxmoxcheckbox',
78 fieldLabel
: gettext('Encrypt OSD'),
81 xtype
: 'proxmoxKVComboBox',
87 name
: 'crush-device-class',
88 nodename
: me
.nodename
,
89 fieldLabel
: gettext('Device Class'),
94 emptyText
: 'auto detect',
95 deleteEmpty
: !me
.isCreate
,
100 xtype
: 'pmxDiskSelector',
102 nodename
: me
.nodename
,
103 diskType
: 'journal_disks',
104 fieldLabel
: gettext('WAL Disk'),
108 emptyText
: 'use OSD/DB disk',
110 change: function(field
, val
) {
111 me
.down('field[name=wal_size]').setDisabled(!val
);
116 xtype
: 'numberfield',
118 fieldLabel
: gettext('WAL size') + ' (GiB)',
124 emptyText
: gettext('Automatic'),
129 xtype
: 'displayfield',
132 value
: 'Note: Ceph is not compatible with disks backed by a hardware ' +
133 'RAID controller. For details see ' +
134 '<a target="_blank" href="' + Proxmox
.Utils
.get_help_link('chapter_pveceph') + '">the reference documentation</a>.',
143 Ext
.define('PVE.CephRemoveOsd', {
144 extend
: 'Proxmox.window.Edit',
145 alias
: ['widget.pveCephRemoveOsd'],
153 xtype
: 'proxmoxcheckbox',
157 fieldLabel
: gettext('Cleanup Disks'),
160 initComponent: function() {
164 throw "no node name specified";
166 if (me
.osdid
=== undefined || me
.osdid
< 0) {
167 throw "no osdid specified";
172 me
.title
= gettext('Destroy') + ': Ceph OSD osd.' + me
.osdid
.toString();
175 url
: "/nodes/" + me
.nodename
+ "/ceph/osd/" + me
.osdid
.toString(),
182 Ext
.define('PVE.CephSetFlags', {
183 extend
: 'Proxmox.window.Edit',
184 xtype
: 'pveCephSetFlags',
191 onlineHelp
: 'pve_ceph_osds',
193 title
: Ext
.String
.format(gettext('Manage {0}'), 'Global OSD Flags'),
194 submitText
: gettext('Apply'),
199 onGetValues: function(values
) {
202 me
.down('#flaggrid').getStore().each((rec
) => {
203 val
[rec
.data
.name
] = rec
.data
.value
? 1 : 0;
215 this.commitChanges();
222 text
: gettext('Enable'),
223 xtype
: 'checkcolumn',
234 dataIndex
: 'description',
242 initComponent: function() {
246 throw "no node name specified";
250 url
: "/cluster/ceph/flags",
256 let grid
= me
.down('#flaggrid');
258 success: function(response
, options
) {
259 let data
= response
.result
.data
;
260 grid
.getStore().setData(data
);
261 // re-align after store load, else the window is not centered
262 me
.alignTo(Ext
.getBody(), 'c-c');
268 Ext
.define('PVE.node.CephOsdTree', {
269 extend
: 'Ext.tree.Panel',
270 alias
: ['widget.pveNodeCephOsdTree'],
271 onlineHelp
: 'chapter_pveceph',
278 mixedversions
: false,
291 xclass
: 'Ext.app.ViewController',
295 let view
= me
.getView();
296 let vm
= me
.getViewModel();
297 let nodename
= vm
.get('nodename');
298 let sm
= view
.getSelectionModel();
299 Proxmox
.Utils
.API2Request({
300 url
: "/nodes/" + nodename
+ "/ceph/osd",
303 failure: function(response
, opts
) {
304 let msg
= response
.htmlStatus
;
305 PVE
.Utils
.showCephInstallOrMask(view
, msg
, nodename
, win
=>
306 view
.mon(win
, 'cephInstallWindowClosed', me
.reload
),
309 success: function(response
, opts
) {
310 let data
= response
.result
.data
;
311 let selected
= view
.getSelection();
313 if (selected
.length
) {
314 name
= selected
[0].data
.name
;
316 vm
.set('versions', data
.versions
);
317 // extract max version
318 let maxversion
= "0";
319 let mixedversions
= false;
321 traverse = function(node
, fn
) {
323 if (Array
.isArray(node
.children
)) {
324 node
.children
.forEach(c
=> { traverse(c
, fn
); });
327 traverse(data
.root
, node
=> {
328 // compatibility for old api call
329 if (node
.type
=== 'host' && !node
.version
) {
330 node
.version
= data
.versions
[node
.name
];
333 if (node
.version
=== undefined) {
337 if (node
.version
!== maxversion
&& maxversion
!== "0") {
338 mixedversions
= true;
341 if (PVE
.Utils
.compare_ceph_versions(node
.version
, maxversion
) > 0) {
342 maxversion
= node
.version
;
345 vm
.set('maxversion', maxversion
);
346 vm
.set('mixedversions', mixedversions
);
348 view
.setRootNode(data
.root
);
351 let node
= me
.getRootNode().findChild('name', name
, true);
353 view
.setSelection([node
]);
357 let flags
= data
.flags
.split(',');
358 vm
.set('flags', flags
);
363 osd_cmd: function(comp
) {
365 let vm
= this.getViewModel();
367 let params
= comp
.params
|| {};
368 let osdid
= vm
.get('osdid');
370 let doRequest = function() {
371 Proxmox
.Utils
.API2Request({
372 url
: "/nodes/" + vm
.get('osdhost') + "/ceph/osd/" + osdid
+ '/' + cmd
,
373 waitMsgTarget
: me
.getView(),
376 success
: () => { me
.reload(); },
377 failure: function(response
, opts
) {
378 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
383 if (cmd
=== 'scrub') {
384 Ext
.MessageBox
.defaultButton
= params
.deep
=== 1 ? 2 : 1;
386 title
: gettext('Confirm'),
387 icon
: params
.deep
=== 1 ? Ext
.Msg
.WARNING
: Ext
.Msg
.QUESTION
,
388 msg
: params
.deep
!== 1
389 ? Ext
.String
.format(gettext("Scrub OSD.{0}"), osdid
)
390 : Ext
.String
.format(gettext("Deep Scrub OSD.{0}"), osdid
) +
391 "<br>Caution: This can reduce performance while it is running.",
392 buttons
: Ext
.Msg
.YESNO
,
393 callback: function(btn
) {
405 create_osd: function() {
407 let vm
= this.getViewModel();
408 Ext
.create('PVE.CephCreateOsd', {
409 nodename
: vm
.get('nodename'),
410 taskDone
: () => { me
.reload(); },
414 destroy_osd: function() {
416 let vm
= this.getViewModel();
417 Ext
.create('PVE.CephRemoveOsd', {
418 nodename
: vm
.get('osdhost'),
419 osdid
: vm
.get('osdid'),
420 taskDone
: () => { me
.reload(); },
424 set_flags: function() {
426 let vm
= this.getViewModel();
427 Ext
.create('PVE.CephSetFlags', {
428 nodename
: vm
.get('nodename'),
429 taskDone
: () => { me
.reload(); },
433 service_cmd: function(comp
) {
435 let vm
= this.getViewModel();
436 let cmd
= comp
.cmd
|| comp
;
437 Proxmox
.Utils
.API2Request({
438 url
: "/nodes/" + vm
.get('osdhost') + "/ceph/" + cmd
,
439 params
: { service
: "osd." + vm
.get('osdid') },
440 waitMsgTarget
: me
.getView(),
442 success: function(response
, options
) {
443 let upid
= response
.result
.data
;
444 let win
= Ext
.create('Proxmox.window.TaskProgress', {
446 taskDone
: () => { me
.reload(); },
450 failure: function(response
, opts
) {
451 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
456 set_selection_status: function(tp
, selection
) {
457 if (selection
.length
< 1) {
460 let rec
= selection
[0];
461 let vm
= this.getViewModel();
463 let isOsd
= rec
.data
.host
&& (rec
.data
.type
=== 'osd') && (rec
.data
.id
>= 0);
465 vm
.set('isOsd', isOsd
);
466 vm
.set('downOsd', isOsd
&& rec
.data
.status
=== 'down');
467 vm
.set('upOsd', isOsd
&& rec
.data
.status
!== 'down');
468 vm
.set('inOsd', isOsd
&& rec
.data
.in);
469 vm
.set('outOsd', isOsd
&& !rec
.data
.in);
470 vm
.set('osdid', isOsd
? rec
.data
.id
: undefined);
471 vm
.set('osdhost', isOsd
? rec
.data
.host
: undefined);
474 render_status: function(value
, metaData
, rec
) {
478 let inout
= rec
.data
.in ? 'in' : 'out';
479 let updownicon
= value
=== 'up' ? 'good fa-arrow-circle-up'
480 : 'critical fa-arrow-circle-down';
482 let inouticon
= rec
.data
.in ? 'good fa-circle'
483 : 'warning fa-circle-o';
485 let text
= value
+ ' <i class="fa ' + updownicon
+ '"></i> / ' +
486 inout
+ ' <i class="fa ' + inouticon
+ '"></i>';
491 render_wal: function(value
, metaData
, rec
) {
493 rec
.data
.osdtype
=== 'bluestore' &&
494 rec
.data
.type
=== 'osd') {
500 render_version: function(value
, metadata
, rec
) {
501 let vm
= this.getViewModel();
502 let versions
= vm
.get('versions');
504 let version
= value
|| "";
505 let maxversion
= vm
.get('maxversion');
506 if (value
&& value
!== maxversion
) {
507 if (rec
.data
.type
=== 'host' || versions
[rec
.data
.host
] !== maxversion
) {
508 icon
= PVE
.Utils
.get_ceph_icon_html('HEALTH_UPGRADE');
510 icon
= PVE
.Utils
.get_ceph_icon_html('HEALTH_OLD');
512 } else if (value
&& vm
.get('mixedversions')) {
513 icon
= PVE
.Utils
.get_ceph_icon_html('HEALTH_OK');
516 return icon
+ version
;
519 render_osd_val: function(value
, metaData
, rec
) {
520 return rec
.data
.type
=== 'osd' ? value
: '';
522 render_osd_weight: function(value
, metaData
, rec
) {
523 if (rec
.data
.type
!== 'osd') {
526 return Ext
.util
.Format
.number(value
, '0.00###');
529 render_osd_latency: function(value
, metaData
, rec
) {
530 if (rec
.data
.type
!== 'osd') {
533 let commit_ms
= rec
.data
.commit_latency_ms
,
534 apply_ms
= rec
.data
.apply_latency_ms
;
535 return apply_ms
+ ' / ' + commit_ms
;
538 render_osd_size: function(value
, metaData
, rec
) {
539 return this.render_osd_val(PVE
.Utils
.render_size(value
), metaData
, rec
);
544 selectionchange
: 'set_selection_status',
548 init: function(view
) {
550 let vm
= this.getViewModel();
552 if (!view
.pveSelNode
.data
.node
) {
553 throw "no node name specified";
556 vm
.set('nodename', view
.pveSelNode
.data
.node
);
564 stateId
: 'grid-ceph-osd',
583 text
: gettext("Class"),
584 dataIndex
: 'device_class',
590 dataIndex
: 'osdtype',
595 text
: "Bluestore Device",
596 dataIndex
: 'blfsdev',
612 renderer
: 'render_wal',
620 renderer
: 'render_status',
624 text
: gettext('Version'),
625 dataIndex
: 'version',
627 renderer
: 'render_version',
631 dataIndex
: 'crush_weight',
633 renderer
: 'render_osd_weight',
638 dataIndex
: 'reweight',
640 renderer
: 'render_osd_weight',
644 text
: gettext('Used') + ' (%)',
645 dataIndex
: 'percent_used',
647 renderer: function(value
, metaData
, rec
) {
648 if (rec
.data
.type
!== 'osd') {
651 return Ext
.util
.Format
.number(value
, '0.00');
656 text
: gettext('Total'),
657 dataIndex
: 'total_space',
659 renderer
: 'render_osd_size',
663 text
: 'Apply/Commit<br>Latency (ms)',
664 dataIndex
: 'apply_latency_ms',
666 renderer
: 'render_osd_latency',
675 text
: gettext('Reload'),
676 iconCls
: 'fa fa-refresh',
681 text
: gettext('Create') + ': OSD',
682 handler
: 'create_osd',
685 text
: Ext
.String
.format(gettext('Manage {0}'), 'Global Flags'),
686 handler
: 'set_flags',
703 gettext('No OSD selected'),
708 text
: gettext('Start'),
709 iconCls
: 'fa fa-play',
712 disabled
: '{!downOsd}',
715 handler
: 'service_cmd',
718 text
: gettext('Stop'),
719 iconCls
: 'fa fa-stop',
722 disabled
: '{!upOsd}',
725 handler
: 'service_cmd',
728 text
: gettext('Restart'),
729 iconCls
: 'fa fa-refresh',
732 disabled
: '{!upOsd}',
735 handler
: 'service_cmd',
740 iconCls
: 'fa fa-circle-o',
743 disabled
: '{!inOsd}',
750 iconCls
: 'fa fa-circle',
753 disabled
: '{!outOsd}',
760 text
: gettext('More'),
761 iconCls
: 'fa fa-bars',
764 disabled
: '{!isOsd}',
768 text
: gettext('Scrub'),
769 iconCls
: 'fa fa-shower',
774 text
: gettext('Deep Scrub'),
775 iconCls
: 'fa fa-bath',
783 text
: gettext('Destroy'),
785 iconCls
: 'fa fa-fw fa-trash-o',
787 disabled
: '{!downOsd}',
789 handler
: 'destroy_osd',
797 'name', 'type', 'status', 'host', 'in', 'id',
798 { type
: 'number', name
: 'reweight' },
799 { type
: 'number', name
: 'percent_used' },
800 { type
: 'integer', name
: 'bytes_used' },
801 { type
: 'integer', name
: 'total_space' },
802 { type
: 'integer', name
: 'apply_latency_ms' },
803 { type
: 'integer', name
: 'commit_latency_ms' },
804 { type
: 'string', name
: 'device_class' },
805 { type
: 'string', name
: 'osdtype' },
806 { type
: 'string', name
: 'blfsdev' },
807 { type
: 'string', name
: 'dbdev' },
808 { type
: 'string', name
: 'waldev' },
810 type
: 'string', name
: 'version', calculate: function(data
) {
811 return PVE
.Utils
.parse_ceph_version(data
);
815 type
: 'string', name
: 'iconCls', calculate: function(data
) {
821 return 'fa x-fa-tree ' + iconMap
[data
.type
];
824 { type
: 'number', name
: 'crush_weight' },