Commit 81ebd380 authored by Dietmar Maurer's avatar Dietmar Maurer

add Datacenter summary

parent ab247809
...@@ -3,6 +3,8 @@ package PVE::API2::Cluster; ...@@ -3,6 +3,8 @@ package PVE::API2::Cluster;
use strict; use strict;
use warnings; use warnings;
use XML::Parser;
use PVE::SafeSyslog; use PVE::SafeSyslog;
use PVE::Tools qw(extract_param); use PVE::Tools qw(extract_param);
use PVE::INotify; use PVE::INotify;
...@@ -66,6 +68,7 @@ __PACKAGE__->register_method ({ ...@@ -66,6 +68,7 @@ __PACKAGE__->register_method ({
{ name => 'tasks' }, { name => 'tasks' },
{ name => 'backup' }, { name => 'backup' },
{ name => 'ha' }, { name => 'ha' },
{ name => 'status' },
]; ];
return $result; return $result;
...@@ -347,4 +350,134 @@ __PACKAGE__->register_method({ ...@@ -347,4 +350,134 @@ __PACKAGE__->register_method({
return undef; return undef;
}}); }});
my $parse_clustat = sub {
my ($clinfo, $members, $nodename, $raw) = @_;
my $createNode = sub {
my ($expat, $tag, %attrib) = @_;
my $node = { type => $tag, %attrib };
if ($tag eq 'node') {
my $name = $node->{name};
return if !$name; # just to be sure
foreach my $key (qw(estranged local qdisk rgmanager rgmanager_master state)) {
$node->{$key} = int($node->{$key}) if defined($node->{$key});
}
$node->{nodeid} = hex($node->{nodeid}) if defined($node->{nodeid});
# unique ID for GUI
$node->{id} = "node/$node->{name}";
my $pmxcfs = 0;
if (!$members) { # no cluster
if ($name eq $nodename) {
$pmxcfs = ($clinfo && $clinfo->{version}) ? 1 : 0; # pmxcfs online ?
}
} elsif ($members->{$name}) {
$pmxcfs = $members->{$name}->{online} ? 1 : 0
}
$node->{pmxcfs} = $pmxcfs;
if ($members && $members->{$name}) {
if (my $ip = $members->{$name}->{ip}) {
$node->{ip} = $ip;
}
}
} elsif ($tag eq 'group') {
my $name = $node->{name};
return if !$name; # just to be sure
# unique ID for GUI
$node->{id} = "group/$node->{name}";
} else {
$node->{id} = $tag;
}
return $node;
};
my $extract_tags = {
cluster => 1,
quorum => 1,
node => 1,
group => 1,
};
my $handlers = {
Init => sub {
my $expat = shift;
$expat->{NodeList} = [];
},
Final => sub {
my $expat = shift;
$expat->{NodeList};
},
Start => sub {
my $expat = shift;
my $tag = shift;
if ($extract_tags->{$tag}) {
my $node = &$createNode($expat, $tag, @_);
push @{$expat->{NodeList}}, $node;
}
},
};
my $data = [];
if ($raw) {
my $parser = new XML::Parser(Handlers => $handlers);
$data = $parser->parse($raw);
}
return $data;
};
__PACKAGE__->register_method({
name => 'get_status',
path => 'status',
method => 'GET',
description => "Get cluster status informations.",
permissions => { user => 'all' },
protected => 1,
parameters => {
additionalProperties => 0,
properties => {},
},
returns => {
type => 'array',
items => {
type => "object",
properties => {
type => {
type => 'string'
},
},
},
},
code => sub {
my ($param) = @_;
# we also add info from pmxcfs
my $clinfo = PVE::Cluster::get_clinfo();
my $members = PVE::Cluster::get_members();
my $nodename = PVE::INotify::nodename();
if ($members) {
my $cmd = ['clustat', '-x'];
my $out = '';
PVE::Tools::run_command($cmd, outfunc => sub { $out .= shift; });
return &$parse_clustat($clinfo, $members, $nodename, $out);
} else {
# fake entry for local node if no cluster defined
my $pmxcfs = ($clinfo && $clinfo->{version}) ? 1 : 0; # pmxcfs online ?
return [{
type => 'node',
id => "node/$nodename",
name => $nodename,
'local' => 1,
nodeid => 0,
pmxcfs => $pmxcfs,
state => 1
}];
}
}});
1; 1;
pve-manager (2.0-18) unstable; urgency=low
* add Datacenter summary
-- Proxmox Support Team <support@proxmox.com> Fri, 23 Dec 2011 10:39:34 +0100
pve-manager (2.0-17) unstable; urgency=low pve-manager (2.0-17) unstable; urgency=low
* new HA configuration panel * new HA configuration panel
......
...@@ -3,7 +3,7 @@ Version: @VERSION@-@PACKAGERELEASE@ ...@@ -3,7 +3,7 @@ Version: @VERSION@-@PACKAGERELEASE@
Section: admin Section: admin
Priority: optional Priority: optional
Architecture: all Architecture: all
Depends: perl5, libtimedate-perl, apache2-mpm-prefork, libauthen-pam-perl, libintl-perl, rsync, libapache2-request-perl, libjson-perl, libdigest-sha1-perl, liblockfile-simple-perl, vncterm, qemu-server (>= 1.1-1), libwww-perl, wget, libnet-dns-perl, vlan, ifenslave-2.6 (>= 1.1.0-10), liblinux-inotify2-perl, debconf (>= 0.5) | debconf-2.0, netcat-traditional, pve-cluster, libpve-common-perl, libpve-storage-perl, libterm-readline-gnu-perl, libpve-access-control, libio-socket-ssl-perl, libfilesys-df-perl, libfile-readbackwards-perl, libfile-sync-perl, redhat-cluster-pve, cstream, mail-transport-agent Depends: perl5, libtimedate-perl, apache2-mpm-prefork, libauthen-pam-perl, libintl-perl, rsync, libapache2-request-perl, libjson-perl, libdigest-sha1-perl, liblockfile-simple-perl, vncterm, qemu-server (>= 1.1-1), libwww-perl, wget, libnet-dns-perl, vlan, ifenslave-2.6 (>= 1.1.0-10), liblinux-inotify2-perl, debconf (>= 0.5) | debconf-2.0, netcat-traditional, pve-cluster, libpve-common-perl, libpve-storage-perl, libterm-readline-gnu-perl, libpve-access-control, libio-socket-ssl-perl, libfilesys-df-perl, libfile-readbackwards-perl, libfile-sync-perl, redhat-cluster-pve, cstream, mail-transport-agent, libxml-parser-perl
Conflicts: netcat-openbsd, vzdump Conflicts: netcat-openbsd, vzdump
Replaces: vzdump Replaces: vzdump
Provides: vzdump Provides: vzdump
......
...@@ -2,7 +2,7 @@ RELEASE=2.0 ...@@ -2,7 +2,7 @@ RELEASE=2.0
VERSION=2.0 VERSION=2.0
PACKAGE=pve-manager PACKAGE=pve-manager
PACKAGERELEASE=17 PACKAGERELEASE=18
BINDIR=${DESTDIR}/usr/bin BINDIR=${DESTDIR}/usr/bin
PERLLIBDIR=${DESTDIR}/usr/share/perl5 PERLLIBDIR=${DESTDIR}/usr/share/perl5
......
...@@ -110,6 +110,7 @@ JSSRC= \ ...@@ -110,6 +110,7 @@ JSSRC= \
storage/NFSEdit.js \ storage/NFSEdit.js \
storage/IScsiEdit.js \ storage/IScsiEdit.js \
storage/LVMEdit.js \ storage/LVMEdit.js \
dc/Summary.js \
dc/OptionView.js \ dc/OptionView.js \
dc/StorageView.js \ dc/StorageView.js \
dc/UserEdit.js \ dc/UserEdit.js \
......
...@@ -9,6 +9,11 @@ Ext.define('PVE.dc.Config', { ...@@ -9,6 +9,11 @@ Ext.define('PVE.dc.Config', {
title: gettext("Datacenter"), title: gettext("Datacenter"),
hstateid: 'dctab', hstateid: 'dctab',
items: [ items: [
{
title: gettext('Summary'),
xtype: 'pveDcSummary',
itemId: 'summary'
},
{ {
xtype: 'pveDcOptionView', xtype: 'pveDcOptionView',
title: gettext('Options'), title: gettext('Options'),
......
Ext.define('PVE.dc.NodeView', {
extend: 'Ext.grid.GridPanel',
alias: ['widget.pveDcNodeView'],
initComponent : function() {
var me = this;
var rstore = Ext.create('PVE.data.UpdateStore', {
interval: 3000,
storeid: 'pve-dc-nodes',
model: 'pve-dc-nodes',
proxy: {
type: 'pve',
url: "/api2/json/cluster/status"
},
filters: {
property: 'type',
value : 'node'
}
});
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
Ext.apply(me, {
store: store,
stateful: false,
columns: [
{
header: gettext('Name'),
width: 200,
sortable: true,
dataIndex: 'name'
},
{
header: 'ID',
width: 50,
sortable: true,
dataIndex: 'nodeid'
},
{
header: gettext('Online'),
width: 100,
sortable: true,
dataIndex: 'state',
renderer: PVE.Utils.format_boolean
},
{
header: gettext('Estranged'),
width: 100,
sortable: true,
dataIndex: 'estranged',
renderer: PVE.Utils.format_boolean
},
{
header: gettext('Server Address'),
width: 100,
sortable: true,
dataIndex: 'ip'
},
{
header: gettext('Services'),
flex: 1,
width: 80,
sortable: true,
dataIndex: 'pmxcfs',
renderer: function(value, metaData, record) {
var list = [];
var data = record.data;
if (data) {
if (data.pmxcfs) {
list.push('PVECluster');
}
if (data.rgmanager) {
list.push('RGManager');
}
}
return list.join(', ');
}
}
],
listeners: {
show: rstore.startUpdate,
hide: rstore.stopUpdate,
destroy: rstore.stopUpdate
}
});
me.callParent();
}
}, function() {
Ext.define('pve-dc-nodes', {
extend: 'Ext.data.Model',
fields: [ 'id', 'type', 'name', 'state', 'nodeid', 'ip',
'pmxcfs', 'rgmanager', 'estranged' ],
idProperty: 'id'
});
});
Ext.define('PVE.dc.HAServiceView', {
extend: 'Ext.grid.GridPanel',
alias: ['widget.pveHaServiceView'],
initComponent : function() {
var me = this;
var rstore = Ext.create('PVE.data.UpdateStore', {
interval: 3000,
storeid: 'pve-ha-services',
model: 'pve-ha-services',
proxy: {
type: 'pve',
url: "/api2/json/cluster/status"
},
filters: {
property: 'type',
value : 'group'
}
});
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
var noClusterText = gettext("Standalone node - no cluster defined");
var status = Ext.create('Ext.Component', {
padding: 2,
html: '&nbsp;',
dock: 'bottom'
});
Ext.apply(me, {
store: store,
stateful: false,
//tbar: [ 'start', 'stop' ],
bbar: [ status ],
columns: [
{
header: gettext('Name'),
flex: 1,
sortable: true,
dataIndex: 'name'
},
{
header: gettext('Owner'),
flex: 1,
sortable: true,
dataIndex: 'owner'
},
{
header: gettext('State'),
width: 80,
sortable: true,
dataIndex: 'state_str'
},
{
header: gettext('Restarts'),
width: 80,
sortable: true,
dataIndex: 'restarts'
},
{
header: gettext('Last transition'),
width: 200,
sortable: true,
dataIndex: 'last_transition'
},
{
header: gettext('Last owner'),
flex: 1,
sortable: true,
dataIndex: 'last_owner'
},
],
listeners: {
show: rstore.startUpdate,
hide: rstore.stopUpdate,
destroy: rstore.stopUpdate
}
});
me.callParent();
rstore.on('load', function(s, records, success) {
if (!success) {
return;
}
var cluster_rec = rstore.getById('cluster');
var quorum_rec = rstore.getById('quorum');
if (!(cluster_rec && quorum_rec)) {
status.update(noClusterText);
return;
}
var cluster_raw = cluster_rec.raw;
var quorum_raw = quorum_rec.raw;
if (!(cluster_raw && quorum_raw)) {
status.update(noClusterText);
return;
}
status.update("Quorate: " + PVE.Utils.format_boolean(quorum_raw.quorate));
});
}
}, function() {
Ext.define('pve-ha-services', {
extend: 'Ext.data.Model',
fields: [ 'id', 'type', 'name', 'owner', 'last_owner', 'state_str', 'restarts',
{ name: 'last_transition', type: 'date', dateFormat: 'timestamp'}
],
idProperty: 'id'
});
});
Ext.define('PVE.dc.Summary', {
extend: 'Ext.panel.Panel',
alias: 'widget.pveDcSummary',
initComponent: function() {
var me = this;
var hagrid = Ext.create('PVE.dc.HAServiceView', {
title: gettext('HA Service Status'),
region: 'south',
border: false,
split: true,
flex: 1
});
var nodegrid = Ext.create('PVE.dc.NodeView', {
title: gettext('Nodes'),
border: false,
region: 'center',
flex: 3
});
Ext.apply(me, {
layout: 'border',
items: [ nodegrid, hagrid ],
listeners: {
show: function() {
hagrid.fireEvent('show', hagrid);
nodegrid.fireEvent('show', hagrid);
},
hide: function() {
hagrid.fireEvent('hide', hagrid);
nodegrid.fireEvent('hide', hagrid);
}
}
});
me.callParent();
}
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment