]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/OSD.js
added basic ability to install ceph via gui
[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: 'weight',
181 dataIndex: 'crush_weight',
182 align: 'right',
183 renderer: function(value, metaData, rec) {
184 if (rec.data.type !== 'osd') {
185 return '';
186 }
187 return value;
188 },
189 width: 80
190 },
191 {
192 text: 'reweight',
193 dataIndex: 'reweight',
194 align: 'right',
195 renderer: function(value, metaData, rec) {
196 if (rec.data.type !== 'osd') {
197 return '';
198 }
199 return value;
200 },
201 width: 90
202 },
203 {
204 header: gettext('Used'),
205 columns: [
206 {
207 text: '%',
208 dataIndex: 'percent_used',
209 align: 'right',
210 renderer: function(value, metaData, rec) {
211 if (rec.data.type !== 'osd') {
212 return '';
213 }
214 return Ext.util.Format.number(value, '0.00');
215 },
216 width: 80
217 },
218 {
219 text: gettext('Total'),
220 dataIndex: 'total_space',
221 align: 'right',
222 renderer: function(value, metaData, rec) {
223 if (rec.data.type !== 'osd') {
224 return '';
225 }
226 return PVE.Utils.render_size(value);
227 },
228 width: 100
229 }
230 ]
231 },
232 {
233 header: gettext('Latency (ms)'),
234 columns: [
235 {
236 text: 'Apply',
237 dataIndex: 'apply_latency_ms',
238 align: 'right',
239 renderer: function(value, metaData, rec) {
240 if (rec.data.type !== 'osd') {
241 return '';
242 }
243 return value;
244 },
245 width: 60
246 },
247 {
248 text: 'Commit',
249 dataIndex: 'commit_latency_ms',
250 align: 'right',
251 renderer: function(value, metaData, rec) {
252 if (rec.data.type !== 'osd') {
253 return '';
254 }
255 return value;
256 },
257 width: 60
258 }
259 ]
260 }
261 ],
262 initComponent: function() {
263 /*jslint confusion: true */
264 var me = this;
265
266 // we expect noout to be not set by default
267 var noout = false;
268
269 var nodename = me.pveSelNode.data.node;
270 if (!nodename) {
271 throw "no node name specified";
272 }
273
274 var sm = Ext.create('Ext.selection.TreeModel', {});
275
276 var set_button_status; // defined later
277
278 var reload = function() {
279 Proxmox.Utils.API2Request({
280 url: "/nodes/" + nodename + "/ceph/osd",
281 waitMsgTarget: me,
282 method: 'GET',
283 failure: function(response, opts) {
284 var msg = response.htmlStatus;
285 PVE.Utils.showCephInstallOrMask(me, msg, me.pveSelNode.data.node,
286 function(win){
287 me.mon(win, 'cephInstallWindowClosed', function(){
288 reload();
289 });
290 }
291 );
292 },
293 success: function(response, opts) {
294 sm.deselectAll();
295 me.setRootNode(response.result.data.root);
296 me.expandAll();
297 // extract noout flag
298 if (response.result.data.flags &&
299 response.result.data.flags.search(/noout/) !== -1) {
300 noout = true;
301 } else {
302 noout = false;
303 }
304 set_button_status();
305 }
306 });
307 };
308
309 var osd_cmd = function(cmd) {
310 var rec = sm.getSelection()[0];
311 if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
312 return;
313 }
314 Proxmox.Utils.API2Request({
315 url: "/nodes/" + rec.data.host + "/ceph/osd/" +
316 rec.data.id + '/' + cmd,
317 waitMsgTarget: me,
318 method: 'POST',
319 success: reload,
320 failure: function(response, opts) {
321 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
322 }
323 });
324 };
325
326 var service_cmd = function(cmd) {
327 var rec = sm.getSelection()[0];
328 if (!(rec && rec.data.name && rec.data.host)) {
329 return;
330 }
331 Proxmox.Utils.API2Request({
332 url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
333 params: { service: rec.data.name },
334 waitMsgTarget: me,
335 method: 'POST',
336 success: function(response, options) {
337 var upid = response.result.data;
338 var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
339 win.show();
340 me.mon(win, 'close', reload, me);
341 },
342 failure: function(response, opts) {
343 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
344 }
345 });
346 };
347
348 var create_btn = new Proxmox.button.Button({
349 text: gettext('Create') + ': OSD',
350 handler: function() {
351 var rec = sm.getSelection()[0];
352
353 var win = Ext.create('PVE.CephCreateOsd', {
354 nodename: nodename
355 });
356 win.show();
357 me.mon(win, 'close', reload, me);
358 }
359 });
360
361 var start_btn = new Ext.Button({
362 text: gettext('Start'),
363 disabled: true,
364 handler: function(){ service_cmd('start'); }
365 });
366
367 var stop_btn = new Ext.Button({
368 text: gettext('Stop'),
369 disabled: true,
370 handler: function(){ service_cmd('stop'); }
371 });
372
373 var restart_btn = new Ext.Button({
374 text: gettext('Restart'),
375 disabled: true,
376 handler: function(){ service_cmd('restart'); }
377 });
378
379 var osd_out_btn = new Ext.Button({
380 text: 'Out',
381 disabled: true,
382 handler: function(){ osd_cmd('out'); }
383 });
384
385 var osd_in_btn = new Ext.Button({
386 text: 'In',
387 disabled: true,
388 handler: function(){ osd_cmd('in'); }
389 });
390
391 var remove_btn = new Ext.Button({
392 text: gettext('Destroy'),
393 disabled: true,
394 handler: function(){
395 var rec = sm.getSelection()[0];
396 if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
397 return;
398 }
399
400 var win = Ext.create('PVE.CephRemoveOsd', {
401 nodename: rec.data.host,
402 osdid: rec.data.id
403 });
404 win.show();
405 me.mon(win, 'close', reload, me);
406 }
407 });
408
409 var noout_btn = new Ext.Button({
410 text: gettext('Set noout'),
411 handler: function() {
412 Proxmox.Utils.API2Request({
413 url: "/nodes/" + nodename + "/ceph/flags/noout",
414 waitMsgTarget: me,
415 method: noout ? 'DELETE' : 'POST',
416 failure: function(response, opts) {
417 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
418 },
419 success: reload
420 });
421 }
422 });
423
424 var osd_label = new Ext.toolbar.TextItem({
425 data: {
426 osd: undefined
427 },
428 tpl: [
429 '<tpl if="osd">',
430 '{osd}:',
431 '<tpl else>',
432 gettext('No OSD selected'),
433 '</tpl>'
434 ]
435 });
436
437 set_button_status = function() {
438 var rec = sm.getSelection()[0];
439 noout_btn.setText(noout?gettext('Unset noout'):gettext('Set noout'));
440
441 if (!rec) {
442 start_btn.setDisabled(true);
443 stop_btn.setDisabled(true);
444 restart_btn.setDisabled(true);
445 remove_btn.setDisabled(true);
446 osd_out_btn.setDisabled(true);
447 osd_in_btn.setDisabled(true);
448 return;
449 }
450
451 var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
452
453 start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
454 stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
455 restart_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
456 remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
457
458 osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
459 osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
460
461 osd_label.update(isOsd?{osd:rec.data.name}:undefined);
462 };
463
464 sm.on('selectionchange', set_button_status);
465
466 var reload_btn = new Ext.Button({
467 text: gettext('Reload'),
468 handler: reload
469 });
470
471 Ext.apply(me, {
472 tbar: [ create_btn, reload_btn, noout_btn, '->', osd_label, start_btn, stop_btn, restart_btn, osd_out_btn, osd_in_btn, remove_btn ],
473 rootVisible: false,
474 useArrows: true,
475 fields: ['name', 'type', 'status', 'host', 'in', 'id' ,
476 { type: 'number', name: 'reweight' },
477 { type: 'number', name: 'percent_used' },
478 { type: 'integer', name: 'bytes_used' },
479 { type: 'integer', name: 'total_space' },
480 { type: 'integer', name: 'apply_latency_ms' },
481 { type: 'integer', name: 'commit_latency_ms' },
482 { type: 'string', name: 'device_class' },
483 { type: 'string', name: 'osdtype' },
484 { type: 'string', name: 'blfsdev' },
485 { type: 'string', name: 'dbdev' },
486 { type: 'string', name: 'waldev' },
487 { type: 'string', name: 'iconCls', calculate: function(data) {
488 var iconCls = 'fa x-fa-tree fa-';
489 switch (data.type) {
490 case 'host':
491 iconCls += 'building';
492 break;
493 case 'osd':
494 iconCls += 'hdd-o';
495 break;
496 case 'root':
497 iconCls += 'server';
498 break;
499 default:
500 return undefined;
501 }
502 return iconCls;
503 } },
504 { type: 'number', name: 'crush_weight' }],
505 selModel: sm,
506
507 listeners: {
508 activate: function() {
509 reload();
510 }
511 }
512 });
513
514 me.callParent();
515
516 reload();
517 }
518 });