Commit 3813e7b4 authored by Dietmar Maurer's avatar Dietmar Maurer

implement PoolMember GUI

parent 3550d09f
...@@ -10,6 +10,7 @@ use PVE::Tools qw(extract_param); ...@@ -10,6 +10,7 @@ use PVE::Tools qw(extract_param);
use PVE::INotify; use PVE::INotify;
use PVE::Cluster qw(cfs_register_file cfs_lock_file cfs_read_file cfs_write_file); use PVE::Cluster qw(cfs_register_file cfs_lock_file cfs_read_file cfs_write_file);
use PVE::Storage; use PVE::Storage;
use PVE::API2Tools;
use PVE::API2::Backup; use PVE::API2::Backup;
use PVE::API2::HAConfig; use PVE::API2::HAConfig;
use JSON; use JSON;
...@@ -178,30 +179,12 @@ __PACKAGE__->register_method({ ...@@ -178,30 +179,12 @@ __PACKAGE__->register_method({
# we try to generate 'numbers' by using "$X + 0" # we try to generate 'numbers' by using "$X + 0"
if (!$param->{type} || $param->{type} eq 'vm') { if (!$param->{type} || $param->{type} eq 'vm') {
foreach my $vmid (keys %$idlist) { foreach my $vmid (keys %$idlist) {
my $data = $idlist->{$vmid};
next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1); next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
my $entry = { my $data = $idlist->{$vmid};
id => "$data->{type}/$vmid", my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd);
vmid => $vmid + 0, if (defined($entry->{uptime})) {
node => $data->{node},
type => $data->{type},
};
if (my $d = $rrd->{"pve2-vm/$vmid"}) {
$entry->{uptime} = ($d->[0] || 0) + 0;
$entry->{name} = $d->[1];
$entry->{maxcpu} = ($d->[3] || 0) + 0;
$entry->{cpu} = ($d->[4] || 0) + 0;
$entry->{maxmem} = ($d->[5] || 0) + 0;
$entry->{mem} = ($d->[6] || 0) + 0;
$entry->{maxdisk} = ($d->[7] || 0) + 0;
$entry->{disk} = ($d->[8] || 0) + 0;
if (my $pool = $usercfg->{vms}->{$vmid}) { if (my $pool = $usercfg->{vms}->{$vmid}) {
if (my $pe = $pooldata->{$pool}) { if (my $pe = $pooldata->{$pool}) {
$pe->{uptime} = $entry->{uptime} if !$pe->{uptime} || $entry->{uptime} > $pe->{uptime}; $pe->{uptime} = $entry->{uptime} if !$pe->{uptime} || $entry->{uptime} > $pe->{uptime};
...@@ -216,7 +199,6 @@ __PACKAGE__->register_method({ ...@@ -216,7 +199,6 @@ __PACKAGE__->register_method({
} }
} }
} }
push @$res, $entry; push @$res, $entry;
} }
...@@ -254,23 +236,14 @@ __PACKAGE__->register_method({ ...@@ -254,23 +236,14 @@ __PACKAGE__->register_method({
my @sids = PVE::Storage::storage_ids ($cfg); my @sids = PVE::Storage::storage_ids ($cfg);
foreach my $storeid (@sids) { foreach my $storeid (@sids) {
my $scfg = PVE::Storage::storage_config($cfg, $storeid);
next if !$rpcenv->check($authuser, "/storage/$storeid", [ 'Datastore.Audit' ], 1); next if !$rpcenv->check($authuser, "/storage/$storeid", [ 'Datastore.Audit' ], 1);
my $scfg = PVE::Storage::storage_config($cfg, $storeid);
# we create a entry for each node # we create a entry for each node
foreach my $node (@$nodelist) { foreach my $node (@$nodelist) {
next if !PVE::Storage::storage_check_enabled($cfg, $storeid, $node, 1); next if !PVE::Storage::storage_check_enabled($cfg, $storeid, $node, 1);
my $entry = {
id => "storage/$node/$storeid",
storage => $storeid,
node => $node,
type => 'storage',
};
if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) {
$entry->{maxdisk} = ($d->[1] || 0) + 0;
$entry->{disk} = ($d->[2] || 0) + 0;
}
my $entry = PVE::API2Tools::extract_storage_stats($storeid, $scfg, $node, $rrd);
push @$res, $entry; push @$res, $entry;
} }
} }
......
...@@ -3,13 +3,16 @@ package PVE::API2::Pool; ...@@ -3,13 +3,16 @@ package PVE::API2::Pool;
use strict; use strict;
use warnings; use warnings;
use PVE::Exception qw(raise_param_exc); use PVE::Exception qw(raise_param_exc);
use PVE::INotify;
use PVE::Cluster qw (cfs_read_file cfs_write_file); use PVE::Cluster qw (cfs_read_file cfs_write_file);
use PVE::AccessControl; use PVE::AccessControl;
use PVE::Storage;
use PVE::SafeSyslog; use PVE::SafeSyslog;
use Data::Dumper; # fixme: remove use Data::Dumper; # fixme: remove
use PVE::API2Tools;
use PVE::RESTHandler; use PVE::RESTHandler;
use base qw(PVE::RESTHandler); use base qw(PVE::RESTHandler);
...@@ -207,10 +210,11 @@ __PACKAGE__->register_method ({ ...@@ -207,10 +210,11 @@ __PACKAGE__->register_method ({
type => 'array', type => 'array',
items => { items => {
type => "object", type => "object",
additionalProperties => 0, additionalProperties => 1,
properties => { properties => {
type => { type => 'string', enum => ['vm', 'storage'] }, type => { type => 'string', enum => ['qemu', 'openvz', 'storage'] },
id => { type => 'string' }, id => { type => 'string' },
node => { type => 'string' },
vmid => { type => 'integer', optional => 1 }, vmid => { type => 'integer', optional => 1 },
storage => { type => 'string', optional => 1 }, storage => { type => 'string', optional => 1 },
}, },
...@@ -223,6 +227,11 @@ __PACKAGE__->register_method ({ ...@@ -223,6 +227,11 @@ __PACKAGE__->register_method ({
my $usercfg = cfs_read_file("user.cfg"); my $usercfg = cfs_read_file("user.cfg");
my $vmlist = PVE::Cluster::get_vmlist() || {};
my $idlist = $vmlist->{ids} || {};
my $rrd = PVE::Cluster::rrd_dump();
my $pool = $param->{poolid}; my $pool = $param->{poolid};
my $data = $usercfg->{pools}->{$pool}; my $data = $usercfg->{pools}->{$pool};
...@@ -233,19 +242,23 @@ __PACKAGE__->register_method ({ ...@@ -233,19 +242,23 @@ __PACKAGE__->register_method ({
my $members = []; my $members = [];
foreach my $vmid (keys %{$data->{vms}}) { foreach my $vmid (keys %{$data->{vms}}) {
push @$members, { my $vmdata = $idlist->{$vmid};
id => "vm/$vmid", next if !$vmdata;
vmid => $vmid + 0, my $entry = PVE::API2Tools::extract_vm_stats($vmid, $vmdata, $rrd);
type => 'vm', push @$members, $entry;
};
} }
foreach my $storage (keys %{$data->{storage}}) { my $nodename = PVE::INotify::nodename();
push @$members, { my $cfg = PVE::Storage::config();
id => "storage/$storage", foreach my $storeid (keys %{$data->{storage}}) {
storage => $storage, my $scfg = PVE::Storage::storage_config ($cfg, $storeid, 1);
type => 'storage', next if !$scfg;
};
my $firstnode = $scfg->{nodes} && $scfg->{nodes}->[0];
my $node = $firstnode || $nodename;
my $entry = PVE::API2Tools::extract_storage_stats($storeid, $scfg, $node, $rrd);
push @$members, $entry;
} }
my $res = { members => $members }; my $res = { members => $members };
......
package PVE::API2Tools;
use strict;
use warnings;
sub extract_vm_stats {
my ($vmid, $data, $rrd) = @_;
my $entry = {
id => "$data->{type}/$vmid",
vmid => $vmid + 0,
node => $data->{node},
type => $data->{type},
};
if (my $d = $rrd->{"pve2-vm/$vmid"}) {
$entry->{uptime} = ($d->[0] || 0) + 0;
$entry->{name} = $d->[1];
$entry->{maxcpu} = ($d->[3] || 0) + 0;
$entry->{cpu} = ($d->[4] || 0) + 0;
$entry->{maxmem} = ($d->[5] || 0) + 0;
$entry->{mem} = ($d->[6] || 0) + 0;
$entry->{maxdisk} = ($d->[7] || 0) + 0;
$entry->{disk} = ($d->[8] || 0) + 0;
};
return $entry;
};
sub extract_storage_stats {
my ($storeid, $scfg, $node, $rrd) = @_;
my $entry = {
id => "storage/$node/$storeid",
storage => $storeid,
node => $node,
type => 'storage',
};
if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) {
$entry->{maxdisk} = ($d->[1] || 0) + 0;
$entry->{disk} = ($d->[2] || 0) + 0;
}
return $entry;
};
1;
...@@ -4,6 +4,7 @@ SUBDIRS=API2 VZDump ...@@ -4,6 +4,7 @@ SUBDIRS=API2 VZDump
PERLSOURCE = \ PERLSOURCE = \
API2.pm \ API2.pm \
API2Tools.pm \
API2Client.pm \ API2Client.pm \
APIDaemon.pm \ APIDaemon.pm \
REST.pm \ REST.pm \
......
...@@ -63,6 +63,7 @@ JSSRC= \ ...@@ -63,6 +63,7 @@ JSSRC= \
grid/SelectFeature.js \ grid/SelectFeature.js \
grid/ObjectGrid.js \ grid/ObjectGrid.js \
grid/ResourceGrid.js \ grid/ResourceGrid.js \
grid/PoolMembers.js \
tree/ResourceTree.js \ tree/ResourceTree.js \
panel/ConfigPanel.js \ panel/ConfigPanel.js \
grid/BackupView.js \ grid/BackupView.js \
......
...@@ -17,7 +17,7 @@ Ext.define('PVE.RestProxy', { ...@@ -17,7 +17,7 @@ Ext.define('PVE.RestProxy', {
noCache : false, noCache : false,
reader: { reader: {
type: 'json', type: 'json',
root: 'data' root: config.root || 'data'
}, },
afterRequest: function(request, success) { afterRequest: function(request, success) {
me.fireEvent('afterload', me, request, success); me.fireEvent('afterload', me, request, success);
......
...@@ -18,7 +18,7 @@ Ext.define('PVE.dc.vmHAServiceEdit', { ...@@ -18,7 +18,7 @@ Ext.define('PVE.dc.vmHAServiceEdit', {
} }
Ext.apply(me, { Ext.apply(me, {
title: gettext('HA managed VM/CT'), subject: gettext('HA managed VM/CT'),
width: 350, width: 350,
items: [ items: [
{ {
......
Ext.define('PVE.pool.AddVM', {
extend: 'PVE.window.Edit',
initComponent : function() {
var me = this;
if (!me.pool) {
throw "no pool specified";
}
me.create = true;
me.isAdd = true;
me.url = "/pools/" + me.pool;
me.method = 'PUT';
Ext.apply(me, {
subject: gettext('Virtual Machine'),
width: 350,
items: [
{
xtype: 'pveVMIDSelector',
name: 'vms',
validateExists: true,
value: '',
fieldLabel: "VM ID"
}
]
});
me.callParent();
}
});
Ext.define('PVE.pool.AddStorage', {
extend: 'PVE.window.Edit',
initComponent : function() {
var me = this;
if (!me.pool) {
throw "no pool specified";
}
me.create = true;
me.isAdd = true;
me.url = "/pools/" + me.pool;
me.method = 'PUT';
Ext.apply(me, {
subject: gettext('Storage'),
width: 350,
items: [
{
xtype: 'PVE.form.StorageSelector',
name: 'storage',
nodename: 'localhost',
autoSelect: false,
value: '',
fieldLabel: gettext("Storage")
}
]
});
me.callParent();
}
});
Ext.define('PVE.grid.PoolMembers', {
extend: 'Ext.grid.GridPanel',
alias: ['widget.pvePoolMembers'],
// fixme: dynamic status update ?
initComponent : function() {
var me = this;
if (!me.pool) {
throw "no pool specified";
}
var store = Ext.create('Ext.data.Store', {
model: 'PVEResources',
sorters: [
{
property : 'type',
direction: 'ASC'
}
],
proxy: {
type: 'pve',
root: 'data.members',
url: "/api2/json/pools/" + me.pool
}
});
var coldef = PVE.data.ResourceStore.defaultColums();
var reload = function() {
store.load();
};
var sm = Ext.create('Ext.selection.RowModel', {});
var remove_btn = new PVE.button.Button({
text: gettext('Remove'),
disabled: true,
selModel: sm,
confirmMsg: function (rec) {
return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
"'" + rec.data.id + "'");
},
handler: function(btn, event, rec) {
var params = { 'delete': 1 };
if (rec.data.type === 'storage') {
params.storage = rec.data.storage;
} else if (rec.data.type === 'qemu' || rec.data.type === 'openvz') {
params.vms = rec.data.vmid;
} else {
throw "unknown resource type";
}
PVE.Utils.API2Request({
url: '/pools/' + me.pool,
method: 'PUT',
params: params,
waitMsgTarget: me,
callback: function() {
reload();
},
failure: function (response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
}
});
}
});
Ext.apply(me, {
store: store,
selModel: sm,
tbar: [
{
text: gettext('Add'),
menu: new Ext.menu.Menu({
items: [
{
text: gettext('Virtual Machine'),
iconCls: 'pve-itype-icon-qemu',
handler: function() {
var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
win.on('destroy', reload);
win.show();
}
},
{
text: gettext('Storage'),
iconCls: 'pve-itype-icon-storage',
handler: function() {
var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
win.on('destroy', reload);
win.show();
}
}
]
})
},
remove_btn
],
viewConfig: {
stripeRows: true
},
columns: coldef
});
me.callParent();
reload();
}
});
\ No newline at end of file
...@@ -173,8 +173,11 @@ Ext.define('PVE.grid.ResourceGrid', { ...@@ -173,8 +173,11 @@ Ext.define('PVE.grid.ResourceGrid', {
updateGrid(); updateGrid();
}; };
Ext.applyIf(me, {
title: gettext('Search')
});
Ext.apply(me, { Ext.apply(me, {
title: gettext('Search'),
store: store, store: store,
tbar: [ tbar: [
'->', '->',
......
...@@ -19,6 +19,12 @@ Ext.define('PVE.pool.Config', { ...@@ -19,6 +19,12 @@ Ext.define('PVE.pool.Config', {
xtype: 'pvePoolSummary', xtype: 'pvePoolSummary',
itemId: 'summary' itemId: 'summary'
}, },
{
title: gettext('Members'),
xtype: 'pvePoolMembers',
pool: pool,
itemId: 'members'
},
{ {
xtype: 'pveACLView', xtype: 'pveACLView',
title: gettext('Permissions'), title: gettext('Permissions'),
......
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