diff --git a/PVE/API2/Ceph.pm b/PVE/API2/Ceph.pm index 07f4f246..3d84142d 100644 --- a/PVE/API2/Ceph.pm +++ b/PVE/API2/Ceph.pm @@ -158,16 +158,16 @@ my $run_ceph_cmd = sub { die $err if $err; }; -my $run_ceph_cmd_json = sub { +my $run_ceph_cmd_text = sub { my ($cmd, %opts) = @_; - my $json = ''; + my $out = ''; my $quiet = delete $opts{quiet}; my $parser = sub { my $line = shift; - $json .= $line; + $out .= "$line\n"; }; my $errfunc = sub { @@ -175,12 +175,17 @@ my $run_ceph_cmd_json = sub { print "$line\n" if !$quiet; }; - &$run_ceph_cmd([@$cmd, '--format', 'json'], - outfunc => $parser, errfunc => $errfunc); + &$run_ceph_cmd($cmd, outfunc => $parser, errfunc => $errfunc); - my $res = decode_json($json); + return $out; +}; - return $res; +my $run_ceph_cmd_json = sub { + my ($cmd, %opts) = @_; + + my $json = &$run_ceph_cmd_text([@$cmd, '--format', 'json'], %opts); + + return decode_json($json); }; sub ceph_mon_status { @@ -261,6 +266,7 @@ __PACKAGE__->register_method ({ { name => 'stop' }, { name => 'start' }, { name => 'status' }, + { name => 'crush' }, ]; return $result; @@ -678,3 +684,29 @@ __PACKAGE__->register_method ({ return undef; }}); + +__PACKAGE__->register_method ({ + name => 'crush', + path => 'crush', + method => 'GET', + description => "Get OSD crush map", + proxyto => 'node', + protected => 1, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + }, + }, + returns => { type => 'string' }, + code => sub { + my ($param) = @_; + + &$check_ceph_inited(); + + my $txt = &$run_ceph_cmd_text(['osd', 'crush', 'dump'], quiet => 1); + + return $txt; + }}); + + diff --git a/www/manager/node/Ceph.js b/www/manager/node/Ceph.js index 31959a5b..bb134034 100644 --- a/www/manager/node/Ceph.js +++ b/www/manager/node/Ceph.js @@ -1,3 +1,50 @@ +Ext.define('PVE.node.CephCrushMap', { + extend: 'Ext.panel.Panel', + alias: 'widget.pveNodeCephCrushMap', + + load: function() { + var me = this; + + PVE.Utils.API2Request({ + url: me.url, + waitMsgTarget: me, + failure: function(response, opts) { + me.update(gettext('Error') + " " + response.htmlStatus); + }, + success: function(response, opts) { + var data = response.result.data; + me.update(data); + } + }); + }, + + initComponent: function() { + var me = this; + + var nodename = me.pveSelNode.data.node; + if (!nodename) { + throw "no node name specified"; + } + + Ext.apply(me, { + url: '/api2/extjs/nodes/' + nodename + '/ceph/crush', + style: 'padding-left:10px', + bodyStyle: 'white-space:pre', + bodyPadding: 5, + autoScroll: true, + listeners: { + show: function() { + me.load(); + } + } + }); + + me.callParent(); + + me.load(); + } +}); + Ext.define('PVE.node.CephStatus', { extend: 'PVE.grid.ObjectGrid', alias: 'widget.pveNodeCephStatus', @@ -178,8 +225,8 @@ Ext.define('PVE.node.Ceph', { }, { title: 'Crush', - itemId: 'test5', - html: "ABCD" + xtype: 'pveNodeCephCrushMap', + itemId: 'crushmap' } ], listeners: {