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) = @_;
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;
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 {
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 ({
--- /dev/null
+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