<div dir="ltr">Hello,<div><br></div><div>We have a number of administrators using our PVE cluster, with hundreds of VM's that are grouped by customer in to Pools.   We were regularly getting complaints from our admin users about the difficulty in finding Virtual Machines that were for a specific customer.  As our VM's were already grouped by pool we decided to develop a new view  called "Pool View".  </div>
<div><br></div><div>The Pool View is very similar to the current Server View, but lists the Pools in the left hand column, and allows expansion of each pool to show the VM's within it.</div><div><br></div><div>This makes administration of pools and VM's a lot more logical, and faster.</div>
<div><br></div><div>The "Pool View" patch honors security permissions on Pools, and has been developed against PVE3.2 (we also have a tested patch for PVE3.0).  The Pool View does not list Storage Resources, as it clutters the view making locating VM's more cumbersome, and is just duplication of what can be done in the "Storage View".  </div>
<div><br></div><div>We figure that since this has been so useful for us, it would most likely be useful for other PVE users, and would be nice to see included in PVE.</div><div><br></div><div>Patch inline:</div><div><br></div>
<div><br></div><div><div>diff -Nuarp usr/share/perl5/PVE/AccessControl.pm usr/share/perl5/PVE/AccessControl.pm</div><div>--- usr/share/perl5/PVE/AccessControl.pm<span class="" style="white-space:pre">    </span>2014-06-27 16:23:34.305587119 +1200</div>
<div>+++ usr/share/perl5/PVE/AccessControl.pm<span class="" style="white-space:pre">    </span>2014-06-27 16:23:44.077692909 +1200</div><div>@@ -492,7 +492,7 @@ my $privgroups = {</div><div>     },</div><div> };</div><div> </div>
<div>-my $valid_privs = {};</div><div>+our $valid_privs = {};</div><div> </div><div> my $special_roles = {</div><div>     'NoAccess' => {}, # no priviledges</div><div>diff -Nuarp usr/share/perl5/PVE/API2/Cluster.pm usr/share/perl5/PVE/API2/Cluster.pm</div>
<div>--- usr/share/perl5/PVE/API2/Cluster.pm<span class="" style="white-space:pre">     </span>2014-06-27 16:22:37.302970017 +1200</div><div>+++ usr/share/perl5/PVE/API2/Cluster.pm<span class="" style="white-space:pre"> </span>2014-06-27 16:26:30.939493106 +1200</div>
<div>@@ -19,6 +19,8 @@ use PVE::RESTHandler;</div><div> use PVE::RPCEnvironment;</div><div> use PVE::JSONSchema qw(get_standard_option);</div><div> </div><div>+use PVE::AccessControl qw(valid_privs);</div><div>+</div><div>
 use base qw(PVE::RESTHandler);</div><div> </div><div> __PACKAGE__->register_method ({</div><div>@@ -160,12 +162,20 @@ __PACKAGE__->register_method({</div><div> <span class="" style="white-space:pre">    </span>my $vmlist = PVE::Cluster::get_vmlist() || {};</div>
<div> <span class="" style="white-space:pre">  </span>my $idlist = $vmlist->{ids} || {};</div><div> </div><div>+<span class="" style="white-space:pre">    </span>my $storage_pool = {};</div><div>+</div><div>+<span class="" style="white-space:pre">    </span>foreach my $pool (keys(%{$usercfg->{pools}})) {</div>
<div>+<span class="" style="white-space:pre">           </span>foreach my $storage (keys(%{$usercfg->{pools}->{$pool}->{storage}})) {</div><div>+<span class="" style="white-space:pre">                   </span>$storage_pool->{$storage}=$pool;</div>
<div>+<span class="" style="white-space:pre">           </span>}</div><div>+<span class="" style="white-space:pre"> </span>}</div><div>+</div><div> <span class="" style="white-space:pre">        </span>my $pooldata = {};</div><div> <span class="" style="white-space:pre">       </span>if (!$param->{type} || $param->{type} eq 'pool') {</div>
<div> <span class="" style="white-space:pre">  </span>    foreach my $pool (keys %{$usercfg->{pools}}) {</div><div> <span class="" style="white-space:pre">          </span>my $d = $usercfg->{pools}->{$pool};</div><div> </div>
<div>-<span class="" style="white-space:pre">           </span>next if !$rpcenv->check($authuser, "/pool/$pool", [ 'Pool.Allocate' ], 1);</div><div>+<span class="" style="white-space:pre">           </span>next if !$rpcenv->check_any($authuser, "/pool/$pool", [keys $PVE::AccessControl::valid_privs], 1);</div>
<div> </div><div> <span class="" style="white-space:pre">         </span>my $entry = {</div><div> <span class="" style="white-space:pre">            </span>    id => "/pool/$pool",</div><div>@@ -185,9 +195,9 @@ __PACKAGE__->register_method({</div>
<div> </div><div> <span class="" style="white-space:pre">         </span>my $data = $idlist->{$vmid};</div><div> <span class="" style="white-space:pre">          </span>my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd);</div>
<div>-<span class="" style="white-space:pre">           </span>if ($entry->{uptime}) {</div><div>-<span class="" style="white-space:pre">                </span>    if (my $pool = $usercfg->{vms}->{$vmid}) {</div><div>-<span class="" style="white-space:pre">                    </span>if (my $pe = $pooldata->{$pool}) {</div>
<div>+<span class="" style="white-space:pre">           </span>if (my $pool = $usercfg->{vms}->{$vmid}) {</div><div>+<span class="" style="white-space:pre">          </span>    if (my $pe = $pooldata->{$pool}) {</div><div>+<span class="" style="white-space:pre">                       </span>if ($entry->{uptime}) {</div>
<div> <span class="" style="white-space:pre">                  </span>    $pe->{uptime} = $entry->{uptime} if !$pe->{uptime} || $entry->{uptime} > $pe->{uptime};</div><div> <span class="" style="white-space:pre">                  </span>    $pe->{mem} = 0 if !$pe->{mem};</div>
<div> <span class="" style="white-space:pre">                  </span>    $pe->{mem} += $entry->{mem};</div><div>@@ -198,6 +208,7 @@ __PACKAGE__->register_method({</div><div> <span class="" style="white-space:pre">                     </span>    $pe->{maxcpu} = 0 if !$pe->{maxcpu};</div>
<div> <span class="" style="white-space:pre">                  </span>    $pe->{maxcpu} += $entry->{maxcpu};</div><div> <span class="" style="white-space:pre">                   </span>}</div><div>+<span class="" style="white-space:pre">                 </span>$entry->{pool} = $pe->{pool};</div>
<div> <span class="" style="white-space:pre">          </span>    }</div><div> <span class="" style="white-space:pre">          </span>}</div><div> <span class="" style="white-space:pre">                </span></div><div>@@ -228,6 +239,9 @@ __PACKAGE__->register_method({</div>
<div> <span class="" style="white-space:pre">          </span>    next if !PVE::Storage::storage_check_enabled($cfg, $storeid, $node, 1);</div><div> </div><div> <span class="" style="white-space:pre">           </span>    my $entry = PVE::API2Tools::extract_storage_stats($storeid, $scfg, $node, $rrd);</div>
<div>+<span class="" style="white-space:pre">           </span>    if (exists $storage_pool->{$entry->{storage}}) {</div><div>+<span class="" style="white-space:pre">                      </span>$entry->{"pool"}=$storage_pool->{$entry->{storage}};</div>
<div>+<span class="" style="white-space:pre">           </span>    }</div><div> <span class="" style="white-space:pre">          </span>    push @$res, $entry;</div><div> <span class="" style="white-space:pre">                </span>}</div><div> <span class="" style="white-space:pre">        </span>    }</div>
<div>diff -Nuarp usr/share/pve-manager/css/ext-pve.css usr/share/pve-manager/css/ext-pve.css</div><div>--- usr/share/pve-manager/css/ext-pve.css<span class="" style="white-space:pre">     </span>2014-06-27 16:33:46.291799762 +1200</div>
<div>+++ usr/share/pve-manager/css/ext-pve.css<span class="" style="white-space:pre">   </span>2014-06-27 16:34:56.083492567 +1200</div><div>@@ -108,7 +108,7 @@</div><div> .x-tree-node-pool,</div><div> .x-grid-tree-pool-expanded .x-tree-node-pool</div>
<div> {</div><div>-    background-image:url(../images/connect_established.png);</div><div>+    background-image:url(../images/connect_established.png) !important;</div><div> }</div><div> </div><div> .pve-itype-icon-itype</div>
<div>diff -Nuarp usr/share/pve-manager/ext4/pvemanagerlib.js usr/share/pve-manager/ext4/pvemanagerlib.js</div><div>--- usr/share/pve-manager/ext4/pvemanagerlib.js<span class="" style="white-space:pre">   </span>2014-06-27 16:33:56.642902474 +1200</div>
<div>+++ usr/share/pve-manager/ext4/pvemanagerlib.js<span class="" style="white-space:pre">     </span>2014-07-03 12:39:08.325001416 +1200</div><div>@@ -4234,6 +4234,15 @@ Ext.define('PVE.form.ViewSelector', {</div><div>
 <span class="" style="white-space:pre">             </span>filterfn: function(node) {</div><div> <span class="" style="white-space:pre">               </span>    return node.data.type === 'storage';</div><div> <span class="" style="white-space:pre">               </span>}</div>
<div>+<span class="" style="white-space:pre">   </span>    }, </div><div>+<span class="" style="white-space:pre">        </span>    pool: { </div><div>+<span class="" style="white-space:pre">           </span>text: gettext('Pool View'), </div>
<div>+<span class="" style="white-space:pre">           </span>groups: ['pool'],</div><div>+                // Pool View is essentially an inverse of "Storage View",</div><div>+                // where storage items are excluded from the overview.</div>
<div>+                filterfn: function(node) {</div><div>+                    return node.data.type !== 'storage';</div><div>+                }</div><div> <span class="" style="white-space:pre">     </span>    }</div>
<div> <span class="" style="white-space:pre">  </span>};</div><div> </div><div>@@ -7220,6 +7229,11 @@ Ext.define('PVE.grid.PoolMembers', {</div><div> <span class="" style="white-space:pre">    </span>    if (!group) {</div>
<div> <span class="" style="white-space:pre">          </span>var groupinfo;</div><div> <span class="" style="white-space:pre">           </span>if (info.type === groupby) {</div><div>+<span class="" style="white-space:pre">              </span>    if (groupby=="pool") { </div>
<div>+<span class="" style="white-space:pre">                   </span>var rstore = new Ext.data.Store({ </div><div>+<span class="" style="white-space:pre">                       </span>    model: 'pve-pools' </div><div>+<span class="" style="white-space:pre">                        </span>}); </div>
<div>+<span class="" style="white-space:pre">           </span>    } </div><div> <span class="" style="white-space:pre">                </span>    groupinfo = info;</div><div> <span class="" style="white-space:pre">          </span>} else {</div><div> <span class="" style="white-space:pre">         </span>    groupinfo = {</div>
</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div></div>