You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2017/04/06 06:35:56 UTC

[3/4] git commit: updated refs/heads/4.9 to 6548839

CLOUDSTACK-9783: Improve metrics view performance

This improves the metrics view feature by improving the rendering performance
of metrics view tables, by reimplementing the logic at the backend and data
served via APIs. In large environments, the older implementation would
make several API calls that increases both network and database load.

List of APIs introduced for improving the performance:

    listClustersMetrics
    listHostsMetrics
    listInfrastructure
    listStoragePoolsMetrics
    listVMsMetrics
    listVolumesMetrics
    listZonesMetrics

Signed-off-by: Rohit Yadav <ro...@shapeblue.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/40225350
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/40225350
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/40225350

Branch: refs/heads/4.9
Commit: 402253504e9520104caf9fbc1317042f2fd89474
Parents: b95bf8f
Author: Rohit Yadav <ro...@shapeblue.com>
Authored: Thu Feb 16 13:45:15 2017 +0530
Committer: Rohit Yadav <ro...@shapeblue.com>
Committed: Tue Feb 28 13:45:03 2017 +0530

----------------------------------------------------------------------
 .travis.yml                                     |   1 +
 .../command/admin/cluster/ListClustersCmd.java  |  12 +-
 .../api/command/admin/host/ListHostsCmd.java    |  20 +-
 .../cloudstack/api/response/HostResponse.java   | 159 +++++
 .../cloudstack/api/response/NicResponse.java    |  84 ++-
 .../api/response/StoragePoolResponse.java       |   8 +
 .../cloudstack/api/response/UserVmResponse.java |  24 +
 .../cloudstack/api/response/VolumeResponse.java | 149 ++++-
 .../cloudstack/api/response/ZoneResponse.java   |  88 +++
 client/pom.xml                                  |   5 +
 .../schema/src/com/cloud/dc/dao/ClusterDao.java |   8 +-
 .../src/com/cloud/dc/dao/ClusterDaoImpl.java    |  28 +-
 .../schema/src/com/cloud/dc/dao/HostPodDao.java |   2 +-
 .../src/com/cloud/dc/dao/HostPodDaoImpl.java    |   6 +-
 plugins/metrics/pom.xml                         |  55 ++
 .../cloudstack/metrics/module.properties        |  18 +
 .../metrics/spring-metrics-context.xml          |  27 +
 .../cloudstack/api/ListClustersMetricsCmd.java  |  51 ++
 .../cloudstack/api/ListHostsMetricsCmd.java     |  54 ++
 .../cloudstack/api/ListInfrastructureCmd.java   |  52 ++
 .../api/ListStoragePoolsMetricsCmd.java         |  52 ++
 .../cloudstack/api/ListVMsMetricsCmd.java       |  51 ++
 .../cloudstack/api/ListVolumesMetricsCmd.java   |  51 ++
 .../cloudstack/api/ListZonesMetricsCmd.java     |  52 ++
 .../cloudstack/metrics/MetricsService.java      |  46 ++
 .../cloudstack/metrics/MetricsServiceImpl.java  | 563 +++++++++++++++++
 .../response/ClusterMetricsResponse.java        | 211 +++++++
 .../response/HostMetricsResponse.java           | 204 ++++++
 .../response/InfrastructureResponse.java        | 101 +++
 .../response/StoragePoolMetricsResponse.java    | 105 ++++
 .../cloudstack/response/VmMetricsResponse.java  | 108 ++++
 .../response/VolumeMetricsResponse.java         |  41 ++
 .../response/ZoneMetricsResponse.java           | 206 ++++++
 plugins/pom.xml                                 |   1 +
 .../com/cloud/api/query/dao/HostJoinDao.java    |   2 +
 .../cloud/api/query/dao/HostJoinDaoImpl.java    |  15 +
 .../deploy/DeploymentPlanningManagerImpl.java   |   2 +-
 test/integration/smoke/test_metrics_api.py      | 210 +++++++
 tools/apidoc/gen_toc.py                         |   4 +-
 ui/scripts/metrics.js                           | 626 +++----------------
 ui/scripts/system.js                            | 331 +---------
 ui/scripts/ui/widgets/listView.js               |   9 +-
 42 files changed, 2922 insertions(+), 920 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index da81633..b8fbf0a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -48,6 +48,7 @@ env:
              smoke/test_list_ids_parameter
              smoke/test_loadbalance
              smoke/test_login
+             smoke/test_metrics_api
              smoke/test_multipleips_per_nic
              smoke/test_network
              smoke/test_network_acl

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java
index 432ca92..74ad764 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java
@@ -125,18 +125,22 @@ public class ListClustersCmd extends BaseListCmd {
         return s_name;
     }
 
-    @Override
-    public void execute() {
+    protected List<ClusterResponse> getClusterResponses() {
         Pair<List<? extends Cluster>, Integer> result = _mgr.searchForClusters(this);
-        ListResponse<ClusterResponse> response = new ListResponse<ClusterResponse>();
         List<ClusterResponse> clusterResponses = new ArrayList<ClusterResponse>();
         for (Cluster cluster : result.first()) {
             ClusterResponse clusterResponse = _responseGenerator.createClusterResponse(cluster, showCapacities);
             clusterResponse.setObjectName("cluster");
             clusterResponses.add(clusterResponse);
         }
+        return clusterResponses;
+    }
 
-        response.setResponses(clusterResponses, result.second());
+    @Override
+    public void execute() {
+        List<ClusterResponse> clusterResponses = getClusterResponses();
+        ListResponse<ClusterResponse> response = new ListResponse<ClusterResponse>();
+        response.setResponses(clusterResponses, clusterResponses.size());
         response.setResponseName(getCommandName());
         this.setResponseObject(response);
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
index 424fc05..3391fdc 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
@@ -132,6 +132,10 @@ public class ListHostsCmd extends BaseListCmd {
         return state;
     }
 
+    public void setType(String type) {
+        this.type = type;
+    }
+
     public String getType() {
         return type;
     }
@@ -198,19 +202,16 @@ public class ListHostsCmd extends BaseListCmd {
         return ApiCommandJobType.Host;
     }
 
-    @Override
-    public void execute() {
-        ListResponse<HostResponse> response = null;
+    protected ListResponse<HostResponse> getHostResponses() {
+        ListResponse<HostResponse> response = new ListResponse<>();
         if (getVirtualMachineId() == null) {
             response = _queryService.searchForServers(this);
         } else {
             Pair<List<? extends Host>, Integer> result;
             Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
-                _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
+                    _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
             result = hostsForMigration.first();
             List<? extends Host> hostsWithCapacity = hostsForMigration.second();
-
-            response = new ListResponse<HostResponse>();
             List<HostResponse> hostResponses = new ArrayList<HostResponse>();
             for (Host host : result.first()) {
                 HostResponse hostResponse = _responseGenerator.createHostResponse(host, getDetails());
@@ -222,9 +223,14 @@ public class ListHostsCmd extends BaseListCmd {
                 hostResponse.setObjectName("host");
                 hostResponses.add(hostResponse);
             }
-
             response.setResponses(hostResponses, result.second());
         }
+        return response;
+    }
+
+    @Override
+    public void execute() {
+        ListResponse<HostResponse> response = getHostResponses();
         response.setResponseName(getCommandName());
         this.setResponseObject(response);
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/HostResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java
index ab9c8c3..90fe800 100644
--- a/api/src/org/apache/cloudstack/api/response/HostResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/HostResponse.java
@@ -458,4 +458,163 @@ public class HostResponse extends BaseResponse {
 
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public Status getState() {
+        return state;
+    }
+
+    public Date getDisconnectedOn() {
+        return disconnectedOn;
+    }
+
+    public Host.Type getHostType() {
+        return hostType;
+    }
+
+    public String getOsCategoryId() {
+        return osCategoryId;
+    }
+
+    public String getOsCategoryName() {
+        return osCategoryName;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public String getZoneId() {
+        return zoneId;
+    }
+
+    public String getZoneName() {
+        return zoneName;
+    }
+
+    public String getPodId() {
+        return podId;
+    }
+
+    public String getPodName() {
+        return podName;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public HypervisorType getHypervisor() {
+        return hypervisor;
+    }
+
+    public Integer getCpuSockets() {
+        return cpuSockets;
+    }
+
+    public Integer getCpuNumber() {
+        return cpuNumber;
+    }
+
+    public Long getCpuSpeed() {
+        return cpuSpeed;
+    }
+
+    public String getCpuUsed() {
+        return cpuUsed;
+    }
+
+    public Long getAverageLoad() {
+        return averageLoad;
+    }
+
+    public Long getNetworkKbsRead() {
+        return networkKbsRead;
+    }
+
+    public Long getNetworkKbsWrite() {
+        return networkKbsWrite;
+    }
+
+    public Long getMemoryTotal() {
+        return memoryTotal;
+    }
+
+    public Long getMemoryAllocated() {
+        return memoryAllocated;
+    }
+
+    public Long getMemoryUsed() {
+        return memoryUsed;
+    }
+
+    public List<GpuResponse> getGpuGroup() {
+        return gpuGroup;
+    }
+
+    public Long getDiskSizeTotal() {
+        return diskSizeTotal;
+    }
+
+    public Long getDiskSizeAllocated() {
+        return diskSizeAllocated;
+    }
+
+    public String getCapabilities() {
+        return capabilities;
+    }
+
+    public Date getLastPinged() {
+        return lastPinged;
+    }
+
+    public Long getManagementServerId() {
+        return managementServerId;
+    }
+
+    public String getClusterId() {
+        return clusterId;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public String getClusterType() {
+        return clusterType;
+    }
+
+    public Boolean getLocalStorageActive() {
+        return localStorageActive;
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+
+    public Date getRemoved() {
+        return removed;
+    }
+
+    public String getEvents() {
+        return events;
+    }
+
+    public Boolean getHasEnoughCapacity() {
+        return hasEnoughCapacity;
+    }
+
+    public Boolean getSuitableForMigration() {
+        return suitableForMigration;
+    }
+
+    public String getHypervisorVersion() {
+        return hypervisorVersion;
+    }
+
+    public Boolean getHaHost() {
+        return haHost;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/NicResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java
index 7335836..7689123 100644
--- a/api/src/org/apache/cloudstack/api/response/NicResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java
@@ -16,15 +16,14 @@
 // under the License.
 package org.apache.cloudstack.api.response;
 
-import java.util.List;
-
+import com.cloud.serializer.Param;
+import com.cloud.vm.Nic;
+import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.EntityReference;
 
-import com.cloud.serializer.Param;
-import com.cloud.vm.Nic;
-import com.google.gson.annotations.SerializedName;
+import java.util.List;
 
 @SuppressWarnings("unused")
 @EntityReference(value = Nic.class)
@@ -221,4 +220,79 @@ public class NicResponse extends BaseResponse {
         this.nsxLogicalSwitchPort = nsxLogicalSwitchPort;
     }
 
+    public String getNetworkId() {
+        return networkId;
+    }
+
+    public String getNetworkName() {
+        return networkName;
+    }
+
+    public String getNetmask() {
+        return netmask;
+    }
+
+    public String getGateway() {
+        return gateway;
+    }
+
+    public String getIsolationUri() {
+        return isolationUri;
+    }
+
+    public String getBroadcastUri() {
+        return broadcastUri;
+    }
+
+    public String getTrafficType() {
+        return trafficType;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public Boolean getDefault() {
+        return isDefault;
+    }
+
+    public String getMacAddress() {
+        return macAddress;
+    }
+
+    public String getIpaddress() {
+        return ipaddress;
+    }
+
+    public String getIp6Gateway() {
+        return ip6Gateway;
+    }
+
+    public String getIp6Cidr() {
+        return ip6Cidr;
+    }
+
+    public String getIp6Address() {
+        return ip6Address;
+    }
+
+    public List<NicSecondaryIpResponse> getSecondaryIps() {
+        return secondaryIps;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public String getVmId() {
+        return vmId;
+    }
+
+    public String getNsxLogicalSwitch() {
+        return nsxLogicalSwitch;
+    }
+
+    public String getNsxLogicalSwitchPort() {
+        return nsxLogicalSwitchPort;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
index 3571866..b7f7d0b 100644
--- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
@@ -309,4 +309,12 @@ public class StoragePoolResponse extends BaseResponse {
     public void setOverProvisionFactor(String overProvisionFactor) {
         this.overProvisionFactor = overProvisionFactor;
     }
+
+    public String getOverProvisionFactor() {
+        return overProvisionFactor;
+    }
+
+    public Boolean getSuitableForMigration() {
+        return suitableForMigration;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/UserVmResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java
index b681d4f..2ff1eaa 100644
--- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java
@@ -813,4 +813,28 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
     public void setOsTypeId(Long osTypeId) {
         this.osTypeId = osTypeId;
     }
+
+    public Set<Long> getTagIds() {
+        return tagIds;
+    }
+
+    public void setTagIds(Set<Long> tagIds) {
+        this.tagIds = tagIds;
+    }
+
+    public Map getDetails() {
+        return details;
+    }
+
+    public Boolean getDynamicallyScalable() {
+        return isDynamicallyScalable;
+    }
+
+    public void setDynamicallyScalable(Boolean dynamicallyScalable) {
+        isDynamicallyScalable = dynamicallyScalable;
+    }
+
+    public Long getOsTypeId() {
+        return osTypeId;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
index a934563..e25adf6 100644
--- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
@@ -16,18 +16,17 @@
 // under the License.
 package org.apache.cloudstack.api.response;
 
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
+import com.cloud.serializer.Param;
+import com.cloud.storage.Volume;
+import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseResponseWithTagInformation;
 import org.apache.cloudstack.api.EntityReference;
 
-import com.cloud.serializer.Param;
-import com.cloud.storage.Volume;
-import com.google.gson.annotations.SerializedName;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
 @EntityReference(value = Volume.class)
 @SuppressWarnings("unused")
@@ -514,4 +513,140 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
     public void setTags(Set<ResourceTagResponse> tags) {
         this.tags = tags;
     }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getZoneId() {
+        return zoneId;
+    }
+
+    public String getZoneName() {
+        return zoneName;
+    }
+
+    public String getVolumeType() {
+        return volumeType;
+    }
+
+    public Long getDeviceId() {
+        return deviceId;
+    }
+
+    public String getVirtualMachineId() {
+        return virtualMachineId;
+    }
+
+    public String getVirtualMachineName() {
+        return virtualMachineName;
+    }
+
+    public String getVirtualMachineDisplayName() {
+        return virtualMachineDisplayName;
+    }
+
+    public String getVirtualMachineState() {
+        return virtualMachineState;
+    }
+
+    public String getProvisioningType() {
+        return provisioningType;
+    }
+
+    public Long getSize() {
+        return size;
+    }
+
+    public Long getMinIops() {
+        return minIops;
+    }
+
+    public Long getMaxIops() {
+        return maxIops;
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public String getProjectId() {
+        return projectId;
+    }
+
+    public String getProjectName() {
+        return projectName;
+    }
+
+    public String getDomainId() {
+        return domainId;
+    }
+
+    public String getDomainName() {
+        return domainName;
+    }
+
+    public String getStorageType() {
+        return storageType;
+    }
+
+    public String getHypervisor() {
+        return hypervisor;
+    }
+
+    public String getDiskOfferingId() {
+        return diskOfferingId;
+    }
+
+    public String getDiskOfferingName() {
+        return diskOfferingName;
+    }
+
+    public String getDiskOfferingDisplayText() {
+        return diskOfferingDisplayText;
+    }
+
+    public String getStoragePoolName() {
+        return storagePoolName;
+    }
+
+    public String getSnapshotId() {
+        return snapshotId;
+    }
+
+    public Date getAttached() {
+        return attached;
+    }
+
+    public String getServiceOfferingId() {
+        return serviceOfferingId;
+    }
+
+    public String getServiceOfferingName() {
+        return serviceOfferingName;
+    }
+
+    public String getServiceOfferingDisplayText() {
+        return serviceOfferingDisplayText;
+    }
+
+    public Boolean getExtractable() {
+        return extractable;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public Boolean getDisplayVolume() {
+        return displayVolume;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/api/src/org/apache/cloudstack/api/response/ZoneResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java
index 4266077..61bab02 100644
--- a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java
@@ -239,4 +239,92 @@ public class ZoneResponse extends BaseResponse {
         }
         this.resourceDetails = new HashMap<>(details);
     }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getDns1() {
+        return dns1;
+    }
+
+    public String getDns2() {
+        return dns2;
+    }
+
+    public String getInternalDns1() {
+        return internalDns1;
+    }
+
+    public String getInternalDns2() {
+        return internalDns2;
+    }
+
+    public String getGuestCidrAddress() {
+        return guestCidrAddress;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public String getDisplayText() {
+        return displayText;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public String getDomainId() {
+        return domainId;
+    }
+
+    public String getDomainName() {
+        return domainName;
+    }
+
+    public String getNetworkType() {
+        return networkType;
+    }
+
+    public boolean isSecurityGroupsEnabled() {
+        return securityGroupsEnabled;
+    }
+
+    public String getAllocationState() {
+        return allocationState;
+    }
+
+    public String getZoneToken() {
+        return zoneToken;
+    }
+
+    public String getDhcpProvider() {
+        return dhcpProvider;
+    }
+
+    public List<CapacityResponse> getCapacitites() {
+        return capacitites;
+    }
+
+    public boolean isLocalStorageEnabled() {
+        return localStorageEnabled;
+    }
+
+    public Set<ResourceTagResponse> getTags() {
+        return tags;
+    }
+
+    public Map<String, String> getResourceDetails() {
+        return resourceDetails;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index d5ddd65..1f246ff 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -103,6 +103,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-plugin-metrics</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
       <artifactId>cloud-plugin-network-nvp</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/engine/schema/src/com/cloud/dc/dao/ClusterDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java
index 06bc5a3..de8d604 100644
--- a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java
+++ b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java
@@ -16,13 +16,13 @@
 // under the License.
 package com.cloud.dc.dao;
 
-import java.util.List;
-import java.util.Map;
-
 import com.cloud.dc.ClusterVO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.utils.db.GenericDao;
 
+import java.util.List;
+import java.util.Map;
+
 public interface ClusterDao extends GenericDao<ClusterVO, Long> {
     List<ClusterVO> listByPodId(long podId);
 
@@ -44,7 +44,7 @@ public interface ClusterDao extends GenericDao<ClusterVO, Long> {
 
     List<ClusterVO> listClustersByDcId(long zoneId);
 
-    List<Long> listAllCusters(long zoneId);
+    List<Long> listAllClusters(Long zoneId);
 
     boolean getSupportsResigning(long clusterId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java
index 0c5bd6f..b1fce61 100644
--- a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java
+++ b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java
@@ -16,18 +16,6 @@
 // under the License.
 package com.cloud.dc.dao;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Inject;
-
-import org.springframework.stereotype.Component;
-
 import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.ClusterDetailsVO;
 import com.cloud.dc.ClusterVO;
@@ -43,6 +31,16 @@ import com.cloud.utils.db.SearchCriteria.Func;
 import com.cloud.utils.db.SearchCriteria.Op;
 import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.exception.CloudRuntimeException;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 @Component
 public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements ClusterDao {
@@ -259,9 +257,11 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
     }
 
     @Override
-    public List<Long> listAllCusters(long zoneId) {
+    public List<Long> listAllClusters(Long zoneId) {
         SearchCriteria<Long> sc = ClusterIdSearch.create();
-        sc.setParameters("dataCenterId", zoneId);
+        if (zoneId != null) {
+            sc.setParameters("dataCenterId", zoneId);
+        }
         return customSearch(sc, null);
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/engine/schema/src/com/cloud/dc/dao/HostPodDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/dc/dao/HostPodDao.java b/engine/schema/src/com/cloud/dc/dao/HostPodDao.java
index 39c8a49..1a000d8 100644
--- a/engine/schema/src/com/cloud/dc/dao/HostPodDao.java
+++ b/engine/schema/src/com/cloud/dc/dao/HostPodDao.java
@@ -31,5 +31,5 @@ public interface HostPodDao extends GenericDao<HostPodVO, Long> {
 
     public List<Long> listDisabledPods(long zoneId);
 
-    public List<Long> listAllPods(long zoneId);
+    public List<Long> listAllPods(Long zoneId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java
index 8d689e3..1c83b3a 100644
--- a/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java
+++ b/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java
@@ -130,9 +130,11 @@ public class HostPodDaoImpl extends GenericDaoBase<HostPodVO, Long> implements H
     }
 
     @Override
-    public List<Long> listAllPods(long zoneId) {
+    public List<Long> listAllPods(Long zoneId) {
         SearchCriteria<Long> sc = PodIdSearch.create();
-        sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
+        if (zoneId != null) {
+            sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
+        }
         return customSearch(sc, null);
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/metrics/pom.xml b/plugins/metrics/pom.xml
new file mode 100644
index 0000000..946b235
--- /dev/null
+++ b/plugins/metrics/pom.xml
@@ -0,0 +1,55 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+  http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloud-plugin-metrics</artifactId>
+  <name>Apache CloudStack Plugin - Metrics</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-plugins</artifactId>
+    <version>4.9.3.0-SNAPSHOT</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>-Xmx1024m</argLine>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/resources/META-INF/cloudstack/metrics/module.properties
----------------------------------------------------------------------
diff --git a/plugins/metrics/resources/META-INF/cloudstack/metrics/module.properties b/plugins/metrics/resources/META-INF/cloudstack/metrics/module.properties
new file mode 100644
index 0000000..149b83a
--- /dev/null
+++ b/plugins/metrics/resources/META-INF/cloudstack/metrics/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=metrics
+parent=api

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml
----------------------------------------------------------------------
diff --git a/plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml b/plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml
new file mode 100644
index 0000000..6584641
--- /dev/null
+++ b/plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml
@@ -0,0 +1,27 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd"
+>
+
+    <bean id="metricsService" class="org.apache.cloudstack.metrics.MetricsServiceImpl" >
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListClustersMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListClustersMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListClustersMetricsCmd.java
new file mode 100644
index 0000000..ef259e1
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListClustersMetricsCmd.java
@@ -0,0 +1,51 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.ClusterMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListClustersMetricsCmd.APINAME, description = "Lists clusters metrics", responseObject = ClusterMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin})
+public class ListClustersMetricsCmd extends ListClustersCmd {
+    public static final String APINAME = "listClustersMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        final List<ClusterMetricsResponse> metricsResponses = metricsService.listClusterMetrics(getClusterResponses());
+        ListResponse<ClusterMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListHostsMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListHostsMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListHostsMetricsCmd.java
new file mode 100644
index 0000000..9010063
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListHostsMetricsCmd.java
@@ -0,0 +1,54 @@
+// 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 org.apache.cloudstack.api;
+
+
+import com.cloud.host.Host;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.HostMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListHostsMetricsCmd.APINAME, description = "Lists hosts metrics", responseObject = HostMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin})
+public class ListHostsMetricsCmd extends ListHostsCmd {
+    public static final String APINAME = "listHostsMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        setType(Host.Type.Routing.toString());
+        final List<HostMetricsResponse> metricsResponses = metricsService.listHostMetrics(getHostResponses().getResponses());
+        ListResponse<HostMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListInfrastructureCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListInfrastructureCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListInfrastructureCmd.java
new file mode 100644
index 0000000..4ea24c3
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListInfrastructureCmd.java
@@ -0,0 +1,52 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.InfrastructureResponse;
+
+import javax.inject.Inject;
+
+@APICommand(name = ListInfrastructureCmd.APINAME, description = "Lists infrastructure", responseObject = InfrastructureResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin})
+public class ListInfrastructureCmd extends BaseCmd {
+    public static final String APINAME = "listInfrastructure";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccountId();
+    }
+
+    @Override
+    public void execute() {
+        final InfrastructureResponse response = metricsService.listInfrastructure();
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListStoragePoolsMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListStoragePoolsMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListStoragePoolsMetricsCmd.java
new file mode 100644
index 0000000..4206568
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListStoragePoolsMetricsCmd.java
@@ -0,0 +1,52 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.StoragePoolMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListStoragePoolsMetricsCmd.APINAME, description = "Lists storage pool metrics", responseObject = StoragePoolMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin})
+public class ListStoragePoolsMetricsCmd extends ListStoragePoolsCmd {
+    public static final String APINAME = "listStoragePoolsMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        final List<StoragePoolMetricsResponse> metricsResponses = metricsService.listStoragePoolMetrics(_queryService.searchForStoragePools(this).getResponses());
+        ListResponse<StoragePoolMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListVMsMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListVMsMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListVMsMetricsCmd.java
new file mode 100644
index 0000000..2321f51
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListVMsMetricsCmd.java
@@ -0,0 +1,51 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.vm.ListVMsCmdByAdmin;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.VmMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListVMsMetricsCmd.APINAME, description = "Lists VM metrics", responseObject = VmMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin,  RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListVMsMetricsCmd extends ListVMsCmdByAdmin {
+    public static final String APINAME = "listVirtualMachinesMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        final List<VmMetricsResponse> metricsResponses = metricsService.listVmMetrics(_queryService.searchForUserVMs(this).getResponses());
+        ListResponse<VmMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListVolumesMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListVolumesMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListVolumesMetricsCmd.java
new file mode 100644
index 0000000..54ac922
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListVolumesMetricsCmd.java
@@ -0,0 +1,51 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.admin.volume.ListVolumesCmdByAdmin;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.VolumeMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListVolumesMetricsCmd.APINAME, description = "Lists volume metrics", responseObject = VolumeMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin,  RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListVolumesMetricsCmd extends ListVolumesCmdByAdmin {
+    public static final String APINAME = "listVolumesMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute()  {
+        final List<VolumeMetricsResponse> metricsResponses = metricsService.listVolumeMetrics(_queryService.searchForVolumes(this).getResponses());
+        ListResponse<VolumeMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/api/ListZonesMetricsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/api/ListZonesMetricsCmd.java b/plugins/metrics/src/org/apache/cloudstack/api/ListZonesMetricsCmd.java
new file mode 100644
index 0000000..1a51a5f
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/api/ListZonesMetricsCmd.java
@@ -0,0 +1,52 @@
+// 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 org.apache.cloudstack.api;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.metrics.MetricsService;
+import org.apache.cloudstack.response.ZoneMetricsResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = ListZonesMetricsCmd.APINAME, description = "Lists zone metrics", responseObject = ZoneMetricsResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full,
+        since = "4.9.3", authorized = {RoleType.Admin})
+public class ListZonesMetricsCmd extends ListZonesCmd {
+    public static final String APINAME = "listZonesMetrics";
+
+    @Inject
+    private MetricsService metricsService;
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public void execute() {
+        final List<ZoneMetricsResponse> metricsResponses = metricsService.listZoneMetrics(_queryService.listDataCenters(this).getResponses());
+        ListResponse<ZoneMetricsResponse> response = new ListResponse<>();
+        response.setResponses(metricsResponses, metricsResponses.size());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsService.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsService.java b/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsService.java
new file mode 100644
index 0000000..deb1da8
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsService.java
@@ -0,0 +1,46 @@
+// 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 org.apache.cloudstack.metrics;
+
+import com.cloud.utils.component.PluggableService;
+import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VolumeResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.response.ClusterMetricsResponse;
+import org.apache.cloudstack.response.HostMetricsResponse;
+import org.apache.cloudstack.response.InfrastructureResponse;
+import org.apache.cloudstack.response.StoragePoolMetricsResponse;
+import org.apache.cloudstack.response.VmMetricsResponse;
+import org.apache.cloudstack.response.VolumeMetricsResponse;
+import org.apache.cloudstack.response.ZoneMetricsResponse;
+
+import java.util.List;
+
+public interface MetricsService extends PluggableService {
+    InfrastructureResponse listInfrastructure();
+
+    List<VolumeMetricsResponse> listVolumeMetrics(List<VolumeResponse> volumeResponses);
+    List<VmMetricsResponse> listVmMetrics(List<UserVmResponse> vmResponses);
+    List<StoragePoolMetricsResponse> listStoragePoolMetrics(List<StoragePoolResponse> poolResponses);
+    List<HostMetricsResponse> listHostMetrics(List<HostResponse> poolResponses);
+    List<ClusterMetricsResponse> listClusterMetrics(List<ClusterResponse> poolResponses);
+    List<ZoneMetricsResponse> listZoneMetrics(List<ZoneResponse> poolResponses);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40225350/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsServiceImpl.java
----------------------------------------------------------------------
diff --git a/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsServiceImpl.java
new file mode 100644
index 0000000..5cab7bc
--- /dev/null
+++ b/plugins/metrics/src/org/apache/cloudstack/metrics/MetricsServiceImpl.java
@@ -0,0 +1,563 @@
+// 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 org.apache.cloudstack.metrics;
+
+import com.cloud.alert.AlertManager;
+import com.cloud.api.ApiDBUtils;
+import com.cloud.api.query.dao.HostJoinDao;
+import com.cloud.api.query.vo.HostJoinVO;
+import com.cloud.capacity.Capacity;
+import com.cloud.capacity.CapacityManager;
+import com.cloud.capacity.dao.CapacityDao;
+import com.cloud.capacity.dao.CapacityDaoImpl;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.deploy.DeploymentClusterPlanner;
+import com.cloud.host.Host;
+import com.cloud.host.HostStats;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.org.Cluster;
+import com.cloud.org.Grouping;
+import com.cloud.org.Managed;
+import com.cloud.utils.component.ComponentLifecycleBase;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.DomainRouterDao;
+import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ListClustersMetricsCmd;
+import org.apache.cloudstack.api.ListHostsMetricsCmd;
+import org.apache.cloudstack.api.ListInfrastructureCmd;
+import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd;
+import org.apache.cloudstack.api.ListVMsMetricsCmd;
+import org.apache.cloudstack.api.ListVolumesMetricsCmd;
+import org.apache.cloudstack.api.ListZonesMetricsCmd;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VolumeResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.response.ClusterMetricsResponse;
+import org.apache.cloudstack.response.HostMetricsResponse;
+import org.apache.cloudstack.response.InfrastructureResponse;
+import org.apache.cloudstack.response.StoragePoolMetricsResponse;
+import org.apache.cloudstack.response.VmMetricsResponse;
+import org.apache.cloudstack.response.VolumeMetricsResponse;
+import org.apache.cloudstack.response.ZoneMetricsResponse;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.commons.beanutils.BeanUtils;
+
+import javax.inject.Inject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MetricsServiceImpl extends ComponentLifecycleBase implements MetricsService {
+
+    @Inject
+    private DataCenterDao dataCenterDao;
+    @Inject
+    private HostPodDao podDao;
+    @Inject
+    private ClusterDao clusterDao;
+    @Inject
+    private HostDao hostDao;
+    @Inject
+    private HostJoinDao hostJoinDao;
+    @Inject
+    private PrimaryDataStoreDao storagePoolDao;
+    @Inject
+    private ImageStoreDao imageStoreDao;
+    @Inject
+    private VMInstanceDao vmInstanceDao;
+    @Inject
+    private DomainRouterDao domainRouterDao;
+    @Inject
+    private CapacityDao capacityDao;
+
+    protected MetricsServiceImpl() {
+        super();
+    }
+
+    private Double findRatioValue(final String value) {
+        if (value != null) {
+            return Double.valueOf(value);
+        }
+        return 1.0;
+    }
+
+    private void updateHostMetrics(final Metrics metrics, final HostJoinVO host) {
+        metrics.incrTotalHosts();
+        metrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity());
+        metrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity());
+        final HostStats hostStats = ApiDBUtils.getHostStatistics(host.getId());
+        if (hostStats != null) {
+            metrics.addCpuUsedPercentage(hostStats.getCpuUtilization());
+            metrics.addMemoryUsed((long) hostStats.getUsedMemory());
+            metrics.setMaximumCpuUsage(hostStats.getCpuUtilization());
+            metrics.setMaximumMemoryUsage((long) hostStats.getUsedMemory());
+        }
+    }
+
+    @Override
+    public InfrastructureResponse listInfrastructure() {
+        final InfrastructureResponse response = new InfrastructureResponse();
+        response.setZones(dataCenterDao.listAllZones().size());
+        response.setPods(podDao.listAllPods(null).size());
+        response.setClusters(clusterDao.listAllClusters(null).size());
+        response.setHosts(hostDao.listByType(Host.Type.Routing).size());
+        response.setStoragePools(storagePoolDao.listAll().size());
+        response.setImageStores(imageStoreDao.listImageStores().size());
+        response.setSystemvms(vmInstanceDao.listByTypes(VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm).size());
+        response.setRouters(domainRouterDao.listAll().size());
+        int cpuSockets = 0;
+        for (final Host host : hostDao.listByType(Host.Type.Routing)) {
+            if (host.getCpuSockets() != null) {
+                cpuSockets += host.getCpuSockets();
+            }
+        }
+        response.setCpuSockets(cpuSockets);
+        return response;
+    }
+
+    @Override
+    public List<VolumeMetricsResponse> listVolumeMetrics(List<VolumeResponse> volumeResponses) {
+        final List<VolumeMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final VolumeResponse volumeResponse: volumeResponses) {
+            VolumeMetricsResponse metricsResponse = new VolumeMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, volumeResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate volume metrics response");
+            }
+
+            metricsResponse.setDiskSizeGB(volumeResponse.getSize());
+            metricsResponse.setStorageType(volumeResponse.getStorageType(), volumeResponse.getVolumeType());
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    @Override
+    public List<VmMetricsResponse> listVmMetrics(List<UserVmResponse> vmResponses) {
+        final List<VmMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final UserVmResponse vmResponse: vmResponses) {
+            VmMetricsResponse metricsResponse = new VmMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, vmResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate vm metrics response");
+            }
+
+            metricsResponse.setIpAddress(vmResponse.getNics());
+            metricsResponse.setCpuTotal(vmResponse.getCpuNumber(), vmResponse.getCpuSpeed());
+            metricsResponse.setMemTotal(vmResponse.getMemory());
+            metricsResponse.setNetworkRead(vmResponse.getNetworkKbsRead());
+            metricsResponse.setNetworkWrite(vmResponse.getNetworkKbsWrite());
+            metricsResponse.setDiskRead(vmResponse.getDiskKbsRead());
+            metricsResponse.setDiskWrite(vmResponse.getDiskKbsWrite());
+            metricsResponse.setDiskIopsTotal(vmResponse.getDiskIORead(), vmResponse.getDiskIOWrite());
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    @Override
+    public List<StoragePoolMetricsResponse> listStoragePoolMetrics(List<StoragePoolResponse> poolResponses) {
+        final List<StoragePoolMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final StoragePoolResponse poolResponse: poolResponses) {
+            StoragePoolMetricsResponse metricsResponse = new StoragePoolMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, poolResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate storagepool metrics response");
+            }
+
+            Long poolClusterId = null;
+            final Cluster cluster = clusterDao.findByUuid(poolResponse.getClusterId());
+            if (cluster != null) {
+                poolClusterId = cluster.getId();
+            }
+            final Double storageThreshold = AlertManager.StorageCapacityThreshold.valueIn(poolClusterId);
+            final Double storageDisableThreshold = CapacityManager.StorageCapacityDisableThreshold.valueIn(poolClusterId);
+
+            metricsResponse.setDiskSizeUsedGB(poolResponse.getDiskSizeUsed());
+            metricsResponse.setDiskSizeTotalGB(poolResponse.getDiskSizeTotal(), poolResponse.getOverProvisionFactor());
+            metricsResponse.setDiskSizeAllocatedGB(poolResponse.getDiskSizeAllocated());
+            metricsResponse.setDiskSizeUnallocatedGB(poolResponse.getDiskSizeTotal(), poolResponse.getDiskSizeAllocated(), poolResponse.getOverProvisionFactor());
+            metricsResponse.setStorageUsedThreshold(poolResponse.getDiskSizeTotal(), poolResponse.getDiskSizeUsed(), poolResponse.getOverProvisionFactor(), storageThreshold);
+            metricsResponse.setStorageUsedDisableThreshold(poolResponse.getDiskSizeTotal(), poolResponse.getDiskSizeUsed(), poolResponse.getOverProvisionFactor(), storageDisableThreshold);
+            metricsResponse.setStorageAllocatedThreshold(poolResponse.getDiskSizeTotal(), poolResponse.getDiskSizeAllocated(), poolResponse.getOverProvisionFactor(), storageThreshold);
+            metricsResponse.setStorageAllocatedDisableThreshold(poolResponse.getDiskSizeTotal(), poolResponse.getDiskSizeUsed(), poolResponse.getOverProvisionFactor(), storageDisableThreshold);
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    @Override
+    public List<HostMetricsResponse> listHostMetrics(List<HostResponse> hostResponses) {
+        final List<HostMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final HostResponse hostResponse: hostResponses) {
+            HostMetricsResponse metricsResponse = new HostMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, hostResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate host metrics response");
+            }
+
+            final Host host = hostDao.findByUuid(hostResponse.getId());
+            if (host == null) {
+                continue;
+            }
+            final Long hostId = host.getId();
+            final Long clusterId = host.getClusterId();
+
+            // Thresholds
+            final Double cpuThreshold = AlertManager.CPUCapacityThreshold.valueIn(clusterId);
+            final Double memoryThreshold = AlertManager.MemoryCapacityThreshold.valueIn(clusterId);
+            final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
+            final Float memoryDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
+            // Over commit ratios
+            final Double cpuOvercommitRatio = findRatioValue(ApiDBUtils.findClusterDetails(clusterId, "cpuOvercommitRatio"));
+            final Double memoryOvercommitRatio = findRatioValue(ApiDBUtils.findClusterDetails(clusterId, "memoryOvercommitRatio"));
+
+            Long upInstances = 0L;
+            Long totalInstances = 0L;
+            for (final VMInstanceVO instance: vmInstanceDao.listByHostId(hostId)) {
+                if (instance == null) {
+                    continue;
+                }
+                if (instance.getType() == VirtualMachine.Type.User) {
+                    totalInstances++;
+                    if (instance.getState() == VirtualMachine.State.Running) {
+                        upInstances++;
+                    }
+                }
+            }
+            metricsResponse.setPowerState(hostResponse.getOutOfBandManagementResponse().getPowerState());
+            metricsResponse.setInstances(upInstances, totalInstances);
+            metricsResponse.setCpuTotal(hostResponse.getCpuNumber(), hostResponse.getCpuSpeed(), cpuOvercommitRatio);
+            metricsResponse.setCpuUsed(hostResponse.getCpuUsed(), hostResponse.getCpuNumber(), hostResponse.getCpuSpeed());
+            metricsResponse.setCpuAllocated(hostResponse.getCpuAllocated(), hostResponse.getCpuNumber(), hostResponse.getCpuSpeed());
+            metricsResponse.setMemTotal(hostResponse.getMemoryTotal(), memoryOvercommitRatio);
+            metricsResponse.setMemAllocated(hostResponse.getMemoryAllocated());
+            metricsResponse.setMemUsed(hostResponse.getMemoryUsed());
+            metricsResponse.setNetworkRead(hostResponse.getNetworkKbsRead());
+            metricsResponse.setNetworkWrite(hostResponse.getNetworkKbsWrite());
+            // CPU thresholds
+            metricsResponse.setCpuUsageThreshold(hostResponse.getCpuUsed(), cpuThreshold);
+            metricsResponse.setCpuUsageDisableThreshold(hostResponse.getCpuUsed(), cpuDisableThreshold);
+            metricsResponse.setCpuAllocatedThreshold(hostResponse.getCpuAllocated(), cpuOvercommitRatio, cpuThreshold);
+            metricsResponse.setCpuAllocatedDisableThreshold(hostResponse.getCpuAllocated(), cpuOvercommitRatio, cpuDisableThreshold);
+            // Memory thresholds
+            metricsResponse.setMemoryUsageThreshold(hostResponse.getMemoryUsed(), hostResponse.getMemoryTotal(), memoryThreshold);
+            metricsResponse.setMemoryUsageDisableThreshold(hostResponse.getMemoryUsed(), hostResponse.getMemoryTotal(), memoryDisableThreshold);
+            metricsResponse.setMemoryAllocatedThreshold(hostResponse.getMemoryAllocated(), hostResponse.getMemoryTotal(), memoryOvercommitRatio, memoryThreshold);
+            metricsResponse.setMemoryAllocatedDisableThreshold(hostResponse.getMemoryAllocated(), hostResponse.getMemoryTotal(), memoryOvercommitRatio, memoryDisableThreshold);
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    private CapacityDaoImpl.SummedCapacity getCapacity(final int capacityType, final Long zoneId, final Long clusterId) {
+        final List<CapacityDaoImpl.SummedCapacity> capacities = capacityDao.findCapacityBy(capacityType, zoneId, null, clusterId);
+        if (capacities == null || capacities.size() < 1) {
+            return null;
+        }
+        return capacities.get(0);
+    }
+
+    @Override
+    public List<ClusterMetricsResponse> listClusterMetrics(List<ClusterResponse> clusterResponses) {
+        final List<ClusterMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final ClusterResponse clusterResponse: clusterResponses) {
+            ClusterMetricsResponse metricsResponse = new ClusterMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, clusterResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate cluster metrics response");
+            }
+
+            final Cluster cluster = clusterDao.findByUuid(clusterResponse.getId());
+            if (cluster == null) {
+                continue;
+            }
+            final Long clusterId = cluster.getId();
+
+            // Thresholds
+            final Double cpuThreshold = AlertManager.CPUCapacityThreshold.valueIn(clusterId);
+            final Double memoryThreshold = AlertManager.MemoryCapacityThreshold.valueIn(clusterId);
+            final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
+            final Float memoryDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
+
+            final Double cpuOvercommitRatio = findRatioValue(ApiDBUtils.findClusterDetails(clusterId, "cpuOvercommitRatio"));
+            final Double memoryOvercommitRatio = findRatioValue(ApiDBUtils.findClusterDetails(clusterId, "memoryOvercommitRatio"));
+
+            // CPU and memory capacities
+            final CapacityDaoImpl.SummedCapacity cpuCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_CPU, null, clusterId);
+            final CapacityDaoImpl.SummedCapacity memoryCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_MEMORY, null, clusterId);
+            final Metrics metrics = new Metrics(cpuCapacity, memoryCapacity);
+
+            for (final HostJoinVO host: hostJoinDao.findByClusterId(clusterId, Host.Type.Routing)) {
+                if (host.getStatus() == Status.Up) {
+                    metrics.incrUpResources();
+                }
+                metrics.incrTotalResources();
+                updateHostMetrics(metrics, host);
+            }
+
+            metricsResponse.setState(clusterResponse.getAllocationState(), clusterResponse.getManagedState());
+            metricsResponse.setResources(metrics.getUpResources(), metrics.getTotalResources());
+            // CPU
+            metricsResponse.setCpuTotal(metrics.getTotalCpu());
+            metricsResponse.setCpuAllocated(metrics.getCpuAllocated(), metrics.getTotalCpu());
+            if (metrics.getCpuUsedPercentage() > 0L) {
+                metricsResponse.setCpuUsed(metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
+                metricsResponse.setCpuMaxDeviation(metrics.getMaximumCpuUsage(), metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
+            }
+            // Memory
+            metricsResponse.setMemTotal(metrics.getTotalMemory());
+            metricsResponse.setMemAllocated(metrics.getMemoryAllocated(), metrics.getTotalMemory());
+            if (metrics.getMemoryUsed() > 0L) {
+                metricsResponse.setMemUsed(metrics.getMemoryUsed(), metrics.getTotalMemory());
+                metricsResponse.setMemMaxDeviation(metrics.getMaximumMemoryUsage(), metrics.getMemoryUsed(), metrics.getTotalHosts());
+            }
+            // CPU thresholds
+            metricsResponse.setCpuUsageThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuThreshold);
+            metricsResponse.setCpuUsageDisableThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuDisableThreshold);
+            metricsResponse.setCpuAllocatedThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuOvercommitRatio, cpuThreshold);
+            metricsResponse.setCpuAllocatedDisableThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuOvercommitRatio, cpuDisableThreshold);
+            // Memory thresholds
+            metricsResponse.setMemoryUsageThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryThreshold);
+            metricsResponse.setMemoryUsageDisableThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryDisableThreshold);
+            metricsResponse.setMemoryAllocatedThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryOvercommitRatio, memoryThreshold);
+            metricsResponse.setMemoryAllocatedDisableThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryOvercommitRatio, memoryDisableThreshold);
+
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    @Override
+    public List<ZoneMetricsResponse> listZoneMetrics(List<ZoneResponse> zoneResponses) {
+        final List<ZoneMetricsResponse> metricsResponses = new ArrayList<>();
+        for (final ZoneResponse zoneResponse: zoneResponses) {
+            ZoneMetricsResponse metricsResponse = new ZoneMetricsResponse();
+
+            try {
+                BeanUtils.copyProperties(metricsResponse, zoneResponse);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate zone metrics response");
+            }
+
+            final DataCenter zone = dataCenterDao.findByUuid(zoneResponse.getId());
+            if (zone == null) {
+                continue;
+            }
+            final Long zoneId = zone.getId();
+
+            // Thresholds
+            final Double cpuThreshold = AlertManager.CPUCapacityThreshold.value();
+            final Double memoryThreshold = AlertManager.MemoryCapacityThreshold.value();
+            final Float cpuDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.value();
+            final Float memoryDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.value();
+
+            // CPU and memory capacities
+            final CapacityDaoImpl.SummedCapacity cpuCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_CPU, zoneId, null);
+            final CapacityDaoImpl.SummedCapacity memoryCapacity = getCapacity((int) Capacity.CAPACITY_TYPE_MEMORY, zoneId, null);
+            final Metrics metrics = new Metrics(cpuCapacity, memoryCapacity);
+
+            for (final Cluster cluster : clusterDao.listClustersByDcId(zoneId)) {
+                metrics.incrTotalResources();
+                if (cluster.getAllocationState() == Grouping.AllocationState.Enabled
+                        && cluster.getManagedState() == Managed.ManagedState.Managed) {
+                    metrics.incrUpResources();
+                }
+
+                for (final HostJoinVO host: hostJoinDao.findByClusterId(cluster.getId(), Host.Type.Routing)) {
+                    updateHostMetrics(metrics, host);
+                }
+            }
+
+            metricsResponse.setState(zoneResponse.getAllocationState());
+            metricsResponse.setResource(metrics.getUpResources(), metrics.getTotalResources());
+            // CPU
+            metricsResponse.setCpuTotal(metrics.getTotalCpu());
+            metricsResponse.setCpuAllocated(metrics.getCpuAllocated(), metrics.getTotalCpu());
+            if (metrics.getCpuUsedPercentage() > 0L) {
+                metricsResponse.setCpuUsed(metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
+                metricsResponse.setCpuMaxDeviation(metrics.getMaximumCpuUsage(), metrics.getCpuUsedPercentage(), metrics.getTotalHosts());
+            }
+            // Memory
+            metricsResponse.setMemTotal(metrics.getTotalMemory());
+            metricsResponse.setMemAllocated(metrics.getMemoryAllocated(), metrics.getTotalMemory());
+            if (metrics.getMemoryUsed() > 0L) {
+                metricsResponse.setMemUsed(metrics.getMemoryUsed(), metrics.getTotalMemory());
+                metricsResponse.setMemMaxDeviation(metrics.getMaximumMemoryUsage(), metrics.getMemoryUsed(), metrics.getTotalHosts());
+            }
+            // CPU thresholds
+            metricsResponse.setCpuUsageThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuThreshold);
+            metricsResponse.setCpuUsageDisableThreshold(metrics.getCpuUsedPercentage(), metrics.getTotalHosts(), cpuDisableThreshold);
+            metricsResponse.setCpuAllocatedThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuThreshold);
+            metricsResponse.setCpuAllocatedDisableThreshold(metrics.getCpuAllocated(), metrics.getTotalCpu(), cpuDisableThreshold);
+            // Memory thresholds
+            metricsResponse.setMemoryUsageThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryThreshold);
+            metricsResponse.setMemoryUsageDisableThreshold(metrics.getMemoryUsed(), metrics.getTotalMemory(), memoryDisableThreshold);
+            metricsResponse.setMemoryAllocatedThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryThreshold);
+            metricsResponse.setMemoryAllocatedDisableThreshold(metrics.getMemoryAllocated(), metrics.getTotalMemory(), memoryDisableThreshold);
+
+            metricsResponses.add(metricsResponse);
+        }
+        return metricsResponses;
+    }
+
+    @Override
+    public List<Class<?>> getCommands() {
+        List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        cmdList.add(ListInfrastructureCmd.class);
+        cmdList.add(ListVolumesMetricsCmd.class);
+        cmdList.add(ListVMsMetricsCmd.class);
+        cmdList.add(ListStoragePoolsMetricsCmd.class);
+        cmdList.add(ListHostsMetricsCmd.class);
+        cmdList.add(ListClustersMetricsCmd.class);
+        cmdList.add(ListZonesMetricsCmd.class);
+        return cmdList;
+    }
+
+    private class Metrics {
+        // CPU metrics
+        private Long totalCpu = 0L;
+        private Long cpuAllocated = 0L;
+        private Double cpuUsedPercentage = 0.0;
+        private Double maximumCpuUsage = 0.0;
+        // Memory metrics
+        private Long totalMemory = 0L;
+        private Long memoryUsed = 0L;
+        private Long memoryAllocated = 0L;
+        private Long maximumMemoryUsage = 0L;
+        // Counters
+        private Long totalHosts = 0L;
+        private Long totalResources = 0L;
+        private Long upResources = 0L;
+
+        public Metrics(final CapacityDaoImpl.SummedCapacity totalCpu, final CapacityDaoImpl.SummedCapacity totalMemory) {
+            if (totalCpu != null) {
+                this.totalCpu = totalCpu.getTotalCapacity();
+            }
+            if (totalMemory != null) {
+                this.totalMemory = totalMemory.getTotalCapacity();
+            }
+        }
+
+        public void addCpuAllocated(Long cpuAllocated) {
+            this.cpuAllocated += cpuAllocated;
+        }
+
+        public void addCpuUsedPercentage(Double cpuUsedPercentage) {
+            this.cpuUsedPercentage += cpuUsedPercentage;
+        }
+
+        public void setMaximumCpuUsage(Double maximumCpuUsage) {
+            if (this.maximumCpuUsage == null || (maximumCpuUsage != null && maximumCpuUsage > this.maximumCpuUsage)) {
+                this.maximumCpuUsage = maximumCpuUsage;
+            }
+        }
+
+        public void addMemoryUsed(Long memoryUsed) {
+            this.memoryUsed += memoryUsed;
+        }
+
+        public void addMemoryAllocated(Long memoryAllocated) {
+            this.memoryAllocated += memoryAllocated;
+        }
+
+        public void setMaximumMemoryUsage(Long maximumMemoryUsage) {
+            if (this.maximumMemoryUsage == null || (maximumMemoryUsage != null && maximumMemoryUsage > this.maximumMemoryUsage)) {
+                this.maximumMemoryUsage = maximumMemoryUsage;
+            }
+        }
+
+        public void incrTotalHosts() {
+            this.totalHosts++;
+        }
+
+        public void incrTotalResources() {
+            this.totalResources++;
+        }
+
+        public void incrUpResources() {
+            this.upResources++;
+        }
+
+        public Long getTotalCpu() {
+            return totalCpu;
+        }
+
+        public Long getCpuAllocated() {
+            return cpuAllocated;
+        }
+
+        public Double getCpuUsedPercentage() {
+            return cpuUsedPercentage;
+        }
+
+        public Double getMaximumCpuUsage() {
+            return maximumCpuUsage;
+        }
+
+        public Long getTotalMemory() {
+            return totalMemory;
+        }
+
+        public Long getMemoryUsed() {
+            return memoryUsed;
+        }
+
+        public Long getMemoryAllocated() {
+            return memoryAllocated;
+        }
+
+        public Long getMaximumMemoryUsage() {
+            return maximumMemoryUsage;
+        }
+
+        public Long getTotalHosts() {
+            return totalHosts;
+        }
+
+        public Long getTotalResources() {
+            return totalResources;
+        }
+
+        public Long getUpResources() {
+            return upResources;
+        }
+    }
+
+}