]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/ceph/OSD.js
added basic ability to install ceph via gui
[pve-manager.git] / www / manager6 / ceph / OSD.js
index 31eeaca7d3f1d39095cbe7f7989c0ad7c1782507..cb3d5f0d17102932ed394b36b52163053c23dbfb 100644 (file)
@@ -1,45 +1,52 @@
 Ext.define('PVE.CephCreateOsd', {
-    extend: 'PVE.window.Edit',
+    extend: 'Proxmox.window.Edit',
     alias: ['widget.pveCephCreateOsd'],
 
     subject: 'Ceph OSD',
 
     showProgress: true,
 
+    onlineHelp: 'pve_ceph_osds',
+
     initComponent : function() {
-        /*jslint confusion: true */
         var me = this;
 
        if (!me.nodename) {
            throw "no node name specified";
        }
 
-       me.create = true;
-  
+       me.isCreate = true;
+
         Ext.applyIf(me, {
            url: "/nodes/" + me.nodename + "/ceph/osd",
-            method: 'POST',
-            items: [
-               {
-                  xtype: 'pveCephDiskSelector',
-                  name: 'dev',
-                  nodename: me.nodename,
-                  value: me.dev,
-                  diskType: 'unused',
-                  fieldLabel: gettext('Disk'),
-                  allowBlank: false
-              },
-               {
-                  xtype: 'pveCephDiskSelector',
-                  name: 'journal_dev',
-                  nodename: me.nodename,
-                  diskType: 'journal_disks',
-                  fieldLabel: gettext('Journal Disk'),
-                  value: '',
-                  autoSelect: false,
-                  allowBlank: true,
-                  emptyText: 'use OSD disk'
-              }
+           method: 'POST',
+           items: [
+               {
+                   xtype: 'pveDiskSelector',
+                   name: 'dev',
+                   nodename: me.nodename,
+                   diskType: 'unused',
+                   fieldLabel: gettext('Disk'),
+                   allowBlank: false
+               },
+               {
+                   xtype: 'pveDiskSelector',
+                   name: 'journal_dev',
+                   nodename: me.nodename,
+                   diskType: 'journal_disks',
+                   fieldLabel: gettext('Journal/DB Disk'),
+                   value: '',
+                   autoSelect: false,
+                   allowBlank: true,
+                   emptyText: 'use OSD disk'
+               },
+               {
+                   xtype: 'proxmoxcheckbox',
+                   name: 'bluestore',
+                   fieldLabel: 'Bluestore',
+                   uncheckedValue: '0',
+                   value: '1'
+               }
             ]
         });
 
@@ -48,15 +55,24 @@ Ext.define('PVE.CephCreateOsd', {
 });
 
 Ext.define('PVE.CephRemoveOsd', {
-    extend: 'PVE.window.Edit',
+    extend: 'Proxmox.window.Edit',
     alias: ['widget.pveCephRemoveOsd'],
 
     isRemove: true,
 
     showProgress: true,
-
+    method: 'DELETE',
+    items: [
+       {
+           xtype: 'proxmoxcheckbox',
+           name: 'cleanup',
+           checked: true,
+           labelWidth: 130,
+           fieldLabel: gettext('Remove Partitions')
+       }
+    ],
     initComponent : function() {
-        /*jslint confusion: true */
+
         var me = this;
 
        if (!me.nodename) {
@@ -66,22 +82,12 @@ Ext.define('PVE.CephRemoveOsd', {
            throw "no osdid specified";
        }
 
-       me.create = true;
+       me.isCreate = true;
+
+       me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
 
-       me.title = gettext('Remove') + ': ' + 'Ceph OSD osd.' + me.osdid;
         Ext.applyIf(me, {
-           url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid,
-            method: 'DELETE',
-            items: [
-               {
-                   xtype: 'pvecheckbox',
-                   name: 'cleanup',
-                   checked: true,
-                   labelWidth: 130,
-                   fieldLabel: gettext('Remove Partitions')
-               }
-             ]
+           url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
         });
 
         me.callParent();
@@ -91,11 +97,175 @@ Ext.define('PVE.CephRemoveOsd', {
 Ext.define('PVE.node.CephOsdTree', {
     extend: 'Ext.tree.Panel',
     alias: ['widget.pveNodeCephOsdTree'],
-
+    onlineHelp: 'chapter_pveceph',
+    stateful: true,
+    stateId: 'grid-ceph-osd',
+    columns: [
+       {
+           xtype: 'treecolumn',
+           text: 'Name',
+           dataIndex: 'name',
+           width: 150
+       },
+       {
+           text: 'Type',
+           dataIndex: 'type',
+           align: 'right',
+           width: 60
+       },
+       {
+           text: gettext("Class"),
+           dataIndex: 'device_class',
+           align: 'right',
+           width: 40
+       },
+       {
+           text: "OSD Type",
+           dataIndex: 'osdtype',
+           align: 'right',
+           width: 40
+       },
+       {
+           text: "Bluestore Device",
+           dataIndex: 'blfsdev',
+           align: 'right',
+           width: 40,
+           hidden: true
+       },
+       {
+           text: "DB Device",
+           dataIndex: 'dbdev',
+           align: 'right',
+           width: 40,
+           hidden: true
+       },
+       {
+           text: "WAL Device",
+           dataIndex: 'waldev',
+           align: 'right',
+           renderer: function(value, metaData, rec) {
+               if (!value &&
+                   rec.data.osdtype === 'bluestore' &&
+                   rec.data.type === 'osd') {
+                   return 'N/A';
+               }
+               return value;
+           },
+           width: 40,
+           hidden: true
+       },
+       {
+           text: 'Status',
+           dataIndex: 'status',
+           align: 'right',
+           renderer: function(value, metaData, rec) {
+               if (!value) {
+                   return value;
+               }
+               var inout = rec.data['in'] ? 'in' : 'out';
+               var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
+                                                 'critical fa-arrow-circle-down';
+
+               var inouticon = rec.data['in'] ? 'good fa-circle' :
+                                                'warning fa-circle-o';
+
+               var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
+                          inout + ' <i class="fa ' + inouticon + '"></i>';
+
+               return text;
+           },
+           width: 80
+       },
+       {
+           text: 'weight',
+           dataIndex: 'crush_weight',
+           align: 'right',
+           renderer: function(value, metaData, rec) {
+               if (rec.data.type !== 'osd') {
+                   return '';
+               }
+               return value;
+           },
+           width: 80
+       },
+       {
+           text: 'reweight',
+           dataIndex: 'reweight',
+           align: 'right',
+           renderer: function(value, metaData, rec) {
+               if (rec.data.type !== 'osd') {
+                   return '';
+               }
+               return value;
+           },
+           width: 90
+       },
+       {
+           header: gettext('Used'),
+           columns: [
+               {
+                   text: '%',
+                   dataIndex: 'percent_used',
+                   align: 'right',
+                   renderer: function(value, metaData, rec) {
+                       if (rec.data.type !== 'osd') {
+                           return '';
+                       }
+                       return Ext.util.Format.number(value, '0.00');
+                   },
+                   width: 80
+               },
+               {
+                   text: gettext('Total'),
+                   dataIndex: 'total_space',
+                   align: 'right',
+                   renderer: function(value, metaData, rec) {
+                       if (rec.data.type !== 'osd') {
+                           return '';
+                       }
+                       return PVE.Utils.render_size(value);
+                   },
+                   width: 100
+               }
+           ]
+       },
+       {
+           header: gettext('Latency (ms)'),
+           columns: [
+               {
+                   text: 'Apply',
+                   dataIndex: 'apply_latency_ms',
+                   align: 'right',
+                   renderer: function(value, metaData, rec) {
+                       if (rec.data.type !== 'osd') {
+                           return '';
+                       }
+                       return value;
+                   },
+                   width: 60
+               },
+               {
+                   text: 'Commit',
+                   dataIndex: 'commit_latency_ms',
+                   align: 'right',
+                   renderer: function(value, metaData, rec) {
+                       if (rec.data.type !== 'osd') {
+                           return '';
+                       }
+                       return value;
+                   },
+                   width: 60
+               }
+           ]
+       }
+    ],
     initComponent: function() {
         /*jslint confusion: true */
         var me = this;
 
+       // we expect noout to be not set by default
+       var noout = false;
+
        var nodename = me.pveSelNode.data.node;
        if (!nodename) {
            throw "no node name specified";
@@ -106,17 +276,31 @@ Ext.define('PVE.node.CephOsdTree', {
        var set_button_status; // defined later
 
        var reload = function() {
-           PVE.Utils.API2Request({
+           Proxmox.Utils.API2Request({
                 url: "/nodes/" + nodename + "/ceph/osd",
                waitMsgTarget: me,
                method: 'GET',
                failure: function(response, opts) {
-                   PVE.Utils.setErrorMask(me, response.htmlStatus);
+                   var msg = response.htmlStatus;
+                   PVE.Utils.showCephInstallOrMask(me, msg, me.pveSelNode.data.node,
+                       function(win){
+                           me.mon(win, 'cephInstallWindowClosed', function(){
+                               reload();
+                           });
+                       }
+                   );
                },
                success: function(response, opts) {
                    sm.deselectAll();
                    me.setRootNode(response.result.data.root);
                    me.expandAll();
+                   // extract noout flag
+                   if (response.result.data.flags &&
+                       response.result.data.flags.search(/noout/) !== -1) {
+                       noout = true;
+                   } else {
+                       noout = false;
+                   }
                    set_button_status();
                }
            });
@@ -127,8 +311,8 @@ Ext.define('PVE.node.CephOsdTree', {
            if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
                return;
            }
-           PVE.Utils.API2Request({
-                url: "/nodes/" + rec.data.host + "/ceph/osd/" + 
+           Proxmox.Utils.API2Request({
+                url: "/nodes/" + rec.data.host + "/ceph/osd/" +
                    rec.data.id + '/' + cmd,
                waitMsgTarget: me,
                method: 'POST',
@@ -144,14 +328,14 @@ Ext.define('PVE.node.CephOsdTree', {
            if (!(rec && rec.data.name && rec.data.host)) {
                return;
            }
-           PVE.Utils.API2Request({
+           Proxmox.Utils.API2Request({
                 url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
                params: { service: rec.data.name },
                waitMsgTarget: me,
                method: 'POST',
                success: function(response, options) {
                    var upid = response.result.data;
-                   var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
+                   var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
                    win.show();
                    me.mon(win, 'close', reload, me);
                },
@@ -161,6 +345,19 @@ Ext.define('PVE.node.CephOsdTree', {
            });
        };
 
+       var create_btn = new Proxmox.button.Button({
+           text: gettext('Create') + ': OSD',
+           handler: function() {
+               var rec = sm.getSelection()[0];
+
+               var win = Ext.create('PVE.CephCreateOsd', {
+                    nodename: nodename
+               });
+               win.show();
+               me.mon(win, 'close', reload, me);
+           }
+       });
+
        var start_btn = new Ext.Button({
            text: gettext('Start'),
            disabled: true,
@@ -173,6 +370,12 @@ Ext.define('PVE.node.CephOsdTree', {
            handler: function(){ service_cmd('stop'); }
        });
 
+       var restart_btn = new Ext.Button({
+           text: gettext('Restart'),
+           disabled: true,
+           handler: function(){ service_cmd('restart'); }
+       });
+
        var osd_out_btn = new Ext.Button({
            text: 'Out',
            disabled: true,
@@ -186,7 +389,7 @@ Ext.define('PVE.node.CephOsdTree', {
        });
 
        var remove_btn = new Ext.Button({
-           text: gettext('Remove'),
+           text: gettext('Destroy'),
            disabled: true,
            handler: function(){
                var rec = sm.getSelection()[0];
@@ -203,12 +406,42 @@ Ext.define('PVE.node.CephOsdTree', {
            }
        });
 
+       var noout_btn = new Ext.Button({
+           text: gettext('Set noout'),
+           handler: function() {
+               Proxmox.Utils.API2Request({
+                   url: "/nodes/" + nodename + "/ceph/flags/noout",
+                   waitMsgTarget: me,
+                   method: noout ? 'DELETE' : 'POST',
+                   failure: function(response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   },
+                   success: reload
+               });
+           }
+       });
+
+       var osd_label = new Ext.toolbar.TextItem({
+           data: {
+               osd: undefined
+           },
+           tpl: [
+               '<tpl if="osd">',
+               '{osd}:',
+               '<tpl else>',
+               gettext('No OSD selected'),
+               '</tpl>'
+           ]
+       });
+
        set_button_status = function() {
            var rec = sm.getSelection()[0];
+           noout_btn.setText(noout?gettext('Unset noout'):gettext('Set noout'));
 
            if (!rec) {
                start_btn.setDisabled(true);
                stop_btn.setDisabled(true);
+               restart_btn.setDisabled(true);
                remove_btn.setDisabled(true);
                osd_out_btn.setDisabled(true);
                osd_in_btn.setDisabled(true);
@@ -219,10 +452,13 @@ Ext.define('PVE.node.CephOsdTree', {
 
            start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
            stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
+           restart_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
            remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
 
            osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
            osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
+
+           osd_label.update(isOsd?{osd:rec.data.name}:undefined);
        };
 
        sm.on('selectionchange', set_button_status);
@@ -233,130 +469,43 @@ Ext.define('PVE.node.CephOsdTree', {
        });
 
        Ext.apply(me, {
-           tbar: [ reload_btn, start_btn, stop_btn, osd_out_btn, osd_in_btn, remove_btn ],
+           tbar: [ create_btn, reload_btn, noout_btn, '->', osd_label, start_btn, stop_btn, restart_btn, osd_out_btn, osd_in_btn, remove_btn ],
            rootVisible: false,
-           fields: ['name', 'type', 'status', 'host', 'in',
-                    { type: 'integer', name: 'id' }, 
-                    { type: 'number', name: 'reweight' }, 
-                    { type: 'number', name: 'percent_used' }, 
-                    { type: 'integer', name: 'bytes_used' }, 
+           useArrows: true,
+           fields: ['name', 'type', 'status', 'host', 'in', 'id' ,
+                    { type: 'number', name: 'reweight' },
+                    { type: 'number', name: 'percent_used' },
+                    { type: 'integer', name: 'bytes_used' },
                     { type: 'integer', name: 'total_space' },
                     { type: 'integer', name: 'apply_latency_ms' },
                     { type: 'integer', name: 'commit_latency_ms' },
+                    { type: 'string', name: 'device_class' },
+                    { type: 'string', name: 'osdtype' },
+                    { type: 'string', name: 'blfsdev' },
+                    { type: 'string', name: 'dbdev' },
+                    { type: 'string', name: 'waldev' },
+                    { type: 'string', name: 'iconCls', calculate: function(data) {
+                        var iconCls = 'fa x-fa-tree fa-';
+                        switch (data.type) {
+                           case 'host':
+                                iconCls += 'building';
+                                break;
+                           case 'osd':
+                                iconCls += 'hdd-o';
+                                break;
+                           case 'root':
+                                iconCls += 'server';
+                                break;
+                           default:
+                                return undefined;
+                        }
+                        return iconCls;
+                    } },
                     { type: 'number', name: 'crush_weight' }],
-           stateful: false,
            selModel: sm,
-           columns: [
-               {
-                   xtype: 'treecolumn',
-                   text: 'Name',
-                   dataIndex: 'name',
-                   width: 150
-               },
-               { 
-                   text: 'Type',
-                   dataIndex: 'type',
-                   align: 'right',
-                   width: 60            
-               },
-               { 
-                   text: 'Status',
-                   dataIndex: 'status',
-                   align: 'right',
-                   renderer: function(value, metaData, rec) {
-                       if (!value) {
-                           return value;
-                       }
-                       var data = rec.data;
-                       return value + '/' + (data['in'] ? 'in' : 'out');
-                   },
-                   width: 60
-               },
-               { 
-                   text: 'weight',
-                   dataIndex: 'crush_weight',
-                   align: 'right',
-                   renderer: function(value, metaData, rec) {
-                       if (rec.data.type !== 'osd') {
-                           return '';
-                       }
-                       return value;
-                   },
-                   width: 60
-               },
-               { 
-                   text: 'reweight',
-                   dataIndex: 'reweight',
-                   align: 'right',
-                   renderer: function(value, metaData, rec) {
-                       if (rec.data.type !== 'osd') {
-                           return '';
-                       }
-                       return value;
-                   },
-                   width: 60
-               },
-               {
-                   header: gettext('Used'),
-                   columns: [
-                       {
-                           text: '%',
-                           dataIndex: 'percent_used',
-                           align: 'right',
-                           renderer: function(value, metaData, rec) {
-                               if (rec.data.type !== 'osd') {
-                                   return '';
-                               }
-                               return Ext.util.Format.number(value, '0.00');
-                           },
-                           width: 80
-                       },
-                       {
-                           text: gettext('Total'),
-                           dataIndex: 'total_space',
-                           align: 'right',
-                           renderer: function(value, metaData, rec) {
-                               if (rec.data.type !== 'osd') {
-                                   return '';
-                               }
-                               return PVE.Utils.render_size(value);
-                           },
-                           width: 100
-                       }
-                   ]
-               },
-               {
-                   header: gettext('Latency (ms)'),
-                   columns: [
-                       {
-                           text: 'Apply',
-                           dataIndex: 'apply_latency_ms',
-                           align: 'right',
-                           renderer: function(value, metaData, rec) {
-                               if (rec.data.type !== 'osd') {
-                                   return '';
-                               }
-                               return value;
-                           },
-                           width: 60
-                       },
-                       {
-                           text: 'Commit',
-                           dataIndex: 'commit_latency_ms',
-                           align: 'right',
-                           renderer: function(value, metaData, rec) {
-                               if (rec.data.type !== 'osd') {
-                                   return '';
-                               }
-                               return value;
-                           },
-                           width: 60
-                       }
-                   ]
-               }
-           ],
+
            listeners: {
-               show: function() {
+               activate: function() {
                    reload();
                }
            }