]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/Pool.js
1 Ext
.define('PVE.CephPoolInputPanel', {
2 extend
: 'Proxmox.panel.InputPanel',
3 xtype
: 'pveCephPoolInputPanel',
4 mixins
: ['Proxmox.Mixin.CBind'],
7 onlineHelp
: 'pve_ceph_pools',
11 defaultSize
: undefined,
12 defaultMinSize
: undefined,
15 xclass
: 'Ext.app.ViewController',
17 init: function(view
) {
18 let vm
= this.getViewModel();
19 vm
.set('size', Number(view
.defaultSize
));
20 vm
.set('minSize', Number(view
.defaultMinSize
));
22 sizeChange: function(field
, val
) {
23 let vm
= this.getViewModel();
24 let minSize
= Math
.round(val
/ 2);
26 vm
.set('minSize', minSize
);
28 vm
.set('size', val
); // bind does not work in a pmxDisplayEditField, update manually
38 minSizeLabel
: (get) => {
39 if (get('showMinSizeOneWarning') || get('showMinSizeHalfWarning')) {
40 return `${gettext('Min. Size')} <i class="fa fa-exclamation-triangle warning"></i>`;
42 return gettext('Min. Size');
44 showMinSizeOneWarning
: (get) => get('minSize') === 1,
45 showMinSizeHalfWarning
: (get) => {
46 let minSize
= get('minSize');
47 let size
= get('size');
51 return minSize
< (size
/ 2) && minSize
!== size
;
58 xtype
: 'pmxDisplayEditField',
59 fieldLabel
: gettext('Name'),
61 editable
: '{isCreate}',
68 xtype
: 'pmxDisplayEditField',
70 editable
: '{!isErasure}',
72 fieldLabel
: gettext('Size'),
75 xtype
: 'proxmoxintegerfield',
77 value
: (get) => get('defaultSize'),
90 xtype
: 'proxmoxKVComboBox',
91 fieldLabel
: 'PG Autoscale Mode',
92 name
: 'pg_autoscale_mode',
98 value
: 'on', // FIXME: check ceph version and only default to on on octopus and newer
104 xtype
: 'proxmoxcheckbox',
105 fieldLabel
: gettext('Add as Storage'),
108 hidden
: '{!isCreate}',
110 name
: 'add_storages',
114 'data-qtip': gettext('Add the new pool to the cluster storage configuration.'),
120 xtype
: 'proxmoxintegerfield',
122 fieldLabel
: '{minSizeLabel}',
127 value
: (get) => get('defaultMinSize'),
129 if (Number(get('defaultMinSize')) === 1) {
132 return get('isCreate') ? 2 : 1;
140 xtype
: 'displayfield',
142 hidden
: '{!showMinSizeHalfWarning}',
146 value
: gettext('min_size < size/2 can lead to data loss, incomplete PGs or unfound objects.'),
149 xtype
: 'displayfield',
151 hidden
: '{!showMinSizeOneWarning}',
155 value
: gettext('a min_size of 1 is not recommended and can lead to data loss'),
158 xtype
: 'pmxDisplayEditField',
160 editable
: '{!isErasure}',
161 nodename
: '{nodename}',
162 isCreate
: '{isCreate}',
164 fieldLabel
: 'Crush Rule', // do not localize
167 xtype
: 'pveCephRuleSelector',
172 xtype
: 'proxmoxintegerfield',
173 fieldLabel
: '# of PGs',
184 xtype
: 'numberfield',
185 fieldLabel
: gettext('Target Ratio'),
186 name
: 'target_size_ratio',
193 'data-qtip': gettext('The ratio of storage amount this pool will consume compared to other pools with ratios. Used for auto-scaling.'),
197 xtype
: 'pveSizeField',
199 fieldLabel
: gettext('Target Size'),
208 'data-qtip': gettext('The amount of data eventually stored in this pool. Used for auto-scaling.'),
212 xtype
: 'displayfield',
214 value
: Ext
.String
.format(gettext('{0} takes precedence.'), gettext('Target Ratio')), // FIXME: tooltip?
217 xtype
: 'proxmoxintegerfield',
218 fieldLabel
: 'Min. # of PGs',
226 onGetValues: function(values
) {
227 Object
.keys(values
|| {}).forEach(function(name
) {
228 if (values
[name
] === '') {
237 Ext
.define('PVE.Ceph.PoolEdit', {
238 extend
: 'Proxmox.window.Edit',
239 alias
: 'widget.pveCephPoolEdit',
240 mixins
: ['Proxmox.Mixin.CBind'],
244 isCreate
: (cfg
) => !cfg
.pool_name
,
245 defaultSize
: undefined,
246 defaultMinSize
: undefined,
250 autoLoad
: get => !get('isCreate'),
251 url
: get => get('isCreate')
252 ? `/nodes/${get('nodename')}/ceph/pool`
253 : `/nodes/${get('nodename')}/ceph/pool/${get('pool_name')}`,
254 loadUrl
: get => `/nodes/${get('nodename')}/ceph/pool/${get('pool_name')}/status`,
255 method
: get => get('isCreate') ? 'POST' : 'PUT',
260 subject
: gettext('Ceph Pool'),
263 xtype
: 'pveCephPoolInputPanel',
265 nodename
: '{nodename}',
266 pool_name
: '{pool_name}',
267 isErasure
: '{isErasure}',
268 isCreate
: '{isCreate}',
269 defaultSize
: '{defaultSize}',
270 defaultMinSize
: '{defaultMinSize}',
275 Ext
.define('PVE.node.Ceph.PoolList', {
276 extend
: 'Ext.grid.GridPanel',
277 alias
: 'widget.pveNodeCephPoolList',
279 onlineHelp
: 'chapter_pveceph',
282 stateId
: 'grid-ceph-pools',
283 bufferedRenderer
: false,
285 features
: [{ ftype
: 'summary' }],
289 text
: gettext('Pool #'),
297 text
: gettext('Name'),
301 dataIndex
: 'pool_name',
304 text
: gettext('Type'),
311 text
: gettext('Size') + '/min',
315 renderer
: (v
, meta
, rec
) => `${v}/${rec.data.min_size}`,
319 text
: '# of Placement Groups',
326 text
: gettext('Optimal # of PGs'),
330 dataIndex
: 'pg_num_final',
331 renderer: function(value
, metaData
) {
333 value
= '<i class="fa fa-info-circle faded"></i> n/a';
334 metaData
.tdAttr
= 'data-qtip="Needs pg_autoscaler module enabled."';
340 text
: gettext('Min. # of PGs'),
344 dataIndex
: 'pg_num_min',
348 text
: gettext('Target Ratio'),
352 dataIndex
: 'target_size_ratio',
353 renderer
: Ext
.util
.Format
.numberRenderer('0.0000'),
357 text
: gettext('Target Size'),
361 dataIndex
: 'target_size',
363 renderer: function(v
, metaData
, rec
) {
364 let value
= Proxmox
.Utils
.render_size(v
);
365 if (rec
.data
.target_size_ratio
> 0) {
366 value
= '<i class="fa fa-info-circle faded"></i> ' + value
;
367 metaData
.tdAttr
= 'data-qtip="Target Size Ratio takes precedence over Target Size."';
373 text
: gettext('Autoscale Mode'),
377 dataIndex
: 'pg_autoscale_mode',
380 text
: 'CRUSH Rule (ID)',
384 renderer
: (v
, meta
, rec
) => `${v} (${rec.data.crush_rule})`,
385 dataIndex
: 'crush_rule_name',
388 text
: gettext('Used') + ' (%)',
393 dataIndex
: 'bytes_used',
395 summaryRenderer
: Proxmox
.Utils
.render_size
,
396 renderer: function(v
, meta
, rec
) {
397 let percentage
= Ext
.util
.Format
.percent(rec
.data
.percent_used
, '0.00');
398 let used
= Proxmox
.Utils
.render_size(v
);
399 return `${used} (${percentage})`;
403 initComponent: function() {
406 var nodename
= me
.pveSelNode
.data
.node
;
408 throw "no node name specified";
411 var sm
= Ext
.create('Ext.selection.RowModel', {});
413 var rstore
= Ext
.create('Proxmox.data.UpdateStore', {
415 storeid
: 'ceph-pool-list' + nodename
,
416 model
: 'ceph-pool-list',
419 url
: `/api2/json/nodes/${nodename}/ceph/pool`,
422 let store
= Ext
.create('Proxmox.data.DiffStore', { rstore
: rstore
});
424 // manages the "install ceph?" overlay
425 PVE
.Utils
.monitor_ceph_installed(me
, rstore
, nodename
);
427 var run_editor = function() {
428 let rec
= sm
.getSelection()[0];
429 if (!rec
|| !rec
.data
.pool_name
) {
432 Ext
.create('PVE.Ceph.PoolEdit', {
433 title
: gettext('Edit') + ': Ceph Pool',
435 pool_name
: rec
.data
.pool_name
,
436 isErasure
: rec
.data
.type
=== 'erasure',
439 destroy
: () => rstore
.load(),
449 text
: gettext('Create'),
450 handler: function() {
452 'global:osd-pool-default-min-size',
453 'global:osd-pool-default-size',
456 'config-keys': keys
.join(';'),
459 Proxmox
.Utils
.API2Request({
460 url
: '/nodes/localhost/ceph/cfg/value',
463 waitMsgTarget
: me
.getView(),
464 failure
: response
=> Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
),
465 success: function({ result
: { data
} }) {
466 let global
= data
.global
;
467 let defaultSize
= global
?.['osd-pool-default-size'] ?? 3;
468 let defaultMinSize
= global
?.['osd-pool-default-min-size'] ?? 2;
470 Ext
.create('PVE.Ceph.PoolEdit', {
471 title
: gettext('Create') + ': Ceph Pool',
479 destroy
: () => rstore
.load(),
487 xtype
: 'proxmoxButton',
488 text
: gettext('Edit'),
494 xtype
: 'proxmoxButton',
495 text
: gettext('Destroy'),
498 handler: function() {
499 let rec
= sm
.getSelection()[0];
500 if (!rec
|| !rec
.data
.pool_name
) {
503 let poolName
= rec
.data
.pool_name
;
504 Ext
.create('Proxmox.window.SafeDestroy', {
506 url
: `/nodes/${nodename}/ceph/pool/${poolName}`,
514 taskName
: 'cephdestroypool',
517 destroy
: () => rstore
.load(),
524 activate
: () => rstore
.startUpdate(),
525 destroy
: () => rstore
.stopUpdate(),
526 itemdblclick
: run_editor
,
533 Ext
.define('ceph-pool-list', {
534 extend
: 'Ext.data.Model',
535 fields
: ['pool_name',
536 { name
: 'pool', type
: 'integer' },
537 { name
: 'size', type
: 'integer' },
538 { name
: 'min_size', type
: 'integer' },
539 { name
: 'pg_num', type
: 'integer' },
540 { name
: 'pg_num_min', type
: 'integer' },
541 { name
: 'bytes_used', type
: 'integer' },
542 { name
: 'percent_used', type
: 'number' },
543 { name
: 'crush_rule', type
: 'integer' },
544 { name
: 'crush_rule_name', type
: 'string' },
545 { name
: 'pg_autoscale_mode', type
: 'string' },
546 { name
: 'pg_num_final', type
: 'integer' },
547 { name
: 'target_size_ratio', type
: 'number' },
548 { name
: 'target_size', type
: 'integer' },
550 idProperty
: 'pool_name',
554 Ext
.define('PVE.form.CephRuleSelector', {
555 extend
: 'Ext.form.field.ComboBox',
556 alias
: 'widget.pveCephRuleSelector',
560 displayField
: 'name',
564 initComponent: function() {
568 throw "no nodename given";
571 me
.originalAllowBlank
= me
.allowBlank
;
572 me
.allowBlank
= true;
580 url
: `/api2/json/nodes/${me.nodename}/ceph/rules`,
583 callback
: (records
, op
, success
) => {
584 if (me
.isCreate
&& success
&& records
.length
> 0) {
585 me
.select(records
[0]);
588 me
.allowBlank
= me
.originalAllowBlank
;
589 delete me
.originalAllowBlank
;