]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/OSD.js
ceph: just use "0" as initial value for ceph version
[pve-manager.git] / www / manager6 / ceph / OSD.js
1 Ext.define('PVE.CephCreateOsd', {
2 extend: 'Proxmox.window.Edit',
3 alias: ['widget.pveCephCreateOsd'],
4
5 subject: 'Ceph OSD',
6
7 showProgress: true,
8
9 onlineHelp: 'pve_ceph_osds',
10
11 initComponent : function() {
12 var me = this;
13
14 if (!me.nodename) {
15 throw "no node name specified";
16 }
17
18 me.isCreate = true;
19
20 Ext.applyIf(me, {
21 url: "/nodes/" + me.nodename + "/ceph/osd",
22 method: 'POST',
23 items: [
24 {
25 xtype: 'pveDiskSelector',
26 name: 'dev',
27 nodename: me.nodename,
28 diskType: 'unused',
29 fieldLabel: gettext('Disk'),
30 allowBlank: false
31 },
32 {
33 xtype: 'pveDiskSelector',
34 name: 'journal_dev',
35 nodename: me.nodename,
36 diskType: 'journal_disks',
37 fieldLabel: gettext('Journal/DB Disk'),
38 value: '',
39 autoSelect: false,
40 allowBlank: true,
41 emptyText: 'use OSD disk'
42 },
43 {
44 xtype: 'proxmoxcheckbox',
45 name: 'bluestore',
46 fieldLabel: 'Bluestore',
47 uncheckedValue: '0',
48 value: '1'
49 }
50 ]
51 });
52
53 me.callParent();
54 }
55 });
56
57 Ext.define('PVE.CephRemoveOsd', {
58 extend: 'Proxmox.window.Edit',
59 alias: ['widget.pveCephRemoveOsd'],
60
61 isRemove: true,
62
63 showProgress: true,
64 method: 'DELETE',
65 items: [
66 {
67 xtype: 'proxmoxcheckbox',
68 name: 'cleanup',
69 checked: true,
70 labelWidth: 130,
71 fieldLabel: gettext('Remove Partitions')
72 }
73 ],
74 initComponent : function() {
75
76 var me = this;
77
78 if (!me.nodename) {
79 throw "no node name specified";
80 }
81 if (me.osdid === undefined || me.osdid < 0) {
82 throw "no osdid specified";
83 }
84
85 me.isCreate = true;
86
87 me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
88
89 Ext.applyIf(me, {
90 url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
91 });
92
93 me.callParent();
94 }
95 });
96
97 Ext.define('PVE.node.CephOsdTree', {
98 extend: 'Ext.tree.Panel',
99 alias: ['widget.pveNodeCephOsdTree'],
100 onlineHelp: 'chapter_pveceph',
101 stateful: true,
102 stateId: 'grid-ceph-osd',
103 columns: [
104 {
105 xtype: 'treecolumn',
106 text: 'Name',
107 dataIndex: 'name',
108 width: 150
109 },
110 {
111 text: 'Type',
112 dataIndex: 'type',
113 align: 'right',
114 width: 60
115 },
116 {
117 text: gettext("Class"),
118 dataIndex: 'device_class',
119 align: 'right',
120 width: 40
121 },
122 {
123 text: "OSD Type",
124 dataIndex: 'osdtype',
125 align: 'right',
126 width: 40
127 },
128 {
129 text: "Bluestore Device",
130 dataIndex: 'blfsdev',
131 align: 'right',
132 width: 40,
133 hidden: true
134 },
135 {
136 text: "DB Device",
137 dataIndex: 'dbdev',
138 align: 'right',
139 width: 40,
140 hidden: true
141 },
142 {
143 text: "WAL Device",
144 dataIndex: 'waldev',
145 align: 'right',
146 renderer: function(value, metaData, rec) {
147 if (!value &&
148 rec.data.osdtype === 'bluestore' &&
149 rec.data.type === 'osd') {
150 return 'N/A';
151 }
152 return value;
153 },
154 width: 40,
155 hidden: true
156 },
157 {
158 text: 'Status',
159 dataIndex: 'status',
160 align: 'right',
161 renderer: function(value, metaData, rec) {
162 if (!value) {
163 return value;
164 }
165 var inout = rec.data['in'] ? 'in' : 'out';
166 var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
167 'critical fa-arrow-circle-down';
168
169 var inouticon = rec.data['in'] ? 'good fa-circle' :
170 'warning fa-circle-o';
171
172 var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
173 inout + ' <i class="fa ' + inouticon + '"></i>';
174
175 return text;
176 },
177 width: 80
178 },
179 {
180 text: gettext('Version'),
181 dataIndex: 'version',
182 renderer: function(value, metadata, rec) {
183 var me = this;
184 var icon = "";
185 var version = value || "";
186 if (value && value != me.maxversion) {
187 icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
188 }
189
190 if (!value && rec.data.type == 'host') {
191 icon = '<i class="fa faded fa-cube"></i> ';
192 version = me.versions[rec.data.name] || Proxmox.Utils.unknownText;
193 }
194
195 return icon + version;
196 }
197 },
198 {
199 text: 'weight',
200 dataIndex: 'crush_weight',
201 align: 'right',
202 renderer: function(value, metaData, rec) {
203 if (rec.data.type !== 'osd') {
204 return '';
205 }
206 return value;
207 },
208 width: 80
209 },
210 {
211 text: 'reweight',
212 dataIndex: 'reweight',
213 align: 'right',
214 renderer: function(value, metaData, rec) {
215 if (rec.data.type !== 'osd') {
216 return '';
217 }
218 return value;
219 },
220 width: 90
221 },
222 {
223 header: gettext('Used'),
224 columns: [
225 {
226 text: '%',
227 dataIndex: 'percent_used',
228 align: 'right',
229 renderer: function(value, metaData, rec) {
230 if (rec.data.type !== 'osd') {
231 return '';
232 }
233 return Ext.util.Format.number(value, '0.00');
234 },
235 width: 80
236 },
237 {
238 text: gettext('Total'),
239 dataIndex: 'total_space',
240 align: 'right',
241 renderer: function(value, metaData, rec) {
242 if (rec.data.type !== 'osd') {
243 return '';
244 }
245 return PVE.Utils.render_size(value);
246 },
247 width: 100
248 }
249 ]
250 },
251 {
252 header: gettext('Latency (ms)'),
253 columns: [
254 {
255 text: 'Apply',
256 dataIndex: 'apply_latency_ms',
257 align: 'right',
258 renderer: function(value, metaData, rec) {
259 if (rec.data.type !== 'osd') {
260 return '';
261 }
262 return value;
263 },
264 width: 60
265 },
266 {
267 text: 'Commit',
268 dataIndex: 'commit_latency_ms',
269 align: 'right',
270 renderer: function(value, metaData, rec) {
271 if (rec.data.type !== 'osd') {
272 return '';
273 }
274 return value;
275 },
276 width: 60
277 }
278 ]
279 }
280 ],
281 initComponent: function() {
282 /*jslint confusion: true */
283 var me = this;
284
285 // we expect noout to be not set by default
286 var noout = false;
287 me.maxversion = "0";
288
289 var nodename = me.pveSelNode.data.node;
290 if (!nodename) {
291 throw "no node name specified";
292 }
293
294 var sm = Ext.create('Ext.selection.TreeModel', {});
295
296 var set_button_status; // defined later
297
298 var reload = function() {
299 Proxmox.Utils.API2Request({
300 url: "/nodes/" + nodename + "/ceph/osd",
301 waitMsgTarget: me,
302 method: 'GET',
303 failure: function(response, opts) {
304 var msg = response.htmlStatus;
305 PVE.Utils.showCephInstallOrMask(me, msg, me.pveSelNode.data.node,
306 function(win){
307 me.mon(win, 'cephInstallWindowClosed', function(){
308 reload();
309 });
310 }
311 );
312 },
313 success: function(response, opts) {
314 var data = response.result.data;
315 sm.deselectAll();
316 me.setRootNode(data.root);
317 me.expandAll();
318 // extract noout flag
319 if (data.flags && data.flags.search(/noout/) !== -1) {
320 noout = true;
321 } else {
322 noout = false;
323 }
324
325 me.versions = data.versions;
326 // extract max version
327 Object.values(data.versions || {}).forEach(function(version) {
328 if (PVE.Utils.compare_ceph_versions(version, me.maxversion) > 0) {
329 me.maxversion = version;
330 }
331 });
332 set_button_status();
333 }
334 });
335 };
336
337 var osd_cmd = function(cmd) {
338 var rec = sm.getSelection()[0];
339 if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
340 return;
341 }
342 Proxmox.Utils.API2Request({
343 url: "/nodes/" + rec.data.host + "/ceph/osd/" +
344 rec.data.id + '/' + cmd,
345 waitMsgTarget: me,
346 method: 'POST',
347 success: reload,
348 failure: function(response, opts) {
349 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
350 }
351 });
352 };
353
354 var service_cmd = function(cmd) {
355 var rec = sm.getSelection()[0];
356 if (!(rec && rec.data.name && rec.data.host)) {
357 return;
358 }
359 Proxmox.Utils.API2Request({
360 url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
361 params: { service: rec.data.name },
362 waitMsgTarget: me,
363 method: 'POST',
364 success: function(response, options) {
365 var upid = response.result.data;
366 var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
367 win.show();
368 me.mon(win, 'close', reload, me);
369 },
370 failure: function(response, opts) {
371 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
372 }
373 });
374 };
375
376 var create_btn = new Proxmox.button.Button({
377 text: gettext('Create') + ': OSD',
378 handler: function() {
379 var rec = sm.getSelection()[0];
380
381 var win = Ext.create('PVE.CephCreateOsd', {
382 nodename: nodename
383 });
384 win.show();
385 me.mon(win, 'close', reload, me);
386 }
387 });
388
389 var start_btn = new Ext.Button({
390 text: gettext('Start'),
391 disabled: true,
392 handler: function(){ service_cmd('start'); }
393 });
394
395 var stop_btn = new Ext.Button({
396 text: gettext('Stop'),
397 disabled: true,
398 handler: function(){ service_cmd('stop'); }
399 });
400
401 var restart_btn = new Ext.Button({
402 text: gettext('Restart'),
403 disabled: true,
404 handler: function(){ service_cmd('restart'); }
405 });
406
407 var osd_out_btn = new Ext.Button({
408 text: 'Out',
409 disabled: true,
410 handler: function(){ osd_cmd('out'); }
411 });
412
413 var osd_in_btn = new Ext.Button({
414 text: 'In',
415 disabled: true,
416 handler: function(){ osd_cmd('in'); }
417 });
418
419 var remove_btn = new Ext.Button({
420 text: gettext('Destroy'),
421 disabled: true,
422 handler: function(){
423 var rec = sm.getSelection()[0];
424 if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
425 return;
426 }
427
428 var win = Ext.create('PVE.CephRemoveOsd', {
429 nodename: rec.data.host,
430 osdid: rec.data.id
431 });
432 win.show();
433 me.mon(win, 'close', reload, me);
434 }
435 });
436
437 var noout_btn = new Ext.Button({
438 text: gettext('Set noout'),
439 handler: function() {
440 Proxmox.Utils.API2Request({
441 url: "/nodes/" + nodename + "/ceph/flags/noout",
442 waitMsgTarget: me,
443 method: noout ? 'DELETE' : 'POST',
444 failure: function(response, opts) {
445 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
446 },
447 success: reload
448 });
449 }
450 });
451
452 var osd_label = new Ext.toolbar.TextItem({
453 data: {
454 osd: undefined
455 },
456 tpl: [
457 '<tpl if="osd">',
458 '{osd}:',
459 '<tpl else>',
460 gettext('No OSD selected'),
461 '</tpl>'
462 ]
463 });
464
465 set_button_status = function() {
466 var rec = sm.getSelection()[0];
467 noout_btn.setText(noout?gettext('Unset noout'):gettext('Set noout'));
468
469 if (!rec) {
470 start_btn.setDisabled(true);
471 stop_btn.setDisabled(true);
472 restart_btn.setDisabled(true);
473 remove_btn.setDisabled(true);
474 osd_out_btn.setDisabled(true);
475 osd_in_btn.setDisabled(true);
476 return;
477 }
478
479 var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
480
481 start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
482 stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
483 restart_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
484 remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
485
486 osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
487 osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
488
489 osd_label.update(isOsd?{osd:rec.data.name}:undefined);
490 };
491
492 sm.on('selectionchange', set_button_status);
493
494 var reload_btn = new Ext.Button({
495 text: gettext('Reload'),
496 handler: reload
497 });
498
499 Ext.apply(me, {
500 tbar: [ create_btn, reload_btn, noout_btn, '->', osd_label, start_btn, stop_btn, restart_btn, osd_out_btn, osd_in_btn, remove_btn ],
501 rootVisible: false,
502 useArrows: true,
503 fields: ['name', 'type', 'status', 'host', 'in', 'id' ,
504 { type: 'number', name: 'reweight' },
505 { type: 'number', name: 'percent_used' },
506 { type: 'integer', name: 'bytes_used' },
507 { type: 'integer', name: 'total_space' },
508 { type: 'integer', name: 'apply_latency_ms' },
509 { type: 'integer', name: 'commit_latency_ms' },
510 { type: 'string', name: 'device_class' },
511 { type: 'string', name: 'osdtype' },
512 { type: 'string', name: 'blfsdev' },
513 { type: 'string', name: 'dbdev' },
514 { type: 'string', name: 'waldev' },
515 { type: 'string', name: 'version', calculate: function(data) {
516 return PVE.Utils.parse_ceph_version(data);
517 } },
518 { type: 'string', name: 'iconCls', calculate: function(data) {
519 var iconCls = 'fa x-fa-tree fa-';
520 switch (data.type) {
521 case 'host':
522 iconCls += 'building';
523 break;
524 case 'osd':
525 iconCls += 'hdd-o';
526 break;
527 case 'root':
528 iconCls += 'server';
529 break;
530 default:
531 return undefined;
532 }
533 return iconCls;
534 } },
535 { type: 'number', name: 'crush_weight' }],
536 selModel: sm,
537
538 listeners: {
539 activate: function() {
540 reload();
541 }
542 }
543 });
544
545 me.callParent();
546
547 reload();
548 }
549 });