cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bhais...@apache.org
Subject [cloudstack] branch master updated: CLOUDSTACK-9972: Enhance listVolume API to include physical size and … (#2158)
Date Sun, 05 Nov 2017 16:14:48 GMT
This is an automated email from the ASF dual-hosted git repository.

bhaisaab pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 4627fb2  CLOUDSTACK-9972: Enhance listVolume API to include physical size and … (#2158)
4627fb2 is described below

commit 4627fb2cd7556173bd7e58bf1bec22c93a78f31d
Author: Abhinandan Prateek <abhinandan.prateek@shapeblue.com>
AuthorDate: Sun Nov 5 21:44:43 2017 +0530

    CLOUDSTACK-9972: Enhance listVolume API to include physical size and … (#2158)
    
    * CLOUDSTACK-9972: Enhance listVolume API to include physical size and utilization.
    Also fixed pool, cluster and pod info
    
    * CLOUDSTACK-9972: Fix volume_view and duplicate API constant
    
    * CLOUDSTACK-9972: Backport Do not allow vms to be deployed on hosts that are in disabled pod
    
    * CLOUDSTACK-9972: Fix localization missing keys
    
    * CLOUDSTACK-9972: Fix sql path
---
 .../src/com/cloud/agent/api/BadCommand.java        |  26 +---
 api/src/com/cloud/storage/VolumeStats.java         |   7 +-
 .../org/apache/cloudstack/api/ApiConstants.java    |   2 +
 .../api/command/user/volume/ListVolumesCmd.java    |   8 ++
 .../cloudstack/api/response/VolumeResponse.java    |  88 ++++++++++++-
 .../com/cloud/agent/api/GetFileStatsAnswer.java    |  41 ------
 .../com/cloud/agent/api/GetVmDiskStatsCommand.java |   4 +
 .../com/cloud/agent/api/GetVolumeStatsAnswer.java  |  73 +++++++++++
 .../com/cloud/agent/api/GetVolumeStatsCommand.java |  75 +++++++++++
 core/src/com/cloud/agent/api/VolumeStatsEntry.java |  64 ++++++++++
 core/src/com/cloud/agent/transport/Request.java    |   3 +
 .../com/cloud/agent/transport/RequestTest.java     |  26 +++-
 .../LibvirtGetVolumeStatsCommandWrapper.java       |  66 ++++++++++
 .../hypervisor/kvm/storage/KVMPhysicalDisk.java    |   5 +
 .../hypervisor/kvm/storage/LibvirtStoragePool.java |   3 +-
 .../hypervisor/vmware/resource/VmwareResource.java |  43 +++++++
 .../CitrixGetVolumeStatsCommandWrapper.java        |  62 +++++++++
 server/src/com/cloud/api/ApiDBUtils.java           |   5 +
 .../src/com/cloud/api/query/QueryManagerImpl.java  |   4 +
 .../com/cloud/api/query/ViewResponseHelper.java    |  26 ++++
 .../com/cloud/api/query/dao/VolumeJoinDaoImpl.java |   6 +
 .../src/com/cloud/api/query/vo/VolumeJoinVO.java   |  47 +++++++
 server/src/com/cloud/configuration/Config.java     |   2 +
 .../deploy/DeploymentPlanningManagerImpl.java      |  88 +++++++------
 server/src/com/cloud/server/StatsCollector.java    |  68 ++++++++--
 server/src/com/cloud/test/DatabaseConfig.java      |   2 +-
 server/src/com/cloud/vm/UserVmManager.java         |   4 +
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  22 ++++
 setup/db/db/schema-41000to41100.sql                | 139 ++++++++++++++++++++-
 test/integration/smoke/test_volumes.py             |  74 ++++++++++-
 ui/l10n/ar.js                                      |   3 +
 ui/l10n/ca.js                                      |   3 +
 ui/l10n/de_DE.js                                   |   3 +
 ui/l10n/en.js                                      |   3 +
 ui/l10n/es.js                                      |   3 +
 ui/l10n/fr_FR.js                                   |   3 +
 ui/l10n/hu.js                                      |   3 +
 ui/l10n/it_IT.js                                   |   3 +
 ui/l10n/ja_JP.js                                   |   3 +
 ui/l10n/ko_KR.js                                   |   3 +
 ui/l10n/nb_NO.js                                   |   3 +
 ui/l10n/nl_NL.js                                   |   3 +
 ui/l10n/pl.js                                      |   3 +
 ui/l10n/pt_BR.js                                   |   3 +
 ui/l10n/ru_RU.js                                   |   3 +
 ui/l10n/zh_CN.js                                   |   3 +
 ui/scripts/metrics.js                              |  12 ++
 ui/scripts/storage.js                              |  29 ++++-
 .../cloud/hypervisor/vmware/mo/DatastoreMO.java    |  32 +++++
 .../hypervisor/vmware/mo/VirtualMachineMO.java     |  53 ++++++++
 50 files changed, 1139 insertions(+), 118 deletions(-)

diff --git a/core/src/com/cloud/agent/api/GetFileStatsCommand.java b/api/src/com/cloud/agent/api/BadCommand.java
similarity index 71%
rename from core/src/com/cloud/agent/api/GetFileStatsCommand.java
rename to api/src/com/cloud/agent/api/BadCommand.java
index b2da1c3..55976f6 100644
--- a/core/src/com/cloud/agent/api/GetFileStatsCommand.java
+++ b/api/src/com/cloud/agent/api/BadCommand.java
@@ -1,4 +1,3 @@
-//
 // Licensed to the Apache Software Foundation (ASF) under one
 // or more contributor license agreements.  See the NOTICE file
 // distributed with this work for additional information
@@ -15,30 +14,17 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-
 package com.cloud.agent.api;
 
-import com.cloud.agent.api.LogLevel.Log4jLevel;
-import com.cloud.storage.Volume;
-
-@LogLevel(Log4jLevel.Trace)
-public class GetFileStatsCommand extends Command {
-    protected GetFileStatsCommand() {
-    }
-
-    String paths;
-
-    public GetFileStatsCommand(Volume volume) {
-        paths = volume.getPath();
-    }
-
-    public String getPaths() {
-        return paths;
-    }
+public class BadCommand extends Command {
 
     @Override
     public boolean executeInSequence() {
+        // TODO Auto-generated method stub
         return false;
     }
+
+    public BadCommand(){
+        super();
+    }
 }
diff --git a/api/src/com/cloud/storage/VolumeStats.java b/api/src/com/cloud/storage/VolumeStats.java
index 70c0b17..81fa7ea 100644
--- a/api/src/com/cloud/storage/VolumeStats.java
+++ b/api/src/com/cloud/storage/VolumeStats.java
@@ -20,5 +20,10 @@ public interface VolumeStats {
     /**
      * @return bytes used by the volume
      */
-    public long getBytesUsed();
+    long getVirtualSize();
+
+    /**
+     * @return bytes allocated
+     */
+    long getPhysicalSize();
 }
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 1ec340d..2a2d686 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -85,6 +85,7 @@ public class ApiConstants {
     public static final String DEVICE_ID = "deviceid";
     public static final String DISK_OFFERING_ID = "diskofferingid";
     public static final String DISK_SIZE = "disksize";
+    public static final String UTILIZATION = "utilization";
     public static final String DRIVER = "driver";
     public static final String ROOT_DISK_SIZE = "rootdisksize";
     public static final String DISPLAY_NAME = "displayname";
@@ -205,6 +206,7 @@ public class ApiConstants {
     public static final String SSHKEY_ENABLED = "sshkeyenabled";
     public static final String PATH = "path";
     public static final String POD_ID = "podid";
+    public static final String POD_NAME = "podname";
     public static final String POD_IDS = "podids";
     public static final String POLICY_ID = "policyid";
     public static final String PORT = "port";
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
index 059def7..554e029 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
@@ -26,6 +26,7 @@ import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.response.ClusterResponse;
 import org.apache.cloudstack.api.response.DiskOfferingResponse;
 import org.apache.cloudstack.api.response.HostResponse;
 import org.apache.cloudstack.api.response.ListResponse;
@@ -63,6 +64,9 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd {
     @Parameter(name = ApiConstants.POD_ID, type = CommandType.UUID, entityType = PodResponse.class, description = "the pod id the disk volume belongs to")
     private Long podId;
 
+    @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.UUID, entityType = ClusterResponse.class, description = "the cluster id the disk volume belongs to", authorized = {RoleType.Admin})
+    private Long clusterId;
+
     @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "the type of disk volume")
     private String type;
 
@@ -98,6 +102,10 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd {
         return hostId;
     }
 
+    public Long getClusterId() {
+        return clusterId;
+    }
+
     public Long getId() {
         return id;
     }
diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
index e25adf6..895e13c 100644
--- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
@@ -228,9 +228,36 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
     String chainInfo;
 
     @SerializedName(ApiConstants.SNAPSHOT_QUIESCEVM)
-    @Param(description = "need quiesce vm or not when taking snapshot", since="4.3")
+    @Param(description = "need quiesce vm or not when taking snapshot", since = "4.3")
     private boolean needQuiescevm;
 
+    @SerializedName(ApiConstants.PHYSICAL_SIZE)
+    @Param(description = "the bytes alloaated")
+    private Long physicalsize;
+
+    @SerializedName(ApiConstants.VIRTUAL_SIZE)
+    @Param(description = "the bytes actually consumed on disk")
+    private Long virtualsize;
+
+    @SerializedName(ApiConstants.UTILIZATION)
+    @Param(description = "the disk utilization")
+    private String utilization;
+
+    @SerializedName(ApiConstants.CLUSTER_ID)
+    @Param(description = "cluster id of the volume")
+    private String clusterid;
+
+    @SerializedName(ApiConstants.CLUSTER_NAME)
+    @Param(description = "cluster name where the volume is allocated")
+    private String clustername;
+
+    @SerializedName(ApiConstants.POD_ID)
+    @Param(description = "pod id of the volume")
+    private String podid;
+
+    @SerializedName(ApiConstants.POD_NAME)
+    @Param(description = "pod name of the volume")
+    private String podname;
 
     public String getPath() {
         return path;
@@ -301,7 +328,7 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
         this.virtualMachineState = virtualMachineState;
     }
 
-    public void setProvisioningType(String provisioningType){
+    public void setProvisioningType(String provisioningType) {
         this.provisioningType = provisioningType;
     }
 
@@ -649,4 +676,61 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
     public Boolean getDisplayVolume() {
         return displayVolume;
     }
+
+    public Long getPhysicalsize() {
+        return physicalsize;
+    }
+
+    public void setPhysicalsize(Long physicalsize) {
+        this.physicalsize = physicalsize;
+    }
+
+    public Long getVirtualsize() {
+        return virtualsize;
+    }
+
+    public void setVirtualsize(Long virtualsize) {
+        this.virtualsize = virtualsize;
+    }
+
+    public String getUtilization() {
+        return utilization;
+    }
+
+    public void setUtilization(String utilization) {
+        this.utilization = utilization;
+    }
+
+    public String getClusterId() {
+        return clusterid;
+    }
+
+    public void setClusterId(String clusterid) {
+        this.clusterid = clusterid;
+    }
+
+    public String getClusterName() {
+        return clustername;
+    }
+
+    public void setClusterName(String clustername) {
+        this.clustername = clustername;
+    }
+
+    public String getPodId() {
+        return podid;
+    }
+
+    public void setPodId(String podid) {
+        this.podid = podid;
+    }
+
+    public String getPodName() {
+        return podname;
+    }
+
+    public void setPodName(String podname) {
+        this.podname = podname;
+    }
+
 }
diff --git a/core/src/com/cloud/agent/api/GetFileStatsAnswer.java b/core/src/com/cloud/agent/api/GetFileStatsAnswer.java
deleted file mode 100644
index 5c3f006..0000000
--- a/core/src/com/cloud/agent/api/GetFileStatsAnswer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-package com.cloud.agent.api;
-
-import com.cloud.agent.api.LogLevel.Log4jLevel;
-import com.cloud.storage.VolumeStats;
-
-@LogLevel(Log4jLevel.Trace)
-public class GetFileStatsAnswer extends Answer implements VolumeStats {
-    long size;
-
-    protected GetFileStatsAnswer() {
-    }
-
-    public GetFileStatsAnswer(GetFileStatsCommand cmd, long value) {
-        super(cmd);
-        size = value;
-    }
-
-    @Override
-    public long getBytesUsed() {
-        return size;
-    }
-}
diff --git a/core/src/com/cloud/agent/api/GetVmDiskStatsCommand.java b/core/src/com/cloud/agent/api/GetVmDiskStatsCommand.java
index 4b2b2e8..8c18e0e 100644
--- a/core/src/com/cloud/agent/api/GetVmDiskStatsCommand.java
+++ b/core/src/com/cloud/agent/api/GetVmDiskStatsCommand.java
@@ -25,6 +25,10 @@ import com.cloud.agent.api.LogLevel.Log4jLevel;
 
 @LogLevel(Log4jLevel.Trace)
 public class GetVmDiskStatsCommand extends Command {
+    public String getString() {
+        return "GetVmDiskStatsCommand [vmNames=" + vmNames + ", hostGuid=" + hostGuid + ", hostName=" + hostName + "]";
+    }
+
     List<String> vmNames;
     String hostGuid;
     String hostName;
diff --git a/core/src/com/cloud/agent/api/GetVolumeStatsAnswer.java b/core/src/com/cloud/agent/api/GetVolumeStatsAnswer.java
new file mode 100644
index 0000000..8f00a4c
--- /dev/null
+++ b/core/src/com/cloud/agent/api/GetVolumeStatsAnswer.java
@@ -0,0 +1,73 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.api;
+
+import java.util.HashMap;
+
+import com.cloud.agent.api.LogLevel.Log4jLevel;
+import com.cloud.storage.Storage.StoragePoolType;
+
+@LogLevel(Log4jLevel.Trace)
+public class GetVolumeStatsAnswer extends Answer {
+
+    String poolUuid;
+    StoragePoolType poolType;
+    HashMap<String, VolumeStatsEntry> volumeStats;
+
+    public GetVolumeStatsAnswer(GetVolumeStatsCommand cmd, String details, HashMap<String, VolumeStatsEntry> volumeStats) {
+        super(cmd, true, details);
+        this.poolUuid = cmd.getPoolUuid();
+        this.poolType = cmd.getPoolType();
+        this.volumeStats = volumeStats;
+    }
+
+    protected GetVolumeStatsAnswer() {
+        //no-args constructor for json serialization-deserialization
+    }
+
+    public String getPoolUuid() {
+        return poolUuid;
+    }
+
+    public void setPoolUuid(String poolUuid) {
+        this.poolUuid = poolUuid;
+    }
+
+    public StoragePoolType getPoolType() {
+        return poolType;
+    }
+
+    public void setPoolType(StoragePoolType poolType) {
+        this.poolType = poolType;
+    }
+
+    public HashMap<String, VolumeStatsEntry> getVolumeStats() {
+        return volumeStats;
+    }
+
+    public void setVolumeStats(HashMap<String, VolumeStatsEntry> volumeStats) {
+        this.volumeStats = volumeStats;
+    }
+
+    public String getString() {
+        return "GetVolumeStatsAnswer [poolUuid=" + poolUuid + ", poolType=" + poolType + ", volumeStats=" + volumeStats + "]";
+    }
+
+}
diff --git a/core/src/com/cloud/agent/api/GetVolumeStatsCommand.java b/core/src/com/cloud/agent/api/GetVolumeStatsCommand.java
new file mode 100644
index 0000000..a08f0db
--- /dev/null
+++ b/core/src/com/cloud/agent/api/GetVolumeStatsCommand.java
@@ -0,0 +1,75 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.api;
+
+import java.util.List;
+
+import com.cloud.agent.api.LogLevel.Log4jLevel;
+import com.cloud.storage.Storage.StoragePoolType;
+
+@LogLevel(Log4jLevel.Trace)
+public class GetVolumeStatsCommand extends Command {
+
+    List<String> volumeUuids;
+    StoragePoolType poolType;
+    String poolUuid;
+
+    protected GetVolumeStatsCommand() {
+    }
+
+    public GetVolumeStatsCommand(StoragePoolType poolType, String storeUuid, List<String> volumeUuids) {
+        this.volumeUuids = volumeUuids;
+        this.poolType = poolType;
+        this.poolUuid = storeUuid;
+    }
+
+    public List<String> getVolumeUuids() {
+        return volumeUuids;
+    }
+
+    public void setVolumeUuids(List<String> volumeUuids) {
+        this.volumeUuids = volumeUuids;
+    }
+
+    public StoragePoolType getPoolType() {
+        return poolType;
+    }
+
+    public void setPoolType(StoragePoolType poolType) {
+        this.poolType = poolType;
+    }
+
+    public String getPoolUuid() {
+        return poolUuid;
+    }
+
+    public void setPoolUuid(String storeUuid) {
+        this.poolUuid = storeUuid;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+
+    public String getString() {
+        return "GetVolumeStatsCommand [volumeUuids=" + volumeUuids + ", poolType=" + poolType + ", poolUuid=" + poolUuid + "]";
+    }
+}
\ No newline at end of file
diff --git a/core/src/com/cloud/agent/api/VolumeStatsEntry.java b/core/src/com/cloud/agent/api/VolumeStatsEntry.java
new file mode 100644
index 0000000..fb4ecc7
--- /dev/null
+++ b/core/src/com/cloud/agent/api/VolumeStatsEntry.java
@@ -0,0 +1,64 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.api;
+
+import com.cloud.storage.VolumeStats;
+
+public class VolumeStatsEntry implements VolumeStats {
+    String volumeUuid;
+    long physicalsize = 0;
+    long virtualSize = 0;
+
+    public VolumeStatsEntry(String volumeUuid, long physicalsize, long virtualSize) {
+        this.volumeUuid = volumeUuid;
+        this.physicalsize = physicalsize;
+        this.virtualSize = virtualSize;
+    }
+
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    public void setVolumeUuid(String volumeUuid) {
+        this.volumeUuid = volumeUuid;
+    }
+
+    public long getPhysicalSize() {
+        return physicalsize;
+    }
+
+    public void setPhysicalSize(long size) {
+        this.physicalsize = size;
+    }
+
+    public long getVirtualSize() {
+        return virtualSize;
+    }
+
+    public void setVirtualSize(long virtualSize) {
+        this.virtualSize = virtualSize;
+    }
+
+    @Override
+    public String toString() {
+        return "VolumeStatsEntry [volumeUuid=" + volumeUuid + ", size=" + physicalsize + ", virtualSize=" + virtualSize + "]";
+    }
+
+}
diff --git a/core/src/com/cloud/agent/transport/Request.java b/core/src/com/cloud/agent/transport/Request.java
index f78a96c..09f6bd4 100644
--- a/core/src/com/cloud/agent/transport/Request.java
+++ b/core/src/com/cloud/agent/transport/Request.java
@@ -47,6 +47,7 @@ import com.google.gson.JsonSerializer;
 import com.google.gson.stream.JsonReader;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BadCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig;
 import com.cloud.exception.UnsupportedVersionException;
@@ -249,6 +250,8 @@ public class Request {
                 JsonReader jsonReader = new JsonReader(reader);
                 jsonReader.setLenient(true);
                 _cmds = s_gson.fromJson(jsonReader, (Type)Command[].class);
+            } catch (JsonParseException e) {
+                _cmds = new Command[] { new BadCommand() };
             } catch (RuntimeException e) {
                 s_logger.error("Caught problem with " + _content, e);
                 throw e;
diff --git a/core/test/com/cloud/agent/transport/RequestTest.java b/core/test/com/cloud/agent/transport/RequestTest.java
index ee3b082..21766ba 100644
--- a/core/test/com/cloud/agent/transport/RequestTest.java
+++ b/core/test/com/cloud/agent/transport/RequestTest.java
@@ -20,7 +20,6 @@
 package com.cloud.agent.transport;
 
 import java.nio.ByteBuffer;
-
 import junit.framework.TestCase;
 
 import org.apache.log4j.Level;
@@ -32,13 +31,16 @@ import org.apache.cloudstack.storage.command.DownloadCommand;
 import org.apache.cloudstack.storage.to.TemplateObjectTO;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BadCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.GetHostStatsCommand;
+import com.cloud.agent.api.GetVolumeStatsCommand;
 import com.cloud.agent.api.SecStorageFirewallCfgCommand;
 import com.cloud.agent.api.UpdateHostPasswordCommand;
 import com.cloud.agent.api.storage.DownloadAnswer;
 import com.cloud.agent.api.storage.ListTemplateCommand;
 import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.transport.Request.Version;
 import com.cloud.exception.UnsupportedVersionException;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.serializer.GsonHelper;
@@ -250,4 +252,26 @@ public class RequestTest extends TestCase {
         }
     }
 
+    public void testGoodCommand() {
+        s_logger.info("Testing good Command");
+        String content = "[{\"com.cloud.agent.api.GetVolumeStatsCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"],"
+                + "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
+        Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content);
+        sreq.setSequence(1);
+        Command cmds[] = sreq.getCommands();
+        s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName());
+        assert cmds[0].getClass().equals(GetVolumeStatsCommand.class);
+    }
+
+    public void testBadCommand() {
+        s_logger.info("Testing Bad Command");
+        String content = "[{\"com.cloud.agent.api.SomeJunkCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"],"
+                + "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
+        Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content);
+        sreq.setSequence(1);
+        Command cmds[] = sreq.getCommands();
+        s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName());
+        assert cmds[0].getClass().equals(BadCommand.class);
+    }
+
 }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatsCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatsCommandWrapper.java
new file mode 100644
index 0000000..6d945b1
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatsCommandWrapper.java
@@ -0,0 +1,66 @@
+//
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//with the License.  You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing,
+//software distributed under the License is distributed on an
+//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//KIND, either express or implied.  See the License for the
+//specific language governing permissions and limitations
+//under the License.
+//
+
+package com.cloud.hypervisor.kvm.resource.wrapper;
+
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.LibvirtException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
+import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
+import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.agent.api.GetVolumeStatsAnswer;
+import com.cloud.agent.api.GetVolumeStatsCommand;
+import com.cloud.agent.api.VolumeStatsEntry;
+
+@ResourceWrapper(handles = GetVolumeStatsCommand.class)
+public final class LibvirtGetVolumeStatsCommandWrapper extends CommandWrapper<GetVolumeStatsCommand, Answer, LibvirtComputingResource> {
+    private static final Logger s_logger = Logger.getLogger(LibvirtGetVmDiskStatsCommandWrapper.class);
+
+    @Override
+    public Answer execute(final GetVolumeStatsCommand cmd, final LibvirtComputingResource libvirtComputingResource) {
+        try {
+            Connect conn = LibvirtConnection.getConnection();
+            String storeUuid = cmd.getPoolUuid();
+            StoragePoolType poolType = cmd.getPoolType();
+            HashMap<String, VolumeStatsEntry> statEntry = new HashMap<String, VolumeStatsEntry>();
+            for (String volumeUuid : cmd.getVolumeUuids()) {
+                statEntry.put(volumeUuid, getVolumeStat(libvirtComputingResource, conn, volumeUuid, storeUuid, poolType));
+            }
+            return new GetVolumeStatsAnswer(cmd, "", statEntry);
+        } catch (LibvirtException e) {
+            return new GetVolumeStatsAnswer(cmd, "Can't get vm disk stats: " + e.getMessage(), null);
+        }
+    }
+
+
+    private VolumeStatsEntry getVolumeStat(final LibvirtComputingResource libvirtComputingResource, final Connect conn, final String volumeUuid, final String storeUuid, final StoragePoolType poolType) throws LibvirtException {
+        KVMStoragePool sourceKVMPool = libvirtComputingResource.getStoragePoolMgr().getStoragePool(poolType, storeUuid);
+        KVMPhysicalDisk sourceKVMVolume = sourceKVMPool.getPhysicalDisk(volumeUuid);
+        return new VolumeStatsEntry(volumeUuid, sourceKVMVolume.getSize(), sourceKVMVolume.getVirtualSize());
+    }
+}
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java
index c344e8c..eaa143a 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java
@@ -56,6 +56,11 @@ public class KVMPhysicalDisk {
         this.pool = pool;
     }
 
+    @Override
+    public String toString() {
+        return "KVMPhysicalDisk [path=" + path + ", name=" + name + ", pool=" + pool + ", format=" + format + ", size=" + size + ", virtualSize=" + virtualSize + "]";
+    }
+
     public void setFormat(PhysicalDiskFormat format) {
         this.format = format;
     }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
index 66018dd..1b554f7 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
@@ -140,7 +140,7 @@ public class LibvirtStoragePool implements KVMStoragePool {
         if (disk != null) {
             return disk;
         }
-        s_logger.debug("find volume bypass libvirt");
+        s_logger.debug("find volume bypass libvirt volumeUid " + volumeUid);
         //For network file system or file system, try to use java file to find the volume, instead of through libvirt. BUG:CLOUDSTACK-4459
         String localPoolPath = this.getLocalPath();
         File f = new File(localPoolPath + File.separator + volumeUuid);
@@ -152,6 +152,7 @@ public class LibvirtStoragePool implements KVMStoragePool {
         disk.setFormat(PhysicalDiskFormat.QCOW2);
         disk.setSize(f.length());
         disk.setVirtualSize(f.length());
+        s_logger.debug("find volume bypass libvirt disk " + disk.toString());
         return disk;
     }
 
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 9d32f34..40ffdf4 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -146,6 +146,8 @@ import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
+import com.cloud.agent.api.GetVolumeStatsAnswer;
+import com.cloud.agent.api.GetVolumeStatsCommand;
 import com.cloud.agent.api.HostStatsEntry;
 import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
@@ -199,6 +201,7 @@ import com.cloud.agent.api.UpgradeSnapshotCommand;
 import com.cloud.agent.api.ValidateSnapshotAnswer;
 import com.cloud.agent.api.ValidateSnapshotCommand;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.VolumeStatsEntry;
 import com.cloud.agent.api.check.CheckSshAnswer;
 import com.cloud.agent.api.check.CheckSshCommand;
 import com.cloud.agent.api.routing.IpAssocCommand;
@@ -414,6 +417,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 answer = execute((GetVmNetworkStatsCommand) cmd);
             } else if (clz == GetVmDiskStatsCommand.class) {
                 answer = execute((GetVmDiskStatsCommand)cmd);
+            } else if (cmd instanceof GetVolumeStatsCommand) {
+                return execute((GetVolumeStatsCommand)cmd);
             } else if (clz == CheckHealthCommand.class) {
                 answer = execute((CheckHealthCommand)cmd);
             } else if (clz == StopCommand.class) {
@@ -3275,6 +3280,44 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return new GetVmNetworkStatsAnswer(cmd, null, null, null);
     }
 
+    protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) {
+        try {
+            VmwareHypervisorHost srcHyperHost = getHyperHost(getServiceContext());
+            ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(srcHyperHost, cmd.getPoolUuid());
+            assert (morDs != null);
+            DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(getServiceContext(), morDs);
+            VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
+            ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter();
+            DatacenterMO dcMo = new DatacenterMO(getServiceContext(), dcMor);
+            HashMap<String, VolumeStatsEntry> statEntry = new HashMap<String, VolumeStatsEntry>();
+
+            for (String chainInfo : cmd.getVolumeUuids()){
+                if (chainInfo != null) {
+                    VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class);
+                    if (infoInChain != null) {
+                        String[] disks = infoInChain.getDiskChain();
+                        if (disks.length > 0) {
+                            for (String diskPath : disks) {
+                                DatastoreFile file = new DatastoreFile(diskPath);
+                                VirtualMachineMO vmMo = dcMo.findVm(file.getDir());
+                                Pair<VirtualDisk, String> vds = vmMo.getDiskDevice(file.getFileName(), true);
+                                long virtualsize = vds.first().getCapacityInKB() * 1024;
+                                long physicalsize = primaryStorageDatastoreMo.fileDiskSize(file.getPath());
+                                VolumeStatsEntry vse = new VolumeStatsEntry(chainInfo, physicalsize, virtualsize);
+                                statEntry.put(chainInfo, vse);
+                            }
+                        }
+                    }
+                }
+            }
+            return new GetVolumeStatsAnswer(cmd, "", statEntry);
+        } catch (Exception e) {
+            s_logger.info("VOLSTAT GetVolumeStatsCommand failed " + e.getMessage());
+        }
+
+        return new GetVolumeStatsAnswer(cmd, "", null);
+    }
+
     protected Answer execute(CheckHealthCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource CheckHealthCommand: " + _gson.toJson(cmd));
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVolumeStatsCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVolumeStatsCommandWrapper.java
new file mode 100644
index 0000000..f5d6604
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVolumeStatsCommandWrapper.java
@@ -0,0 +1,62 @@
+//
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements.  See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership.  The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//with the License.  You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing,
+//software distributed under the License is distributed on an
+//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//KIND, either express or implied.  See the License for the
+//specific language governing permissions and limitations
+//under the License.
+//
+
+package com.cloud.hypervisor.xenserver.resource.wrapper.xenbase;
+
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.GetVolumeStatsAnswer;
+import com.cloud.agent.api.GetVolumeStatsCommand;
+import com.cloud.agent.api.VolumeStatsEntry;
+import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.VDI;
+
+@ResourceWrapper(handles = GetVolumeStatsCommand.class)
+public final class CitrixGetVolumeStatsCommandWrapper extends CommandWrapper<GetVolumeStatsCommand, Answer, CitrixResourceBase> {
+    private static final Logger s_logger = Logger.getLogger(CitrixGetVolumeStatsCommandWrapper.class);
+
+    @Override
+    public Answer execute(final GetVolumeStatsCommand cmd, final CitrixResourceBase citrixResourceBase) {
+        Connection conn = citrixResourceBase.getConnection();
+        HashMap<String, VolumeStatsEntry> statEntry = new HashMap<String, VolumeStatsEntry>();
+        for (String volumeUuid : cmd.getVolumeUuids()) {
+            VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volumeUuid, false);
+            if (vdi != null) {
+                try {
+                    VolumeStatsEntry vse = new VolumeStatsEntry(volumeUuid, vdi.getPhysicalUtilisation(conn), vdi.getVirtualSize(conn));
+                    statEntry.put(volumeUuid, vse);
+                } catch (Exception e) {
+                    s_logger.warn("Unable to get volume stats", e);
+                    statEntry.put(volumeUuid, new VolumeStatsEntry(volumeUuid, -1, -1));
+                }
+            } else {
+                s_logger.warn("VDI not found for path " + volumeUuid);
+                statEntry.put(volumeUuid, new VolumeStatsEntry(volumeUuid, -1L, -1L));
+            }
+        }
+        return new GetVolumeStatsAnswer(cmd, "", statEntry);
+    }
+
+}
\ No newline at end of file
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index e88a102..9f67aa7 100644
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -260,6 +260,7 @@ import com.cloud.storage.UploadVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
+import com.cloud.storage.VolumeStats;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSCategoryDao;
@@ -923,6 +924,10 @@ public class ApiDBUtils {
         return s_statsCollector.getVmStats(hostId);
     }
 
+    public static VolumeStats getVolumeStatistics(String volumeUuid) {
+        return s_statsCollector.getVolumeStats(volumeUuid);
+    }
+
     public static StorageStats getSecondaryStorageStatistics(long id) {
         return s_statsCollector.getStorageStats(id);
     }
diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java
index 1c5c70c..42bef79 100644
--- a/server/src/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/com/cloud/api/query/QueryManagerImpl.java
@@ -1736,6 +1736,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
         String type = cmd.getType();
         Map<String, String> tags = cmd.getTags();
         Long storageId = cmd.getStorageId();
+        Long clusterId = cmd.getClusterId();
         Long diskOffId = cmd.getDiskOfferingId();
         Boolean display = cmd.getDisplay();
 
@@ -1845,6 +1846,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
             sc.setParameters("storageId", storageId);
         }
 
+        if (clusterId != null) {
+            sc.setParameters("clusterId", clusterId);
+        }
         // Don't return DomR and ConsoleProxy volumes
         sc.setParameters("type", VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.DomainRouter);
 
diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java
index dfed7ba..11af5a9 100644
--- a/server/src/com/cloud/api/query/ViewResponseHelper.java
+++ b/server/src/com/cloud/api/query/ViewResponseHelper.java
@@ -16,6 +16,7 @@
 // under the License.
 package com.cloud.api.query;
 
+import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.Hashtable;
@@ -79,6 +80,8 @@ import com.cloud.api.query.vo.UserAccountJoinVO;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.api.query.vo.VolumeJoinVO;
 import com.cloud.storage.StoragePoolTagVO;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.VolumeStats;
 import com.cloud.user.Account;
 
 /**
@@ -263,6 +266,7 @@ public class ViewResponseHelper {
 
     public static List<VolumeResponse> createVolumeResponse(ResponseView view, VolumeJoinVO... volumes) {
         Hashtable<Long, VolumeResponse> vrDataList = new Hashtable<Long, VolumeResponse>();
+        DecimalFormat df = new DecimalFormat("0.00");
         for (VolumeJoinVO vr : volumes) {
             VolumeResponse vrData = vrDataList.get(vr.getId());
             if (vrData == null) {
@@ -274,6 +278,28 @@ public class ViewResponseHelper {
                 vrData = ApiDBUtils.fillVolumeDetails(view, vrData, vr);
             }
             vrDataList.put(vr.getId(), vrData);
+
+            if (view == ResponseView.Full) {
+                VolumeStats vs = null;
+                if (vr.getFormat() == ImageFormat.QCOW2) {
+                    vs = ApiDBUtils.getVolumeStatistics(vrData.getId());
+                }
+                else if (vr.getFormat() == ImageFormat.VHD){
+                    vs = ApiDBUtils.getVolumeStatistics(vrData.getPath());
+                }
+                else if (vr.getFormat() == ImageFormat.OVA){
+                    vs = ApiDBUtils.getVolumeStatistics(vrData.getChainInfo());
+                }
+                if (vs != null){
+                    long vsz = vs.getVirtualSize();
+                    long psz = vs.getPhysicalSize() ;
+                    double util = (double)psz/vsz;
+                    vrData.setVirtualsize(vsz);
+                    vrData.setPhysicalsize(psz);
+                    vrData.setUtilization(df.format(util));
+                }
+            }
+
         }
         return new ArrayList<VolumeResponse>(vrDataList.values());
     }
diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
index 73e0c6d..6ed9be9 100644
--- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
@@ -78,6 +78,12 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
 
         volResponse.setZoneId(volume.getDataCenterUuid());
         volResponse.setZoneName(volume.getDataCenterName());
+        if (view == ResponseView.Full) {
+            volResponse.setClusterId(volume.getClusterUuid());
+            volResponse.setClusterName(volume.getClusterName());
+            volResponse.setPodId(volume.getPodUuid());
+            volResponse.setPodName(volume.getPodName());
+        }
 
         if (volume.getVolumeType() != null) {
             volResponse.setVolumeType(volume.getVolumeType().toString());
diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
index 77785b1..cf361df 100644
--- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
@@ -113,6 +113,21 @@ public class VolumeJoinVO extends BaseViewWithTagInformationVO implements Contro
     @Column(name = "pod_id")
     private long podId;
 
+    @Column(name = "pod_name")
+    private String podName;
+
+    @Column(name = "pod_uuid")
+    private String podUuid;
+
+    @Column(name = "cluster_id")
+    private long clusterId;
+
+    @Column(name = "cluster_name")
+    private String clusterName;
+
+    @Column(name = "cluster_uuid")
+    private String clusterUuid;
+
     @Column(name = "data_center_id")
     private long dataCenterId;
 
@@ -469,6 +484,38 @@ public class VolumeJoinVO extends BaseViewWithTagInformationVO implements Contro
         return poolName;
     }
 
+    public String getPodName() {
+        return podName;
+    }
+
+    public void setPodName(String podName) {
+        this.podName = podName;
+    }
+
+    public String getPodUuid() {
+        return podUuid;
+    }
+
+    public void setPodUuid(String podUuid) {
+        this.podUuid = podUuid;
+    }
+
+    public void setPodId(long podId) {
+        this.podId = podId;
+    }
+
+    public long getClusterId() {
+        return clusterId;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public String getClusterUuid() {
+        return clusterUuid;
+    }
+
     public long getTemplateId() {
         return templateId;
     }
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 6f48eab..bc8272a 100644
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -853,6 +853,8 @@ public enum Config {
             "60000",
             "The interval (in milliseconds) when vm stats are retrieved from agents.",
             null),
+    VmDiskStatsInterval("Advanced", ManagementServer.class, Integer.class, "vm.disk.stats.interval", "0", "Interval (in seconds) to report vm disk statistics.", null),
+    VolumeStatsInterval("Advanced", ManagementServer.class, Integer.class, "volume.stats.interval", "60000", "Interval (in seconds) to report volume statistics.", null),
     VmTransitionWaitInterval(
             "Advanced",
             ManagementServer.class,
diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index 3363b0e..6cb5381 100644
--- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -282,12 +282,22 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
                 s_logger.debug("The specified host is in avoid set");
             } else {
                 if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Looking for suitable pools for this host under zone: " + host.getDataCenterId() + ", pod: " + host.getPodId() + ", cluster: " +
-                            host.getClusterId());
+                    s_logger.debug(
+                            "Looking for suitable pools for this host under zone: " + host.getDataCenterId() + ", pod: " + host.getPodId() + ", cluster: " + host.getClusterId());
                 }
 
                 Pod pod = _podDao.findById(host.getPodId());
+                // check if the cluster or the pod is disabled
+                if (pod.getAllocationState() != Grouping.AllocationState.Enabled) {
+                    s_logger.warn("The Pod containing this host is in disabled state, PodId= " + pod.getId());
+                    return null;
+                }
+
                 Cluster cluster = _clusterDao.findById(host.getClusterId());
+                if (cluster.getAllocationState() != Grouping.AllocationState.Enabled) {
+                    s_logger.warn("The Cluster containing this host is in disabled state, PodId= " + cluster.getId());
+                    return null;
+                }
 
                 if (vm.getHypervisorType() == HypervisorType.BareMetal) {
                     DeployDestination dest = new DeployDestination(dc, pod, cluster, host, new HashMap<Volume, StoragePool>());
@@ -1041,47 +1051,49 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
             DataCenterDeployment potentialPlan =
                     new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, plan.getPoolId(), null, plan.getReservationContext());
 
-            // find suitable hosts under this cluster, need as many hosts as we
-            // get.
-            List<Host> suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL);
-            // if found suitable hosts in this cluster, find suitable storage
-            // pools for each volume of the VM
-            if (suitableHosts != null && !suitableHosts.isEmpty()) {
-                if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) {
-                    Pod pod = _podDao.findById(clusterVO.getPodId());
-                    DeployDestination dest = new DeployDestination(dc, pod, clusterVO, suitableHosts.get(0));
-                    return dest;
-                }
-
-                Pair<Map<Volume, List<StoragePool>>, List<Volume>> result =
-                        findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL);
-                Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
-                List<Volume> readyAndReusedVolumes = result.second();
-
-                // choose the potential host and pool for the VM
-                if (!suitableVolumeStoragePools.isEmpty()) {
-                    Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(
-                            suitableHosts, suitableVolumeStoragePools, avoid, resourceUsageRequired,
-                            readyAndReusedVolumes);
+            Pod pod = _podDao.findById(clusterVO.getPodId());
+            if (pod.getAllocationState() == Grouping.AllocationState.Enabled ) {
+                // find suitable hosts under this cluster, need as many hosts as we
+                // get.
+                List<Host> suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL);
+                // if found suitable hosts in this cluster, find suitable storage
+                // pools for each volume of the VM
+                if (suitableHosts != null && !suitableHosts.isEmpty()) {
+                    if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) {
+                        DeployDestination dest = new DeployDestination(dc, pod, clusterVO, suitableHosts.get(0));
+                        return dest;
+                    }
 
-                    if (potentialResources != null) {
-                        Pod pod = _podDao.findById(clusterVO.getPodId());
-                        Host host = _hostDao.findById(potentialResources.first().getId());
-                        Map<Volume, StoragePool> storageVolMap = potentialResources.second();
-                        // remove the reused vol<->pool from destination, since
-                        // we don't have to prepare this volume.
-                        for (Volume vol : readyAndReusedVolumes) {
-                            storageVolMap.remove(vol);
+                    Pair<Map<Volume, List<StoragePool>>, List<Volume>> result = findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL);
+                    Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
+                    List<Volume> readyAndReusedVolumes = result.second();
+
+                    // choose the potential host and pool for the VM
+                    if (!suitableVolumeStoragePools.isEmpty()) {
+                        Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools, avoid,
+                                resourceUsageRequired, readyAndReusedVolumes);
+
+                        if (potentialResources != null) {
+                            Host host = _hostDao.findById(potentialResources.first().getId());
+                            Map<Volume, StoragePool> storageVolMap = potentialResources.second();
+                            // remove the reused vol<->pool from destination, since
+                            // we don't have to prepare this volume.
+                            for (Volume vol : readyAndReusedVolumes) {
+                                storageVolMap.remove(vol);
+                            }
+                            DeployDestination dest = new DeployDestination(dc, pod, clusterVO, host, storageVolMap);
+                            s_logger.debug("Returning Deployment Destination: " + dest);
+                            return dest;
                         }
-                        DeployDestination dest = new DeployDestination(dc, pod, clusterVO, host, storageVolMap);
-                        s_logger.debug("Returning Deployment Destination: " + dest);
-                        return dest;
+                    } else {
+                        s_logger.debug("No suitable storagePools found under this Cluster: " + clusterId);
                     }
                 } else {
-                    s_logger.debug("No suitable storagePools found under this Cluster: " + clusterId);
+                    s_logger.debug("No suitable hosts found under this Cluster: " + clusterId);
                 }
-            } else {
-                s_logger.debug("No suitable hosts found under this Cluster: " + clusterId);
+            }
+            else {
+                s_logger.debug("The cluster is in a disabled pod : " + pod.getId());
             }
 
             if (canAvoidCluster(clusterVO, avoid, plannerAvoidOutput, vmProfile)) {
diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java
index 048b3b1..305711e 100644
--- a/server/src/com/cloud/server/StatsCollector.java
+++ b/server/src/com/cloud/server/StatsCollector.java
@@ -41,7 +41,6 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.utils.graphite.GraphiteClient;
@@ -60,6 +59,7 @@ import com.cloud.agent.api.VgpuTypesInfo;
 import com.cloud.agent.api.VmDiskStatsEntry;
 import com.cloud.agent.api.VmNetworkStatsEntry;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.VolumeStatsEntry;
 import com.cloud.cluster.ManagementServerHostVO;
 import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.dc.Vlan.VlanType;
@@ -101,9 +101,9 @@ import com.cloud.storage.StorageManager;
 import com.cloud.storage.StorageStats;
 import com.cloud.storage.VolumeStats;
 import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.user.UserStatisticsVO;
+import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.user.VmDiskStatisticsVO;
 import com.cloud.user.dao.UserStatisticsDao;
 import com.cloud.user.dao.VmDiskStatisticsDao;
@@ -160,6 +160,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
             "Interval (in seconds) to report vm network statistics (for Shared networks). Vm network statistics will be disabled if this is set to 0 or less than 0.", false);
     static final ConfigKey<Integer> vmNetworkStatsIntervalMin = new ConfigKey<Integer>("Advanced", Integer.class, "vm.network.stats.interval.min", "300",
             "Minimal Interval (in seconds) to report vm network statistics (for Shared networks). If vm.network.stats.interval is smaller than this, use this to report vm network statistics.", false);
+    static final ConfigKey<Integer> StatsTimeout = new ConfigKey<Integer>("Advanced", Integer.class, "stats.timeout", "60000",
+            "The timeout for stats call in milli seconds.", true, ConfigKey.Scope.Cluster);
 
     private static StatsCollector s_instance = null;
 
@@ -177,12 +179,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
     @Inject
     private PrimaryDataStoreDao _storagePoolDao;
     @Inject
-    private ImageStoreDao _imageStoreDao;
-    @Inject
     private StorageManager _storageManager;
     @Inject
-    private StoragePoolHostDao _storagePoolHostDao;
-    @Inject
     private DataStoreManager _dataStoreMgr;
     @Inject
     private ResourceManager _resourceMgr;
@@ -229,7 +227,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
 
     private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>();
     private final ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>();
-    private final ConcurrentHashMap<Long, VolumeStats> _volumeStats = new ConcurrentHashMap<Long, VolumeStats>();
+    private final Map<String, VolumeStats> _volumeStats = new ConcurrentHashMap<String, VolumeStats>();
     private ConcurrentHashMap<Long, StorageStats> _storageStats = new ConcurrentHashMap<Long, StorageStats>();
     private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<Long, StorageStats>();
 
@@ -282,7 +280,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         hostStatsInterval = NumbersUtil.parseLong(configs.get("host.stats.interval"), 60000L);
         hostAndVmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), 60000L);
         storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), 60000L);
-        volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), -1L);
+        volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), 600000L);
         autoScaleStatsInterval = NumbersUtil.parseLong(configs.get("autoscale.stats.interval"), 60000L);
 
         /* URI to send statistics to. Currently only Graphite is supported */
@@ -359,6 +357,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
             s_logger.debug("vm.network.stats.interval - " + vmNetworkStatsInterval.value() + " is 0 or less than 0, so not scheduling the vm network stats thread");
         }
 
+        if (volumeStatsInterval > 0) {
+            _executor.scheduleAtFixedRate(new VolumeStatsTask(), 15000L, volumeStatsInterval, TimeUnit.MILLISECONDS);
+        }
+
         //Schedule disk stats update task
         _diskStatsUpdateExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DiskStatsUpdater"));
 
@@ -644,6 +646,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
                 return;
             }
             // collect the vm disk statistics(total) from hypervisor. added by weizhou, 2013.03.
+            s_logger.trace("Running VM disk stats ...");
             try {
                 Transaction.execute(new TransactionCallbackNoReturn() {
                     @Override
@@ -887,6 +890,51 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
         }
     }
 
+
+    class VolumeStatsTask extends ManagedContextRunnable {
+        @Override
+        protected void runInContext() {
+            try {
+                List<StoragePoolVO> pools = _storagePoolDao.listAll();
+
+                for (StoragePoolVO pool : pools) {
+                    List<VolumeVO> volumes = _volsDao.findByPoolId(pool.getId(), null);
+                    List<String> volumeLocators = new ArrayList<String>();
+                    for (VolumeVO volume: volumes){
+                        if (volume.getFormat() == ImageFormat.QCOW2) {
+                            volumeLocators.add(volume.getUuid());
+                        }
+                        else if (volume.getFormat() == ImageFormat.VHD){
+                            volumeLocators.add(volume.getPath());
+                        }
+                        else if (volume.getFormat() == ImageFormat.OVA){
+                            volumeLocators.add(volume.getChainInfo());
+                        }
+                        else {
+                            s_logger.warn("Volume stats not implemented for this format type " + volume.getFormat() );
+                            break;
+                        }
+                    }
+                    try {
+                        HashMap<String, VolumeStatsEntry> volumeStatsByUuid = _userVmMgr.getVolumeStatistics(pool.getClusterId(), pool.getUuid(), pool.getPoolType(), volumeLocators, StatsTimeout.value());
+                        if (volumeStatsByUuid != null){
+                            _volumeStats.putAll(volumeStatsByUuid);
+                        }
+                    } catch (Exception e) {
+                        s_logger.warn("Failed to get volume stats for cluster with ID: " + pool.getClusterId(), e);
+                        continue;
+                    }
+                }
+            } catch (Throwable t) {
+                s_logger.error("Error trying to retrieve volume stats", t);
+            }
+        }
+    }
+
+    public VolumeStats getVolumeStats(String volumeLocator) {
+        return _volumeStats.get(volumeLocator);
+    }
+
     class StorageCollector extends ManagedContextRunnable {
         @Override
         protected void runInContext() {
@@ -1257,11 +1305,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
 
     @Override
     public String getConfigComponentName() {
-        return this.getClass().getSimpleName();
+        return StatsCollector.class.getSimpleName();
     }
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] { vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin };
+        return new ConfigKey<?>[] { vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout };
     }
 }
diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java
index 7240374..f93692c 100644
--- a/server/src/com/cloud/test/DatabaseConfig.java
+++ b/server/src/com/cloud/test/DatabaseConfig.java
@@ -315,7 +315,7 @@ public class DatabaseConfig {
 
         s_defaultConfigurationValues.put("host.stats.interval", "60000");
         s_defaultConfigurationValues.put("storage.stats.interval", "60000");
-        //s_defaultConfigurationValues.put("volume.stats.interval", "-1");
+        s_defaultConfigurationValues.put("volume.stats.interval", "60000");
         s_defaultConfigurationValues.put("port", "8250");
         s_defaultConfigurationValues.put("integration.api.port", "8096");
         s_defaultConfigurationValues.put("usage.stats.job.exec.time", "00:15"); // run at 12:15am
diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java
index 51cce9d..6a384f1 100644
--- a/server/src/com/cloud/vm/UserVmManager.java
+++ b/server/src/com/cloud/vm/UserVmManager.java
@@ -26,6 +26,7 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 import com.cloud.agent.api.VmDiskStatsEntry;
 import com.cloud.agent.api.VmNetworkStatsEntry;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.VolumeStatsEntry;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.ManagementServerException;
@@ -33,6 +34,7 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.exception.VirtualMachineMigrationException;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.service.ServiceOfferingVO;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.user.Account;
 import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
@@ -82,6 +84,8 @@ public interface UserVmManager extends UserVmService {
 
     HashMap<Long, List<VmDiskStatsEntry>> getVmDiskStatistics(long hostId, String hostName, List<Long> vmIds);
 
+    HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, String poolUuid, StoragePoolType poolType, List<String> volumeLocator, int timout);
+
     boolean deleteVmGroup(long groupId);
 
     boolean addInstanceToGroup(long userVmId, String group);
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 07dd0ea..791ad95 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -103,6 +103,8 @@ import com.cloud.agent.api.GetVmNetworkStatsAnswer;
 import com.cloud.agent.api.GetVmNetworkStatsCommand;
 import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.GetVolumeStatsAnswer;
+import com.cloud.agent.api.GetVolumeStatsCommand;
 import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.agent.api.RestoreVMSnapshotAnswer;
 import com.cloud.agent.api.RestoreVMSnapshotCommand;
@@ -110,6 +112,7 @@ import com.cloud.agent.api.StartAnswer;
 import com.cloud.agent.api.VmDiskStatsEntry;
 import com.cloud.agent.api.VmNetworkStatsEntry;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.VolumeStatsEntry;
 import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
@@ -167,6 +170,7 @@ import com.cloud.gpu.GPU;
 import com.cloud.ha.HighAvailabilityManager;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
+import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.HypervisorCapabilitiesVO;
@@ -226,6 +230,7 @@ import com.cloud.storage.GuestOSVO;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Storage.TemplateType;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.StorageManager;
@@ -1869,6 +1874,23 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
     }
 
     @Override
+    public HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, String poolUuid, StoragePoolType poolType, List<String> volumeLocator, int timeout) {
+        List<HostVO> neighbors = _resourceMgr.listHostsInClusterByStatus(clusterId, Status.Up);
+        for (HostVO neighbor : neighbors) {
+            GetVolumeStatsCommand cmd = new GetVolumeStatsCommand(poolType, poolUuid, volumeLocator);
+            if (timeout > 0) {
+                cmd.setWait(timeout/1000);
+            }
+            Answer answer = _agentMgr.easySend(neighbor.getId(), cmd);
+            if (answer instanceof GetVolumeStatsAnswer){
+                GetVolumeStatsAnswer volstats = (GetVolumeStatsAnswer)answer;
+                return volstats.getVolumeStats();
+            }
+        }
+        return null;
+    }
+
+    @Override
     @DB
     public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException, CloudRuntimeException {
 
diff --git a/setup/db/db/schema-41000to41100.sql b/setup/db/db/schema-41000to41100.sql
index e5e6c05..db98f2e 100644
--- a/setup/db/db/schema-41000to41100.sql
+++ b/setup/db/db/schema-41000to41100.sql
@@ -295,4 +295,141 @@ ALTER TABLE `cloud`.`oobm` MODIFY COLUMN port VARCHAR(255);
 INSERT IGNORE INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `value`, `description`, `default_value`, `is_dynamic`) VALUES ('Console Proxy', 'DEFAULT', 'AgentManager', 'consoleproxy.sslEnabled', 'false', 'Enable SSL for console proxy', 'false', 0);
 
 -- CLOUDSTACK-9859: Retirement of midonet plugin (final removal) 
-delete from `cloud`.`configuration` where name in ('midonet.apiserver.address', 'midonet.providerrouter.id');
\ No newline at end of file
+delete from `cloud`.`configuration` where name in ('midonet.apiserver.address', 'midonet.providerrouter.id');
+
+-- CLOUDSTACK-9972: Enhance listVolumes API
+INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Premium', 'DEFAULT', 'management-server', 'volume.stats.interval', '600000', 'Interval (in seconds) to report volume statistics', '600000', now(), NULL, NULL);
+
+DROP VIEW IF EXISTS `cloud`.`volume_view`;
+CREATE VIEW `cloud`.`volume_view` AS
+    select
+        volumes.id,
+        volumes.uuid,
+        volumes.name,
+        volumes.device_id,
+        volumes.volume_type,
+        volumes.provisioning_type,
+        volumes.size,
+        volumes.min_iops,
+        volumes.max_iops,
+        volumes.created,
+        volumes.state,
+        volumes.attached,
+        volumes.removed,
+        volumes.display_volume,
+        volumes.format,
+        volumes.path,
+        volumes.chain_info,
+        account.id account_id,
+        account.uuid account_uuid,
+        account.account_name account_name,
+        account.type account_type,
+        domain.id domain_id,
+        domain.uuid domain_uuid,
+        domain.name domain_name,
+        domain.path domain_path,
+        projects.id project_id,
+        projects.uuid project_uuid,
+        projects.name project_name,
+        data_center.id data_center_id,
+        data_center.uuid data_center_uuid,
+        data_center.name data_center_name,
+        data_center.networktype data_center_type,
+        vm_instance.id vm_id,
+        vm_instance.uuid vm_uuid,
+        vm_instance.name vm_name,
+        vm_instance.state vm_state,
+        vm_instance.vm_type,
+        user_vm.display_name vm_display_name,
+        volume_store_ref.size volume_store_size,
+        volume_store_ref.download_pct,
+        volume_store_ref.download_state,
+        volume_store_ref.error_str,
+        volume_store_ref.created created_on_store,
+        disk_offering.id disk_offering_id,
+        disk_offering.uuid disk_offering_uuid,
+        disk_offering.name disk_offering_name,
+        disk_offering.display_text disk_offering_display_text,
+        disk_offering.use_local_storage,
+        disk_offering.system_use,
+        disk_offering.bytes_read_rate,
+        disk_offering.bytes_write_rate,
+        disk_offering.iops_read_rate,
+        disk_offering.iops_write_rate,
+        disk_offering.cache_mode,
+        storage_pool.id pool_id,
+        storage_pool.uuid pool_uuid,
+        storage_pool.name pool_name,
+        cluster.id cluster_id,
+        cluster.name cluster_name,
+        cluster.uuid cluster_uuid,
+        cluster.hypervisor_type,
+        vm_template.id template_id,
+        vm_template.uuid template_uuid,
+        vm_template.extractable,
+        vm_template.type template_type,
+        vm_template.name template_name,
+        vm_template.display_text template_display_text,
+        iso.id iso_id,
+        iso.uuid iso_uuid,
+        iso.name iso_name,
+        iso.display_text iso_display_text,
+        resource_tags.id tag_id,
+        resource_tags.uuid tag_uuid,
+        resource_tags.key tag_key,
+        resource_tags.value tag_value,
+        resource_tags.domain_id tag_domain_id,
+        resource_tags.account_id tag_account_id,
+        resource_tags.resource_id tag_resource_id,
+        resource_tags.resource_uuid tag_resource_uuid,
+        resource_tags.resource_type tag_resource_type,
+        resource_tags.customer tag_customer,
+        async_job.id job_id,
+        async_job.uuid job_uuid,
+        async_job.job_status job_status,
+        async_job.account_id job_account_id,
+        host_pod_ref.id pod_id,
+        host_pod_ref.uuid pod_uuid,
+        host_pod_ref.name pod_name,
+        resource_tag_account.account_name tag_account_name,
+        resource_tag_domain.uuid tag_domain_uuid,
+        resource_tag_domain.name tag_domain_name
+    from
+        `cloud`.`volumes`
+            inner join
+        `cloud`.`account` ON volumes.account_id = account.id
+            inner join
+        `cloud`.`domain` ON volumes.domain_id = domain.id
+            left join
+        `cloud`.`projects` ON projects.project_account_id = account.id
+            left join
+        `cloud`.`data_center` ON volumes.data_center_id = data_center.id
+            left join
+        `cloud`.`vm_instance` ON volumes.instance_id = vm_instance.id
+            left join
+        `cloud`.`user_vm` ON user_vm.id = vm_instance.id
+            left join
+        `cloud`.`volume_store_ref` ON volumes.id = volume_store_ref.volume_id
+            left join
+        `cloud`.`disk_offering` ON volumes.disk_offering_id = disk_offering.id
+            left join
+        `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id
+            left join
+        `cloud`.`host_pod_ref` ON storage_pool.pod_id = host_pod_ref.id
+            left join
+        `cloud`.`cluster` ON storage_pool.cluster_id = cluster.id
+            left join
+        `cloud`.`vm_template` ON volumes.template_id = vm_template.id
+            left join
+        `cloud`.`vm_template` iso ON iso.id = volumes.iso_id
+            left join
+        `cloud`.`resource_tags` ON resource_tags.resource_id = volumes.id
+            and resource_tags.resource_type = 'Volume'
+            left join
+        `cloud`.`async_job` ON async_job.instance_id = volumes.id
+            and async_job.instance_type = 'Volume'
+            and async_job.job_status = 0
+            left join
+        `cloud`.`account` resource_tag_account ON resource_tag_account.id = resource_tags.account_id
+            left join
+        `cloud`.`domain` resource_tag_domain ON resource_tag_domain.id = resource_tags.domain_id;
diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py
index fca65f2..588b762 100644
--- a/test/integration/smoke/test_volumes.py
+++ b/test/integration/smoke/test_volumes.py
@@ -35,7 +35,8 @@ from marvin.lib.base import (ServiceOffering,
 from marvin.lib.common import (get_domain,
                                 get_zone,
                                 get_template,
-                                find_storage_pool_type)
+                                find_storage_pool_type,
+                                get_pod)
 from marvin.lib.utils import checkVolumeSize
 from marvin.codes import SUCCESS, FAILED, XEN_SERVER
 from nose.plugins.attrib import attr
@@ -797,3 +798,74 @@ class TestVolumes(cloudstackTestCase):
                         "Check if volume exists in ListVolumes"
                     )
         return
+
+    @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true")
+    def test_10_list_volumes(self):
+
+        # Validate the following
+        #
+        # 1. List Root Volume and waits until it has the newly introduced attributes
+        #
+        # 2. Verifies return attributes has values different from none, when instance is running
+        #
+
+        list_vm = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)[0]
+
+        host = Host.list(
+            self.apiclient,
+            type='Routing',
+            virtualmachineid=list_vm.id
+        )[0]
+        list_pods = get_pod(self.apiclient, self.zone.id, host.podid)
+
+        root_volume = self.wait_for_attributes_and_return_root_vol()
+
+        self.assertTrue(hasattr(root_volume, "utilization"))
+        self.assertTrue(root_volume.utilization is not None)
+
+        self.assertTrue(hasattr(root_volume, "virtualsize"))
+        self.assertTrue(root_volume.virtualsize is not None)
+
+        self.assertTrue(hasattr(root_volume, "physicalsize"))
+        self.assertTrue(root_volume.physicalsize is not None)
+
+        self.assertTrue(hasattr(root_volume, "vmname"))
+        self.assertEqual(root_volume.vmname, list_vm.name)
+
+        self.assertTrue(hasattr(root_volume, "clustername"))
+        self.assertTrue(root_volume.clustername is not None)
+
+        self.assertTrue(hasattr(root_volume, "clusterid"))
+        self.assertTrue(root_volume.clusterid is not None)
+
+        self.assertTrue(hasattr(root_volume, "storageid"))
+        self.assertTrue(root_volume.storageid is not None)
+
+        self.assertTrue(hasattr(root_volume, "storage"))
+        self.assertTrue(root_volume.storage is not None)
+
+        self.assertTrue(hasattr(root_volume, "zoneid"))
+        self.assertEqual(root_volume.zoneid, self.zone.id)
+
+        self.assertTrue(hasattr(root_volume, "zonename"))
+        self.assertEqual(root_volume.zonename, self.zone.name)
+
+        self.assertTrue(hasattr(root_volume, "podid"))
+        self.assertEqual(root_volume.podid, list_pods.id)
+
+        self.assertTrue(hasattr(root_volume, "podname"))
+        self.assertEqual(root_volume.podname, list_pods.name)
+
+    def wait_for_attributes_and_return_root_vol(self):
+
+        for i in range(60):
+            list_volume_response = Volume.list(
+                self.apiClient,
+                virtualmachineid=self.virtual_machine.id,
+                type='ROOT',
+                listall=True
+            )
+            if list_volume_response[0].virtualsize is not None:
+                return list_volume_response[0]
+
+            time.sleep(1)
diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js
index 538fd4b..afb4269 100644
--- a/ui/l10n/ar.js
+++ b/ui/l10n/ar.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Disk Write Rate (IOPS)",
     "label.disk.offering": "Disk Offering",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning Type",
     "label.disk.read.bytes": "Disk Read (Bytes)",
     "label.disk.read.io": "Disk Read (IO)",
     "label.disk.size": "Disk Size",
     "label.disk.size.gb": "Disk Size (in GB)",
     "label.disk.total": "Disk Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disk Volume",
     "label.disk.write.bytes": "Disk Write (Bytes)",
     "label.disk.write.io": "Disk Write (IO)",
diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js
index d97a948..3b1f04c 100644
--- a/ui/l10n/ca.js
+++ b/ui/l10n/ca.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Disk Write Rate (IOPS)",
     "label.disk.offering": "Disk Offering",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning Type",
     "label.disk.read.bytes": "Disk Read (Bytes)",
     "label.disk.read.io": "Disk Read (IO)",
     "label.disk.size": "Disk Size",
     "label.disk.size.gb": "Disk Size (in GB)",
     "label.disk.total": "Disk Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disk Volume",
     "label.disk.write.bytes": "Disk Write (Bytes)",
     "label.disk.write.io": "Disk Write (IO)",
diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js
index f3d93bf..c0f2e0a 100644
--- a/ui/l10n/de_DE.js
+++ b/ui/l10n/de_DE.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Festplatten-Schreibrate (IOPS)",
     "label.disk.offering": "Festplattenangebot",
     "label.disk.offering.details": "Festplattenangebotdetails",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisionierungstyp",
     "label.disk.read.bytes": "Festplatte Lesen (Bytes)",
     "label.disk.read.io": "Festplatte Lesen (EA)",
     "label.disk.size": "Festplattengröße",
     "label.disk.size.gb": "Festplattengröße (in GB)",
     "label.disk.total": "Gesamtzahl der Festplatten",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Festplattenvolumen",
     "label.disk.write.bytes": "Festplatte Schreiben (Bytes)",
     "label.disk.write.io": "Festplatte Schreiben (EA)",
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 3727dc6..003c93f 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -667,12 +667,15 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.disk.iops.write.rate":"Disk Write Rate (IOPS)",
 "label.disk.offering":"Disk Offering",
 "label.disk.offering.details":"Disk offering details",
+"label.disk.physicalsize":"Physical Size",
 "label.disk.provisioningtype":"Provisioning Type",
 "label.disk.read.bytes":"Disk Read (Bytes)",
 "label.disk.read.io":"Disk Read (IO)",
 "label.disk.size":"Disk Size",
 "label.disk.size.gb":"Disk Size (in GB)",
 "label.disk.total":"Disk Total",
+"label.disk.utilisation":"Utilisation",
+"label.disk.virtualsize":"Virtual Size",
 "label.disk.volume":"Disk Volume",
 "label.disk.write.bytes":"Disk Write (Bytes)",
 "label.disk.write.io":"Disk Write (IO)",
diff --git a/ui/l10n/es.js b/ui/l10n/es.js
index 38ec9c0..6abfd8e 100644
--- a/ui/l10n/es.js
+++ b/ui/l10n/es.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Tasa Escritura de Disco (IOPS)",
     "label.disk.offering": "Oferta de Disco",
     "label.disk.offering.details": "Detalles de Oferta de Disco",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Tipo de Aprovisionamiento",
     "label.disk.read.bytes": "Lectura Disco (Bytes)",
     "label.disk.read.io": "Lectura Disco (IO)",
     "label.disk.size": "tamaño de disco",
     "label.disk.size.gb": "tamaño de disco (en GB)",
     "label.disk.total": "disco Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "volumen de disco",
     "label.disk.write.bytes": "Escritura Disco (Bytes)",
     "label.disk.write.io": "Escritura Disco (IO)",
diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js
index 0bb6a0d..dd5e85a 100644
--- a/ui/l10n/fr_FR.js
+++ b/ui/l10n/fr_FR.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Débit écriture disque (IOPS)",
     "label.disk.offering": "Offre de Disque",
     "label.disk.offering.details": "Détails offre de disque",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Type de provisionnement",
     "label.disk.read.bytes": "Lecture Disque (Octets)",
     "label.disk.read.io": "Lecture Disque (IO)",
     "label.disk.size": "Capacité disque",
     "label.disk.size.gb": "Capacité disque (Go)",
     "label.disk.total": "Espace disque total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Volume disque",
     "label.disk.write.bytes": "Écriture Disque (Octets)",
     "label.disk.write.io": "Écriture Disque (IO)",
diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js
index 3da6941..23519b9 100644
--- a/ui/l10n/hu.js
+++ b/ui/l10n/hu.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Írási ráta (IOPS)",
     "label.disk.offering": "Merevlemez ajánlat",
     "label.disk.offering.details": "Merevlemez ajánlat részletei",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Létrehozás típusa",
     "label.disk.read.bytes": "Merevlemez olvasás (Byte)",
     "label.disk.read.io": "Merevlemez írás (IO)",
     "label.disk.size": "Merevlemez méret",
     "label.disk.size.gb": "Merevlemez méret (GB)",
     "label.disk.total": "Merevlemez összes",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Merevlemez kötet",
     "label.disk.write.bytes": "Merevlemez írás (byte)",
     "label.disk.write.io": "Merevlemez írás (IO)",
diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js
index 247b8e0..c4501e6 100644
--- a/ui/l10n/it_IT.js
+++ b/ui/l10n/it_IT.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Disk Write Rate (IOPS)",
     "label.disk.offering": "Offerta Disco",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Tipo di Provisioning",
     "label.disk.read.bytes": "Disk Read (Bytes)",
     "label.disk.read.io": "Disk Read (IO)",
     "label.disk.size": "Disk Size",
     "label.disk.size.gb": "Disk Size (in GB)",
     "label.disk.total": "Disk Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disk Volume",
     "label.disk.write.bytes": "Disk Write (Bytes)",
     "label.disk.write.io": "Disk Write (IO)",
diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js
index a5da1a3..a2f42f9 100644
--- a/ui/l10n/ja_JP.js
+++ b/ui/l10n/ja_JP.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "ディスク書き込み速度 (IOPS)",
     "label.disk.offering": "ディスク オファリング",
     "label.disk.offering.details": "ディスクオファリングの詳細",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "プロビジョニングの種類",
     "label.disk.read.bytes": "ディスク読み取り (バイト)",
     "label.disk.read.io": "ディスク読み取り (IO)",
     "label.disk.size": "ディスク サイズ",
     "label.disk.size.gb": "ディスク サイズ (GB)",
     "label.disk.total": "ディスク合計",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "ディスク ボリューム",
     "label.disk.write.bytes": "ディスク書き込み (バイト)",
     "label.disk.write.io": "ディスク書き込み (IO)",
diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js
index f592a7c..9655052 100644
--- a/ui/l10n/ko_KR.js
+++ b/ui/l10n/ko_KR.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Disk Write Rate (IOPS)",
     "label.disk.offering": "디스크 제공",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning Type",
     "label.disk.read.bytes": "Disk Read (Bytes)",
     "label.disk.read.io": "Disk Read (IO)",
     "label.disk.size": "디스크 크기",
     "label.disk.size.gb": "디스크 크기(GB 단위)",
     "label.disk.total": "디스크 합계",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "디스크 볼륨",
     "label.disk.write.bytes": "Disk Write (Bytes)",
     "label.disk.write.io": "Disk Write (IO)",
diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js
index 1ef4145..c9836ea 100644
--- a/ui/l10n/nb_NO.js
+++ b/ui/l10n/nb_NO.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Diskskrivehastighet (IOPS)",
     "label.disk.offering": "Disktilbud",
     "label.disk.offering.details": "Disktilbud detaljer",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisjoneringstype",
     "label.disk.read.bytes": "Disk lese (Bytes)",
     "label.disk.read.io": "Disk lese (IO)",
     "label.disk.size": "Diskstørrelse",
     "label.disk.size.gb": "Diskstørrelse (i GB)",
     "label.disk.total": "Disk Totalt",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disk Volum",
     "label.disk.write.bytes": "Disk skrive (Bytes)",
     "label.disk.write.io": "Disk skrive (IO)",
diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js
index 58465f3..5e43889 100644
--- a/ui/l10n/nl_NL.js
+++ b/ui/l10n/nl_NL.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Schrijf snelheid Schijf (IOPS)",
     "label.disk.offering": "Schijf Aanbieding",
     "label.disk.offering.details": "schijfe offerte gegevens",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning type",
     "label.disk.read.bytes": "Schijf lezen (Bytes)",
     "label.disk.read.io": "Schijf Lezen (IO)",
     "label.disk.size": "Schijf Grootte",
     "label.disk.size.gb": "Schijf Grootte (in GB)",
     "label.disk.total": "Schijf Totaal",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Schijf Volume",
     "label.disk.write.bytes": "Schijf Schrijven (Bytes)",
     "label.disk.write.io": "Schijf Schrijven (IO)",
diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js
index 1ba89b2..8b1cb42 100644
--- a/ui/l10n/pl.js
+++ b/ui/l10n/pl.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Disk Write Rate (IOPS)",
     "label.disk.offering": "Disk Offering",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning Type",
     "label.disk.read.bytes": "Disk Read (Bytes)",
     "label.disk.read.io": "Disk Read (IO)",
     "label.disk.size": "Wielkość dysku",
     "label.disk.size.gb": "Wielkość dysku (w GB)",
     "label.disk.total": "Disk Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disk Volume",
     "label.disk.write.bytes": "Disk Write (Bytes)",
     "label.disk.write.io": "Disk Write (IO)",
diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js
index 77bfe53..fbaafcb 100644
--- a/ui/l10n/pt_BR.js
+++ b/ui/l10n/pt_BR.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Taxa de Escrita no Disco (IOPS)",
     "label.disk.offering": "Oferta de Disco",
     "label.disk.offering.details": "Detalhes da oferta de disco",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Tipo de Provisionamento",
     "label.disk.read.bytes": "Leitura do Disco (Bytes)",
     "label.disk.read.io": "Leitura do Disk (I/O)",
     "label.disk.size": "Tamanho do Disco",
     "label.disk.size.gb": "Tamanho (em GB)",
     "label.disk.total": "Disco Total",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Disco",
     "label.disk.write.bytes": "Escrita no Disco (Bytes)",
     "label.disk.write.io": "Escrita no Disco (I/O)",
diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js
index aaa40b8..649e5fe 100644
--- a/ui/l10n/ru_RU.js
+++ b/ui/l10n/ru_RU.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "Скорость записи диска (IOPS)",
     "label.disk.offering": "Услуга дискового пространства",
     "label.disk.offering.details": "Disk offering details",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "Provisioning Type",
     "label.disk.read.bytes": "Прочитано с диска (Байт)",
     "label.disk.read.io": "Прочитано с диска (IO)",
     "label.disk.size": "Размер диска",
     "label.disk.size.gb": "Размер диска (в ГБ)",
     "label.disk.total": "Всего в дисках",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "Объем диска",
     "label.disk.write.bytes": "Записано на диск (Байт)",
     "label.disk.write.io": "Записано на диск (IO)",
diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js
index 2131c98..c4a663c4 100644
--- a/ui/l10n/zh_CN.js
+++ b/ui/l10n/zh_CN.js
@@ -657,12 +657,15 @@ var dictionary = {
     "label.disk.iops.write.rate": "磁盘写入速度(IOPS)",
     "label.disk.offering": "磁盘方案",
     "label.disk.offering.details": "磁盘方案详情",
+    "label.disk.physicalsize":"Physical Size",
     "label.disk.provisioningtype": "置备类型",
     "label.disk.read.bytes": "磁盘读取(字节)",
     "label.disk.read.io": "磁盘读取(IO)",
     "label.disk.size": "磁盘大小",
     "label.disk.size.gb": "磁盘大小(GB)",
     "label.disk.total": "磁盘总量",
+    "label.disk.utilisation":"Utilisation",
+    "label.disk.virtualsize":"Virtual Size",
     "label.disk.volume": "磁盘卷",
     "label.disk.write.bytes": "磁盘写入(字节)",
     "label.disk.write.io": "磁盘写入(IO)",
diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js
index 3152af7..bc73934 100644
--- a/ui/scripts/metrics.js
+++ b/ui/scripts/metrics.js
@@ -577,6 +577,18 @@
                 sizegb: {
                     label: 'label.metrics.disk.size'
                 },
+                physicalsize: {
+                    label: 'label.disk.physicalsize',
+                    converter: function(args) {
+                        if (args == null || args == 0)
+                            return "";
+                        else
+                            return cloudStack.converters.convertBytes(args);
+                    }
+                },
+                utilization: {
+                    label: 'label.disk.utilisation'
+                },
                 storagetype: {
                     label: 'label.metrics.disk.storagetype'
                 },
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index 639f8a9..9c017b1 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -1752,7 +1752,7 @@
                                     if (isAdmin()) {
                                         hiddenFields = [];
                                     } else {
-                                        hiddenFields = ['storage', 'hypervisor'];
+                                        hiddenFields = ['storage', 'hypervisor', 'virtualsize', 'physicalsize', 'utilization', 'clusterid', 'clustername'];
                                     }
                                     return hiddenFields;
                                 },
@@ -1817,6 +1817,33 @@
                                                 return cloudStack.converters.convertBytes(args);
                                         }
                                     },
+                                    clusterid: {
+					label: 'label.cluster'
+                                    },
+                                    clustername: {
+					label: 'label.cluster.name'
+                                    },
+                                    physicalsize: {
+                                        label: 'label.disk.physicalsize',
+                                        converter: function(args) {
+                                            if (args == null || args == 0)
+                                                return "";
+                                            else
+                                                return cloudStack.converters.convertBytes(args);
+                                        }
+                                    },
+                                    utilization: {
+                                        label: 'label.disk.utilisation'
+                                    },
+                                    virtualsize: {
+                                        label: 'label.disk.virtualsize',
+                                        converter: function(args) {
+                                            if (args == null || args == 0)
+                                                return "";
+                                            else
+                                                return cloudStack.converters.convertBytes(args);
+                                        }
+                                    },
                                     miniops: {
                                         label: 'label.disk.iops.min',
                                         converter: function(args) {
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
index 1152ba5..3659cf5 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
@@ -24,7 +24,9 @@ import org.apache.log4j.Logger;
 import com.vmware.vim25.DatastoreHostMount;
 import com.vmware.vim25.DatastoreSummary;
 import com.vmware.vim25.FileInfo;
+import com.vmware.vim25.FileQueryFlags;
 import com.vmware.vim25.HostDatastoreBrowserSearchResults;
+import com.vmware.vim25.HostDatastoreBrowserSearchSpec;
 import com.vmware.vim25.HostMountInfo;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.ObjectContent;
@@ -339,6 +341,36 @@ public class DatastoreMO extends BaseMO {
         return false;
     }
 
+    public long fileDiskSize(String fileFullPath) throws Exception {
+        long size = 0;
+        DatastoreFile file = new DatastoreFile(fileFullPath);
+        DatastoreFile dirFile = new DatastoreFile(file.getDatastoreName(), file.getDir());
+
+        HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
+
+        HostDatastoreBrowserSearchSpec searchSpec = new HostDatastoreBrowserSearchSpec();
+        FileQueryFlags fqf = new FileQueryFlags();
+        fqf.setFileSize(true);
+        fqf.setFileOwner(true);
+        fqf.setModification(true);
+        searchSpec.setDetails(fqf);
+        searchSpec.setSearchCaseInsensitive(false);
+        searchSpec.getMatchPattern().add(file.getFileName());
+        s_logger.debug("Search file " + file.getFileName() + " on " + dirFile.getPath()); //ROOT-2.vmdk, [3ecf7a579d3b3793b86d9d019a97ae27] s-2-VM
+        HostDatastoreBrowserSearchResults result = browserMo.searchDatastore(dirFile.getPath(), searchSpec);
+        if (result != null) {
+            List<FileInfo> info = result.getFile();
+            for (FileInfo fi : info) {
+                if (file.getFileName().equals(fi.getPath())) {
+                    s_logger.debug("File found = " + fi.getPath() + ", size=" + fi.getFileSize());
+                    return fi.getFileSize();
+                }
+            }
+        }
+        s_logger.debug("File " + fileFullPath + " does not exist on datastore");
+        return size;
+    }
+
     public boolean folderExists(String folderParentDatastorePath, String folderName) throws Exception {
         HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
 
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
index c7bdbcd..a4f26db 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -2376,6 +2376,59 @@ public class VirtualMachineMO extends BaseMO {
         return null;
     }
 
+    // return pair of VirtualDisk and disk device bus name(ide0:0, etc)
+    public Pair<VirtualDisk, String> getDiskDevice(String vmdkDatastorePath, boolean matchExactly) throws Exception {
+        List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
+
+        DatastoreFile dsSrcFile = new DatastoreFile(vmdkDatastorePath);
+        String srcBaseName = dsSrcFile.getFileBaseName();
+        String trimmedSrcBaseName = VmwareHelper.trimSnapshotDeltaPostfix(srcBaseName);
+
+        if (matchExactly) {
+            s_logger.info("Look for disk device info from volume : " + vmdkDatastorePath + " with base name: " + srcBaseName);
+        } else {
+            s_logger.info("Look for disk device info from volume : " + vmdkDatastorePath + " with trimmed base name: " + trimmedSrcBaseName);
+        }
+
+        if (devices != null && devices.size() > 0) {
+            for (VirtualDevice device : devices) {
+                if (device instanceof VirtualDisk) {
+                    s_logger.info("Test against disk device, controller key: " + device.getControllerKey() + ", unit number: " + device.getUnitNumber());
+
+                    VirtualDeviceBackingInfo backingInfo = ((VirtualDisk)device).getBacking();
+                    if (backingInfo instanceof VirtualDiskFlatVer2BackingInfo) {
+                        VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo)backingInfo;
+                        do {
+                            s_logger.info("Test against disk backing : " + diskBackingInfo.getFileName());
+
+                            DatastoreFile dsBackingFile = new DatastoreFile(diskBackingInfo.getFileName());
+                            String backingBaseName = dsBackingFile.getFileBaseName();
+                            if (matchExactly) {
+                                if (backingBaseName.equalsIgnoreCase(srcBaseName)) {
+                                    String deviceNumbering = getDeviceBusName(devices, device);
+
+                                    s_logger.info("Disk backing : " + diskBackingInfo.getFileName() + " matches ==> " + deviceNumbering);
+                                    return new Pair<VirtualDisk, String>((VirtualDisk)device, deviceNumbering);
+                                }
+                            } else {
+                                if (backingBaseName.contains(trimmedSrcBaseName)) {
+                                    String deviceNumbering = getDeviceBusName(devices, device);
+
+                                    s_logger.info("Disk backing : " + diskBackingInfo.getFileName() + " matches ==> " + deviceNumbering);
+                                    return new Pair<VirtualDisk, String>((VirtualDisk)device, deviceNumbering);
+                                }
+                            }
+
+                            diskBackingInfo = diskBackingInfo.getParent();
+                        } while (diskBackingInfo != null);
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
     public String getDiskCurrentTopBackingFileInChain(String deviceBusName) throws Exception {
         List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
         if (devices != null && devices.size() > 0) {

-- 
To stop receiving notification emails like this one, please contact
['"commits@cloudstack.apache.org" <commits@cloudstack.apache.org>'].

Mime
View raw message