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);
use PVE::INotify;
use PVE::Cluster qw(cfs_register_file cfs_lock_file cfs_read_file cfs_write_file);
use PVE::Storage;
use PVE::API2Tools;
use PVE::API2::Backup;
use PVE::API2::HAConfig;
use JSON;
......@@ -178,30 +179,12 @@ __PACKAGE__->register_method({
# we try to generate 'numbers' by using "$X + 0"
if (!$param->{type} || $param->{type} eq 'vm') {
foreach my $vmid (keys %$idlist) {
my $data = $idlist->{$vmid};
next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
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;
my $data = $idlist->{$vmid};
my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd);
if (defined($entry->{uptime})) {
if (my $pool = $usercfg->{vms}->{$vmid}) {
if (my $pe = $pooldata->{$pool}) {
$pe->{uptime} = $entry->{uptime} if !$pe->{uptime} || $entry->{uptime} > $pe->{uptime};
......@@ -216,7 +199,6 @@ __PACKAGE__->register_method({
}
}
}
push @$res, $entry;
}
......@@ -254,23 +236,14 @@ __PACKAGE__->register_method({
my @sids = PVE::Storage::storage_ids ($cfg);
foreach my $storeid (@sids) {
my $scfg = PVE::Storage::storage_config($cfg, $storeid);
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
foreach my $node (@$nodelist) {
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;
}
}
......
......@@ -3,13 +3,16 @@ package PVE::API2::Pool;
use strict;
use warnings;
use PVE::Exception qw(raise_param_exc);
use PVE::INotify;
use PVE::Cluster qw (cfs_read_file cfs_write_file);
use PVE::AccessControl;
use PVE::Storage;
use PVE::SafeSyslog;
use Data::Dumper; # fixme: remove
use PVE::API2Tools;
use PVE::RESTHandler;
use base qw(PVE::RESTHandler);
......@@ -207,10 +210,11 @@ __PACKAGE__->register_method ({
type => 'array',
items => {
type => "object",
additionalProperties => 0,
additionalProperties => 1,
properties => {
type => { type => 'string', enum => ['vm', 'storage'] },
type => { type => 'string', enum => ['qemu', 'openvz', 'storage'] },
id => { type => 'string' },
node => { type => 'string' },
vmid => { type => 'integer', optional => 1 },
storage => { type => 'string', optional => 1 },
},
......@@ -223,6 +227,11 @@ __PACKAGE__->register_method ({
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 $data = $usercfg->{pools}->{$pool};
......@@ -233,19 +242,23 @@ __PACKAGE__->register_method ({
my $members = [];
foreach my $vmid (keys %{$data->{vms}}) {
push @$members, {
id => "vm/$vmid",
vmid => $vmid + 0,
type => 'vm',
};
my $vmdata = $idlist->{$vmid};
next if !$vmdata;
my $entry = PVE::API2Tools::extract_vm_stats($vmid, $vmdata, $rrd);
push @$members, $entry;
}
foreach my $storage (keys %{$data->{storage}}) {
push @$members, {
id => "storage/$storage",
storage => $storage,
type => 'storage',
};
my $nodename = PVE::INotify::nodename();
my $cfg = PVE::Storage::config();
foreach my $storeid (keys %{$data->{storage}}) {
my $scfg = PVE::Storage::storage_config ($cfg, $storeid, 1);
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 };
......
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
PERLSOURCE = \
API2.pm \
API2Tools.pm \
API2Client.pm \
APIDaemon.pm \
REST.pm \
......
......@@ -63,6 +63,7 @@ JSSRC= \
grid/SelectFeature.js \
grid/ObjectGrid.js \
grid/ResourceGrid.js \
grid/PoolMembers.js \
tree/ResourceTree.js \
panel/ConfigPanel.js \
grid/BackupView.js \
......
......@@ -17,7 +17,7 @@ Ext.define('PVE.RestProxy', {
noCache : false,
reader: {
type: 'json',
root: 'data'
root: config.root || 'data'
},
afterRequest: function(request, success) {
me.fireEvent('afterload', me, request, success);
......
......@@ -18,7 +18,7 @@ Ext.define('PVE.dc.vmHAServiceEdit', {
}
Ext.apply(me, {
title: gettext('HA managed VM/CT'),
subject: gettext('HA managed VM/CT'),
width: 350,
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', {
updateGrid();
};
Ext.applyIf(me, {
title: gettext('Search')
});
Ext.apply(me, {
title: gettext('Search'),
store: store,
tbar: [
'->',
......
......@@ -19,6 +19,12 @@ Ext.define('PVE.pool.Config', {
xtype: 'pvePoolSummary',
itemId: 'summary'
},
{
title: gettext('Members'),
xtype: 'pvePoolMembers',
pool: pool,
itemId: 'members'
},
{
xtype: 'pveACLView',
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