]> git.proxmox.com Git - pve-manager.git/commitdiff
start ceph management GUI
authorDietmar Maurer <dietmar@proxmox.com>
Wed, 13 Nov 2013 10:01:24 +0000 (11:01 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 13 Nov 2013 10:01:24 +0000 (11:01 +0100)
PVE/API2/Ceph.pm
www/manager/Makefile
www/manager/node/Ceph.js [new file with mode: 0644]
www/manager/node/Config.js

index a16caac17fdea1d57aaac5933e63f2c73f588ed0..07f4f24667940b7372542b88a6d372cce61dc1a1 100644 (file)
@@ -80,6 +80,19 @@ my $check_ceph_inited = sub {
     return 1;
 };
 
+my $check_ceph_enabled = sub {
+    my ($noerr) = @_;
+
+    return undef if !&$check_ceph_inited($noerr);
+
+    if (! -f $ceph_cfgpath) {
+       die "pveceph configuration not enabled\n" if !$noerr;
+       return undef;
+    }
+
+    return 1;
+};
+
 my $force_symlink = sub {
     my ($old, $new) = @_;
 
@@ -143,13 +156,15 @@ my $run_ceph_cmd = sub {
     alarm($oldalarm) if $oldalarm;
 
     die $err if $err;
-
 };
 
-sub ceph_mon_status {
-    my ($quiet) = @_;
+my $run_ceph_cmd_json = sub {
+    my ($cmd, %opts) = @_;
 
     my $json = '';
+
+    my $quiet = delete $opts{quiet};
+
     my $parser = sub {
        my $line = shift;
        $json .= $line;
@@ -160,33 +175,25 @@ sub ceph_mon_status {
        print "$line\n" if !$quiet;
     };
 
-    &$run_ceph_cmd(['mon_status'], outfunc => $parser, errfunc => $errfunc);
+    &$run_ceph_cmd([@$cmd, '--format', 'json'], 
+                  outfunc => $parser, errfunc => $errfunc);
 
     my $res = decode_json($json);
 
     return $res;
-}
+};
 
-my $ceph_osd_status = sub {
+sub ceph_mon_status {
     my ($quiet) = @_;
+    return &$run_ceph_cmd_json(['mon_status'], quiet => $quiet);
 
-    my $json = '';
-    my $parser = sub {
-       my $line = shift;
-       $json .= $line;
-    };
-
-    my $errfunc = sub {
-       my $line = shift;
-       print "$line\n" if !$quiet;
-    };
-
-    &$run_ceph_cmd(['osd', 'dump', '--format', 'json'], 
-                  outfunc => $parser, errfunc => $errfunc);
+}
 
-    my $res = decode_json($json);
+my $ceph_osd_status = sub {
+    my ($quiet) = @_;
 
-    return $res;
+    return &$run_ceph_cmd_json(['osd', 'dump'], quiet => $quiet);
 };
 
 my $write_ceph_config = sub {
@@ -556,38 +563,9 @@ __PACKAGE__->register_method ({
     code => sub {
        my ($param) = @_;
 
-       my $res = { status => 'unknown' };
-
-       eval {
-           if (!&$check_ceph_installed(1)) {
-               $res->{status} = 'notinstalled';
-           }
-           if (! -f $ceph_cfgpath) {
-               $res->{status} = 'notconfigured';               
-               return;
-           } else {
-               $res->{status} = 'configured';
-           }
-
-           my $cfg = &$parse_ceph_config($pve_ceph_cfgpath);
-           $res->{config} = $cfg;
-
-           eval { 
-               my $monstat = ceph_mon_status(1);
-               $res->{monstat} = $monstat;
-           };
-           warn $@ if $@;
-
-           eval {
-               my $osdstat =  &$ceph_osd_status(1);
-               $res->{osdstat} = $osdstat;
-           };
-           warn $@ if $@;
-
-       };
-       warn $@ if $@;
+       &$check_ceph_enabled();
 
-       return $res;
+       return &$run_ceph_cmd_json(['status'], quiet => 1);
     }});
 
 __PACKAGE__->register_method ({
index 46c8a3284d16e282402139a76f42be56d9839bb7..4c73b8a63f05ffa4eacac9cbbcbe3af0a2995b3c 100644 (file)
@@ -85,6 +85,7 @@ JSSRC=                                                        \
        node/Tasks.js                                   \
        node/Subscription.js                            \
        node/APT.js                                     \
+       node/Ceph.js                                    \
        node/Config.js                                  \
        qemu/StatusView.js                              \
        window/Migrate.js                               \
diff --git a/www/manager/node/Ceph.js b/www/manager/node/Ceph.js
new file mode 100644 (file)
index 0000000..31959a5
--- /dev/null
@@ -0,0 +1,198 @@
+Ext.define('PVE.node.CephStatus', {
+    extend: 'PVE.grid.ObjectGrid',
+    alias: 'widget.pveNodeCephStatus',
+
+    initComponent: function() {
+        var me = this;
+
+       var nodename = me.pveSelNode.data.node;
+       if (!nodename) {
+           throw "no node name specified";
+       }
+
+       var renderquorum = function(value) {
+           if (!value) {
+               return '';
+           }
+           var txt = '';
+
+           Ext.Array.each(value, function(name) {
+               txt += name + ' ';
+           });
+
+           return txt;
+       };
+
+       var rendermonmap = function(d) {
+           if (!d) {
+               return '';
+           }
+
+           var txt =  'e' + d.epoch + ': ' + d.mons.length + " mons at ";
+
+           Ext.Array.each(d.mons, function(d) {
+               txt += d.name + '=' + d.addr + ',';
+           });
+
+           return txt;
+       };
+
+       var renderosdmap = function(value) {
+           if (!value || !value.osdmap) {
+               return '';
+           }
+
+           var d = value.osdmap;
+
+           var txt = 'e' + d.epoch + ': ';
+
+           txt += d.num_osds + ' osds: ' + d.num_up_osds + ' up, ' +
+               d.num_in_osds + " in";
+
+           return txt;
+       };
+
+       var renderhealth = function(value) {
+           if (!value || !value.overall_status) {
+               return '';
+           }
+
+           var txt = value.overall_status;
+           Ext.Array.each(value.summary, function(d) {
+               txt += " " + d.summary + ';';
+           });
+
+           return txt;
+       };
+
+       var renderpgmap = function(d) {
+           if (!d) {
+               return '';
+           }
+
+           var txt = 'v' + d.version + ': ';
+
+           txt += d.num_pgs + " pgs:";
+
+           Ext.Array.each(d.pgs_by_state, function(s) {
+               txt += " " + s.count + " " + s.state_name;
+           });
+           txt += '; ';
+
+           txt += d.data_bytes + " bytes data, ";
+           txt += d.bytes_used + " bytes used, ";
+           txt += d.bytes_avail + " bytes avail";
+
+           return txt;
+       };
+
+       Ext.applyIf(me, {
+           url: "/api2/json/nodes/" + nodename + "/ceph/status",
+           cwidth1: 150,
+           interval: 3000,
+           rows: {
+               health: { 
+                   header: 'health', 
+                   renderer: renderhealth, 
+                   required: true
+               },
+               fsid: { 
+                   header: 'cluster', 
+                   required: true
+               },
+               monmap: {
+                   header: 'monmap',
+                   renderer: rendermonmap, 
+                   required: true
+               },
+               quorum_names: {
+                   header: 'quorum',
+                   renderer: renderquorum, 
+                   required: true
+               },
+               osdmap: {
+                   header: 'osdmap',
+                   renderer: renderosdmap, 
+                   required: true
+               },
+               pgmap: {
+                   header: 'pgmap',
+                   renderer: renderpgmap, 
+                   required: true
+               }
+           }
+       });
+
+       me.callParent();
+
+       me.on('show', me.rstore.startUpdate);
+       me.on('hide', me.rstore.stopUpdate);
+       me.on('destroy', me.rstore.stopUpdate); 
+    }
+});
+
+Ext.define('PVE.node.Ceph', {
+    extend: 'Ext.tab.Panel',
+    alias: 'widget.pveNodeCeph',
+
+    initComponent: function() {
+        var me = this;
+
+       var nodename = me.pveSelNode.data.node;
+       if (!nodename) {
+           throw "no node name specified";
+       }
+
+       Ext.apply(me, {
+           plain: true,
+           tabPosition: 'bottom',
+           defaults: {
+               border: false,
+               pveSelNode: me.pveSelNode
+           },
+           items: [
+               {
+                   xtype: 'pveNodeCephStatus',
+                   title: 'Status',
+                   itemId: 'status'
+               },
+               {
+                   title: 'Config',
+                   itemId: 'config',
+                   html: "ABCD"
+               },
+               {
+                   title: 'Monitor',
+                   itemId: 'test2',
+                   html: "ABCD"
+               },
+               {
+                   title: 'OSD',
+                   itemId: 'test3',
+                   html: "ABCD"
+               },
+               {
+                   title: 'Pool',
+                   itemId: 'test4',
+                   html: "ABCD"
+               },
+               {
+                   title: 'Crush',
+                   itemId: 'test5',
+                   html: "ABCD"
+               }
+           ],
+           listeners: {
+               afterrender: function(tp) {
+                   var first =  tp.items.get(0);
+                   if (first) {
+                       first.fireEvent('show', first);
+                   }
+               }
+           }
+       });
+
+       me.callParent();
+
+    }
+});
\ No newline at end of file
index d80c725d9195d655fca0f54fd150c0084d707f65..fb18c2d49c6e7dbf9e467c581725e7ae330e5316 100644 (file)
@@ -154,6 +154,12 @@ Ext.define('PVE.node.Config', {
                xtype: 'pveNodeAPT',
                nodename: nodename
            }]);
+           me.items.push([{
+               title: 'Ceph',
+               itemId: 'ceph',
+               xtype: 'pveNodeCeph',
+               nodename: nodename
+           }]);
        }
 
        me.callParent();