From 402253504e9520104caf9fbc1317042f2fd89474 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 16 Feb 2017 13:45:15 +0530 Subject: [PATCH] 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 --- .travis.yml | 1 + .../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 + .../api/response/UserVmResponse.java | 24 + .../api/response/VolumeResponse.java | 149 ++++- .../cloudstack/api/response/ZoneResponse.java | 88 +++ client/pom.xml | 5 + .../src/com/cloud/dc/dao/ClusterDao.java | 8 +- .../src/com/cloud/dc/dao/ClusterDaoImpl.java | 28 +- .../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 + .../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 ++ .../metrics/MetricsServiceImpl.java | 563 ++++++++++++++++ .../response/ClusterMetricsResponse.java | 211 ++++++ .../response/HostMetricsResponse.java | 204 ++++++ .../response/InfrastructureResponse.java | 101 +++ .../response/StoragePoolMetricsResponse.java | 105 +++ .../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(-) create mode 100644 plugins/metrics/pom.xml create mode 100644 plugins/metrics/resources/META-INF/cloudstack/metrics/module.properties create mode 100644 plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListClustersMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListHostsMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListInfrastructureCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListStoragePoolsMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListVMsMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListVolumesMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/api/ListZonesMetricsCmd.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/metrics/MetricsService.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/metrics/MetricsServiceImpl.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/ClusterMetricsResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/HostMetricsResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/InfrastructureResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/StoragePoolMetricsResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/VmMetricsResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/VolumeMetricsResponse.java create mode 100644 plugins/metrics/src/org/apache/cloudstack/response/ZoneMetricsResponse.java create mode 100644 test/integration/smoke/test_metrics_api.py diff --git a/.travis.yml b/.travis.yml index da81633bb17..b8fbf0af3d0 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 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 432ca921c4d..74ad764608c 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 getClusterResponses() { Pair, Integer> result = _mgr.searchForClusters(this); - ListResponse response = new ListResponse(); List clusterResponses = new ArrayList(); 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 clusterResponses = getClusterResponses(); + ListResponse response = new ListResponse(); + response.setResponses(clusterResponses, clusterResponses.size()); response.setResponseName(getCommandName()); this.setResponseObject(response); } 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 424fc05aed1..3391fdca1e3 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 response = null; + protected ListResponse getHostResponses() { + ListResponse response = new ListResponse<>(); if (getVirtualMachineId() == null) { response = _queryService.searchForServers(this); } else { Pair, Integer> result; Ternary, Integer>, List, Map> hostsForMigration = - _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal()); + _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal()); result = hostsForMigration.first(); List hostsWithCapacity = hostsForMigration.second(); - - response = new ListResponse(); List hostResponses = new ArrayList(); 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 response = getHostResponses(); response.setResponseName(getCommandName()); this.setResponseObject(response); } diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java index ab9c8c37674..90fe800a8bc 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 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; + } } diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java index 73358360a05..7689123cbaf 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 getSecondaryIps() { + return secondaryIps; + } + + public String getDeviceId() { + return deviceId; + } + + public String getVmId() { + return vmId; + } + + public String getNsxLogicalSwitch() { + return nsxLogicalSwitch; + } + + public String getNsxLogicalSwitchPort() { + return nsxLogicalSwitchPort; + } } diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java index 3571866fe74..b7f7d0b41ee 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; + } } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index b681d4f70df..2ff1eaa717b 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 getTagIds() { + return tagIds; + } + + public void setTagIds(Set 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; + } } diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index a934563e9fe..e25adf618d8 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 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; + } } diff --git a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java index 4266077e813..61bab02d321 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 getCapacitites() { + return capacitites; + } + + public boolean isLocalStorageEnabled() { + return localStorageEnabled; + } + + public Set getTags() { + return tags; + } + + public Map getResourceDetails() { + return resourceDetails; + } } diff --git a/client/pom.xml b/client/pom.xml index d5ddd65e925..1f246ffb0ec 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -101,6 +101,11 @@ cloud-plugin-user-authenticator-sha256salted ${project.version} + + org.apache.cloudstack + cloud-plugin-metrics + ${project.version} + org.apache.cloudstack cloud-plugin-network-nvp diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java index 06bc5a3afc6..de8d604fb4c 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 { List listByPodId(long podId); @@ -44,7 +44,7 @@ public interface ClusterDao extends GenericDao { List listClustersByDcId(long zoneId); - List listAllCusters(long zoneId); + List listAllClusters(Long zoneId); boolean getSupportsResigning(long clusterId); } diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java index 0c5bd6f4a79..b1fce6195ba 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 implements ClusterDao { @@ -259,9 +257,11 @@ public class ClusterDaoImpl extends GenericDaoBase implements C } @Override - public List listAllCusters(long zoneId) { + public List listAllClusters(Long zoneId) { SearchCriteria sc = ClusterIdSearch.create(); - sc.setParameters("dataCenterId", zoneId); + if (zoneId != null) { + sc.setParameters("dataCenterId", zoneId); + } return customSearch(sc, null); } diff --git a/engine/schema/src/com/cloud/dc/dao/HostPodDao.java b/engine/schema/src/com/cloud/dc/dao/HostPodDao.java index 39c8a499192..1a000d8830c 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 { public List listDisabledPods(long zoneId); - public List listAllPods(long zoneId); + public List listAllPods(Long zoneId); } diff --git a/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/HostPodDaoImpl.java index 8d689e3a4a8..1c83b3a4a78 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 implements H } @Override - public List listAllPods(long zoneId) { + public List listAllPods(Long zoneId) { SearchCriteria sc = PodIdSearch.create(); - sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); + if (zoneId != null) { + sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); + } return customSearch(sc, null); } } diff --git a/plugins/metrics/pom.xml b/plugins/metrics/pom.xml new file mode 100644 index 00000000000..946b235dcd4 --- /dev/null +++ b/plugins/metrics/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + cloud-plugin-metrics + Apache CloudStack Plugin - Metrics + + org.apache.cloudstack + cloudstack-plugins + 4.9.3.0-SNAPSHOT + ../pom.xml + + + + org.apache.cloudstack + cloud-api + ${project.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -Xmx1024m + + + + + 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 00000000000..149b83afde1 --- /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 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 00000000000..65846417e11 --- /dev/null +++ b/plugins/metrics/resources/META-INF/cloudstack/metrics/spring-metrics-context.xml @@ -0,0 +1,27 @@ + + + + + + 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 00000000000..ef259e19a73 --- /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 metricsResponses = metricsService.listClusterMetrics(getClusterResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } +} 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 00000000000..90100631d6b --- /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 metricsResponses = metricsService.listHostMetrics(getHostResponses().getResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } +} 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 00000000000..4ea24c3f66b --- /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); + } +} 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 00000000000..420656800fa --- /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 metricsResponses = metricsService.listStoragePoolMetrics(_queryService.searchForStoragePools(this).getResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + +} 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 00000000000..2321f519472 --- /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 metricsResponses = metricsService.listVmMetrics(_queryService.searchForUserVMs(this).getResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } +} 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 00000000000..54ac92226ae --- /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 metricsResponses = metricsService.listVolumeMetrics(_queryService.searchForVolumes(this).getResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } +} 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 00000000000..1a51a5fbe00 --- /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 metricsResponses = metricsService.listZoneMetrics(_queryService.listDataCenters(this).getResponses()); + ListResponse response = new ListResponse<>(); + response.setResponses(metricsResponses, metricsResponses.size()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + +} 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 00000000000..deb1da89c9f --- /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 listVolumeMetrics(List volumeResponses); + List listVmMetrics(List vmResponses); + List listStoragePoolMetrics(List poolResponses); + List listHostMetrics(List poolResponses); + List listClusterMetrics(List poolResponses); + List listZoneMetrics(List poolResponses); +} 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 00000000000..5cab7bcf19c --- /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 listVolumeMetrics(List volumeResponses) { + final List 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 listVmMetrics(List vmResponses) { + final List 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 listStoragePoolMetrics(List poolResponses) { + final List 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 listHostMetrics(List hostResponses) { + final List 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 capacities = capacityDao.findCapacityBy(capacityType, zoneId, null, clusterId); + if (capacities == null || capacities.size() < 1) { + return null; + } + return capacities.get(0); + } + + @Override + public List listClusterMetrics(List clusterResponses) { + final List 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 listZoneMetrics(List zoneResponses) { + final List 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> getCommands() { + List> cmdList = new ArrayList>(); + 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; + } + } + +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/ClusterMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/ClusterMetricsResponse.java new file mode 100644 index 00000000000..dde1ab76327 --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/ClusterMetricsResponse.java @@ -0,0 +1,211 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.response.ClusterResponse; + +public class ClusterMetricsResponse extends ClusterResponse { + @SerializedName("state") + @Param(description = "state of the cluster") + private String state; + + @SerializedName("hosts") + @Param(description = "running / total hosts in the cluster") + private String resources; + + @SerializedName("cputotal") + @Param(description = "the total cpu capacity in Ghz") + private String cpuTotal; + + @SerializedName("cpuused") + @Param(description = "the total cpu used in Ghz") + private String cpuUsed; + + @SerializedName("cpuallocated") + @Param(description = "the total cpu allocated in Ghz") + private String cpuAllocated; + + @SerializedName("cpumaxdeviation") + @Param(description = "the maximum cpu deviation") + private String cpuMaxDeviation; + + @SerializedName("memorytotal") + @Param(description = "the total cpu capacity in GiB") + private String memTotal; + + @SerializedName("memoryused") + @Param(description = "the total cpu used in GiB") + private String memUsed; + + @SerializedName("memoryallocated") + @Param(description = "the total cpu allocated in GiB") + private String memAllocated; + + @SerializedName("memorymaxdeviation") + @Param(description = "the maximum memory deviation") + private String memMaxDeviation; + + @SerializedName("cputhreshold") + @Param(description = "cpu usage notification threshold exceeded") + private Boolean cpuThresholdExceeded; + + @SerializedName("cpudisablethreshold") + @Param(description = "cpu usage disable threshold exceeded") + private Boolean cpuDisableThresholdExceeded; + + @SerializedName("cpuallocatedthreshold") + @Param(description = "cpu allocated notification threshold exceeded") + private Boolean cpuAllocatedThresholdExceeded; + + @SerializedName("cpuallocateddisablethreshold") + @Param(description = "cpu allocated disable threshold exceeded") + private Boolean cpuAllocatedDisableThresholdExceeded; + + @SerializedName("memorythreshold") + @Param(description = "memory usage notification threshold exceeded") + private Boolean memoryThresholdExceeded; + + @SerializedName("memorydisablethreshold") + @Param(description = "memory usage disable threshold exceeded") + private Boolean memoryDisableThresholdExceeded; + + @SerializedName("memoryallocatedthreshold") + @Param(description = "memory allocated notification threshold exceeded") + private Boolean memoryAllocatedThresholdExceeded; + + @SerializedName("memoryallocateddisablethreshold") + @Param(description = "memory allocated disable threshold exceeded") + private Boolean memoryAllocatedDisableThresholdExceeded; + + public void setState(final String allocationState, final String managedState) { + this.state = allocationState; + if (managedState.equals("Unmanaged")) { + this.state = managedState; + } + if (managedState.equals("Managed")) { + this.state = allocationState; + } + } + + public void setResources(final Long upResources, final Long totalResources) { + if (upResources != null && totalResources != null) { + this.resources = String.format("%d / %d", upResources, totalResources); + } + } + + public void setCpuTotal(final Long cpuTotal) { + if (cpuTotal != null) { + this.cpuTotal = String.format("%.2f Ghz", cpuTotal / 1000.0); + } + } + + public void setCpuUsed(final Double cpuUsedPercentage, final Long totalHosts) { + if (cpuUsedPercentage != null && totalHosts != null && totalHosts != 0) { + this.cpuUsed = String.format("%.2f%%", 1.0 * cpuUsedPercentage / totalHosts); + } + } + + public void setCpuAllocated(final Long cpuAllocated, final Long cpuTotal) { + if (cpuAllocated != null && cpuTotal != null && cpuTotal != 0) { + this.cpuAllocated = String.format("%.2f%%", cpuAllocated * 100.0 / cpuTotal); + } + } + + public void setCpuMaxDeviation(final Double maxCpuDeviation, final Double totalCpuUsed, final Long totalHosts) { + if (maxCpuDeviation != null && totalCpuUsed != null && totalHosts != null && totalHosts != 0) { + final Double averageCpuUsage = totalCpuUsed / totalHosts; + this.cpuMaxDeviation = String.format("%.2f%%", (maxCpuDeviation - averageCpuUsage) * 100.0 / averageCpuUsage); + } + } + + public void setMemTotal(final Long memTotal) { + if (memTotal != null) { + this.memTotal = String.format("%.2f GB", memTotal / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setMemUsed( final Long memUsed, final Long memTotal) { + if (memUsed != null && memTotal != null && memTotal != 0) { + this.memUsed = String.format("%.2f%%", memUsed * 100.0 / memTotal); + } + } + + public void setMemAllocated(final Long memAllocated, final Long memTotal) { + if (memAllocated != null && memTotal != null && memTotal != 0) { + this.memAllocated = String.format("%.2f%%", memAllocated * 100.0 / memTotal); + } + } + + public void setMemMaxDeviation(final Long maxMemoryUsage, final Long totalMemory, final Long totalHosts) { + if (maxMemoryUsage != null && totalMemory != null && totalHosts != null && totalHosts != 0) { + final Double averageMemoryUsage = 1.0 * totalMemory / totalHosts; + this.memMaxDeviation = String.format("%.2f%%", (maxMemoryUsage - averageMemoryUsage) * 100.0 / averageMemoryUsage); + } + } + + public void setCpuUsageThreshold(final Double cpuUsed, final Long totalHosts, final Double threshold) { + if (cpuUsed != null && totalHosts != null && threshold != null && totalHosts != 0) { + this.cpuThresholdExceeded = (cpuUsed / (100.0 * totalHosts)) > threshold; + } + } + + public void setCpuUsageDisableThreshold(final Double cpuUsed, final Long totalHosts, final Float threshold) { + if (cpuUsed != null && totalHosts != null && threshold != null && totalHosts != 0) { + this.cpuDisableThresholdExceeded = (cpuUsed / (100.0 * totalHosts)) > threshold; + } + } + + public void setCpuAllocatedThreshold(final Long cpuAllocated, final Long cpuUsed, final Double overCommitRatio, final Double threshold) { + if (cpuAllocated != null && cpuUsed != null && overCommitRatio != null && threshold != null && cpuUsed != 0) { + this.cpuAllocatedThresholdExceeded = (1.0 * cpuAllocated * overCommitRatio / cpuUsed) > threshold; + } + } + + public void setCpuAllocatedDisableThreshold(final Long cpuAllocated, final Long cpuUsed, final Double overCommitRatio, final Float threshold) { + if (cpuAllocated != null && cpuUsed != null && overCommitRatio != null && threshold != null && cpuUsed != 0) { + this.cpuAllocatedDisableThresholdExceeded = (1.0 * cpuAllocated * overCommitRatio / cpuUsed) > threshold; + } + } + + public void setMemoryUsageThreshold(final Long memUsed, final Long memTotal, final Double threshold) { + if (memUsed != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryThresholdExceeded = (1.0 * memUsed / memTotal) > threshold; + } + } + + public void setMemoryUsageDisableThreshold(final Long memUsed, final Long memTotal, final Float threshold) { + if (memUsed != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryDisableThresholdExceeded = (1.0 * memUsed / memTotal) > threshold; + } + } + + + public void setMemoryAllocatedThreshold(final Long memAllocated, final Long memTotal, final Double overCommitRatio, final Double threshold) { + if (memAllocated != null && memTotal != null && overCommitRatio != null && threshold != null && memTotal != 0) { + this.memoryAllocatedThresholdExceeded = (1.0 * memAllocated * overCommitRatio / memTotal) > threshold; + } + } + + public void setMemoryAllocatedDisableThreshold(final Long memAllocated, final Long memTotal, final Double overCommitRatio, final Float threshold) { + if (memAllocated != null && memTotal != null && overCommitRatio != null && threshold != null && memTotal != 0) { + this.memoryAllocatedDisableThresholdExceeded = (1.0 * memAllocated * overCommitRatio / memTotal) > threshold; + } + } +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/HostMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/HostMetricsResponse.java new file mode 100644 index 00000000000..cdc9d16d845 --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/HostMetricsResponse.java @@ -0,0 +1,204 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public class HostMetricsResponse extends HostResponse { + @SerializedName("powerstate") + @Param(description = "out-of-band management power state") + private OutOfBandManagement.PowerState powerState; + + @SerializedName("instances") + @Param(description = "instances on the host") + private String instances; + + @SerializedName("cputotalghz") + @Param(description = "the total cpu capacity in Ghz") + private String cpuTotal; + + @SerializedName("cpuusedghz") + @Param(description = "the total cpu used in Ghz") + private String cpuUsed; + + @SerializedName("cpuallocatedghz") + @Param(description = "the total cpu allocated in Ghz") + private String cpuAllocated; + + @SerializedName("memorytotalgb") + @Param(description = "the total cpu capacity in GiB") + private String memTotal; + + @SerializedName("memoryusedgb") + @Param(description = "the total cpu used in GiB") + private String memUsed; + + @SerializedName("memoryallocatedgb") + @Param(description = "the total cpu allocated in GiB") + private String memAllocated; + + @SerializedName("networkread") + @Param(description = "network read in GiB") + private String networkRead; + + @SerializedName("networkwrite") + @Param(description = "network write in GiB") + private String networkWrite; + + @SerializedName("cputhreshold") + @Param(description = "cpu usage notification threshold exceeded") + private Boolean cpuThresholdExceeded; + + @SerializedName("cpudisablethreshold") + @Param(description = "cpu usage disable threshold exceeded") + private Boolean cpuDisableThresholdExceeded; + + @SerializedName("cpuallocatedthreshold") + @Param(description = "cpu allocated notification threshold exceeded") + private Boolean cpuAllocatedThresholdExceeded; + + @SerializedName("cpuallocateddisablethreshold") + @Param(description = "cpu allocated disable threshold exceeded") + private Boolean cpuAllocatedDisableThresholdExceeded; + + @SerializedName("memorythreshold") + @Param(description = "memory usage notification threshold exceeded") + private Boolean memoryThresholdExceeded; + + @SerializedName("memorydisablethreshold") + @Param(description = "memory usage disable threshold exceeded") + private Boolean memoryDisableThresholdExceeded; + + @SerializedName("memoryallocatedthreshold") + @Param(description = "memory allocated notification threshold exceeded") + private Boolean memoryAllocatedThresholdExceeded; + + @SerializedName("memoryallocateddisablethreshold") + @Param(description = "memory allocated disable threshold exceeded") + private Boolean memoryAllocatedDisableThresholdExceeded; + + public void setPowerState(final OutOfBandManagement.PowerState powerState) { + this.powerState = powerState; + } + + public void setInstances(final Long running, final Long total) { + if (running != null && total != null) { + this.instances = String.format("%d / %d", running, total); + } + } + + public void setCpuTotal(final Integer cpuNumber, final Long cpuSpeed, final Double overcommitRatio) { + if (cpuNumber != null && cpuSpeed != null && overcommitRatio != null) { + this.cpuTotal = String.format("%.2f Ghz (x %.1f)", cpuNumber * cpuSpeed / 1000.0, overcommitRatio); + } + } + + public void setCpuUsed(final String cpuUsed, final Integer cpuNumber, final Long cpuSpeed) { + if (cpuUsed != null && cpuNumber != null && cpuSpeed != null) { + this.cpuUsed = String.format("%.2f Ghz", Double.valueOf(cpuUsed.replace("%", "")) * cpuNumber * cpuSpeed / (100.0 * 1000.0)); + } + } + + public void setCpuAllocated(final String cpuAllocated, final Integer cpuNumber, final Long cpuSpeed) { + if (cpuAllocated != null && cpuNumber != null && cpuSpeed != null) { + this.cpuAllocated = String.format("%.2f Ghz", Double.valueOf(cpuAllocated.replace("%", "")) * cpuNumber * cpuSpeed / (100.0 * 1000.0)); + } + } + + public void setMemTotal(final Long memTotal, final Double overcommitRatio) { + if (memTotal != null && overcommitRatio != null) { + this.memTotal = String.format("%.2f GB (x %.1f)", memTotal / (1024.0 * 1024.0 * 1024.0), overcommitRatio); + } + } + + public void setMemUsed(final Long memUsed) { + if (memUsed != null) { + this.memUsed = String.format("%.2f GB", memUsed / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setMemAllocated(final Long memAllocated) { + if (memAllocated != null) { + this.memAllocated = String.format("%.2f GB", memAllocated / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setNetworkRead(final Long networkReadKbs) { + if (networkReadKbs != null) { + this.networkRead = String.format("%.2f GB", networkReadKbs / (1024.0 * 1024.0)); + } + } + + public void setNetworkWrite(final Long networkWriteKbs) { + if (networkWriteKbs != null) { + this.networkWrite = String.format("%.2f GB", networkWriteKbs / (1024.0 * 1024.0)); + } + } + + public void setCpuUsageThreshold(final String cpuUsed, final Double threshold) { + if (cpuUsed != null && threshold != null) { + this.cpuThresholdExceeded = Double.valueOf(cpuUsed.replace("%", "")) > (100.0 * threshold); + } + } + + public void setCpuUsageDisableThreshold(final String cpuUsed, final Float threshold) { + if (cpuUsed != null && threshold != null) { + this.cpuDisableThresholdExceeded = Double.valueOf(cpuUsed.replace("%", "")) > (100.0 * threshold); + } + } + + public void setCpuAllocatedThreshold(final String cpuAllocated, final Double overCommitRatio, final Double threshold) { + if (cpuAllocated != null && overCommitRatio != null && threshold != null) { + this.cpuAllocatedThresholdExceeded = (Double.valueOf(cpuAllocated.replace("%", "")) * overCommitRatio) > (100.0 * threshold); + } + } + + public void setCpuAllocatedDisableThreshold(final String cpuAllocated, final Double overCommitRatio, final Float threshold) { + if (cpuAllocated != null && overCommitRatio != null && threshold != null) { + this.cpuAllocatedDisableThresholdExceeded = (Double.valueOf(cpuAllocated.replace("%", "")) * overCommitRatio) > (100.0 * threshold); + } + } + + public void setMemoryUsageThreshold(final Long memUsed, final Long memTotal, final Double threshold) { + if (memUsed != null && memTotal != null && threshold != null) { + this.memoryThresholdExceeded = memUsed > (memTotal * threshold); + } + } + + public void setMemoryUsageDisableThreshold(final Long memUsed, final Long memTotal, final Float threshold) { + if (memUsed != null && memTotal != null && threshold != null) { + this.memoryDisableThresholdExceeded = memUsed > (memTotal * threshold); + } + } + + public void setMemoryAllocatedThreshold(final Long memAllocated, final Long memTotal, final Double overCommitRatio, final Double threshold) { + if (memAllocated != null && memTotal != null && overCommitRatio != null && threshold != null) { + this.memoryAllocatedThresholdExceeded = (memAllocated * overCommitRatio) > (memTotal * threshold); + } + } + + public void setMemoryAllocatedDisableThreshold(final Long memAllocated, final Long memTotal, final Double overCommitRatio, final Float threshold) { + if (memAllocated != null && memTotal != null && overCommitRatio != null && threshold != null) { + this.memoryAllocatedDisableThresholdExceeded = (memAllocated * overCommitRatio) > (memTotal * threshold); + } + } + +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/InfrastructureResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/InfrastructureResponse.java new file mode 100644 index 00000000000..a4db345d21d --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/InfrastructureResponse.java @@ -0,0 +1,101 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.BaseResponse; + +public class InfrastructureResponse extends BaseResponse { + + @SerializedName("zones") + @Param(description = "Number of zones") + private Integer zones; + + @SerializedName("pods") + @Param(description = "Number of pods") + private Integer pods; + + @SerializedName("clusters") + @Param(description = "Number of clusters") + private Integer clusters; + + @SerializedName("hosts") + @Param(description = "Number of hypervisor hosts") + private Integer hosts; + + @SerializedName("storagepools") + @Param(description = "Number of storage pools") + private Integer storagePools; + + @SerializedName("imagestores") + @Param(description = "Number of images stores") + private Integer imageStores; + + @SerializedName("systemvms") + @Param(description = "Number of systemvms") + private Integer systemvms; + + @SerializedName("routers") + @Param(description = "Number of routers") + private Integer routers; + + @SerializedName("cpusockets") + @Param(description = "Number of cpu sockets") + private Integer cpuSockets; + + public InfrastructureResponse() { + setObjectName("infrastructure"); + } + + public void setZones(final Integer zones) { + this.zones = zones; + } + + public void setPods(final Integer pods) { + this.pods = pods; + } + + public void setClusters(final Integer clusters) { + this.clusters = clusters; + } + + public void setHosts(final Integer hosts) { + this.hosts = hosts; + } + + public void setStoragePools(final Integer storagePools) { + this.storagePools = storagePools; + } + + public void setImageStores(final Integer imageStores) { + this.imageStores = imageStores; + } + + public void setSystemvms(final Integer systemvms) { + this.systemvms = systemvms; + } + + public void setRouters(final Integer routers) { + this.routers = routers; + } + + public void setCpuSockets(final Integer cpuSockets) { + this.cpuSockets = cpuSockets; + } +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/StoragePoolMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/StoragePoolMetricsResponse.java new file mode 100644 index 00000000000..f20f797aa3e --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/StoragePoolMetricsResponse.java @@ -0,0 +1,105 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.response.StoragePoolResponse; + +public class StoragePoolMetricsResponse extends StoragePoolResponse { + @SerializedName("disksizeusedgb") + @Param(description = "disk size used in GiB") + private String diskSizeUsedGB; + + @SerializedName("disksizetotalgb") + @Param(description = "disk size in GiB") + private String diskSizeTotalGB; + + @SerializedName("disksizeallocatedgb") + @Param(description = "disk size allocated in GiB") + private String diskSizeAllocatedGB; + + @SerializedName("disksizeunallocatedgb") + @Param(description = "disk size unallocated in GiB") + private String diskSizeUnallocatedGB; + + @SerializedName("storageusagethreshold") + @Param(description = "storage usage notification threshold exceeded") + private Boolean storageUsedThreshold; + + @SerializedName("storageusagedisablethreshold") + @Param(description = "storage usage disable threshold exceeded") + private Boolean storageUsedDisableThreshold; + + @SerializedName("storageallocatedthreshold") + @Param(description = "storage allocated notification threshold exceeded") + private Boolean storageAllocatedThreshold; + + @SerializedName("storageallocateddisablethreshold") + @Param(description = "storage allocated disable threshold exceeded") + private Boolean storageAllocatedDisableThreshold; + + public void setDiskSizeUsedGB(final Long diskSizeUsed) { + if (diskSizeUsed != null) { + this.diskSizeUsedGB = String.format("%.2f GB", diskSizeUsed / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setDiskSizeTotalGB(final Long totalDiskSize, final String overProvisionFactor) { + if (totalDiskSize != null && overProvisionFactor != null) { + this.diskSizeTotalGB = String.format("%.2f GB (x%s)", totalDiskSize / (1024.0 * 1024.0 * 1024.0), overProvisionFactor); + } + } + + public void setDiskSizeAllocatedGB(final Long diskSizeAllocated) { + if (diskSizeAllocated != null) { + this.diskSizeAllocatedGB = String.format("%.2f GB", diskSizeAllocated / (1024.0 * 1024.0 * 1024.0)); + + } + } + + public void setDiskSizeUnallocatedGB(final Long totalDiskSize, final Long diskSizeAllocated, final String overProvisionFactor) { + if (totalDiskSize != null && diskSizeAllocated != null && overProvisionFactor != null) { + this.diskSizeUnallocatedGB = String.format("%.2f GB", ((Double.valueOf(overProvisionFactor) * totalDiskSize) - diskSizeAllocated) / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setStorageUsedThreshold(final Long totalDiskSize, final Long diskSizeUsed, final String overProvisionFactor, final Double threshold) { + if (totalDiskSize != null && diskSizeUsed != null && overProvisionFactor != null && threshold != null) { + this.storageUsedThreshold = diskSizeUsed > (totalDiskSize * Double.valueOf(overProvisionFactor) * threshold) ; + } + } + + public void setStorageUsedDisableThreshold(final Long totalDiskSize, final Long diskSizeUsed, final String overProvisionFactor, final Double threshold) { + if (totalDiskSize != null && diskSizeUsed != null && overProvisionFactor != null && threshold != null) { + this.storageUsedDisableThreshold = diskSizeUsed > (totalDiskSize * Double.valueOf(overProvisionFactor) * threshold); + } + } + + public void setStorageAllocatedThreshold(final Long totalDiskSize, final Long diskSizeAllocated, final String overProvisionFactor, final Double threshold) { + if (totalDiskSize != null && diskSizeAllocated != null && overProvisionFactor != null && threshold != null) { + this.storageAllocatedThreshold = diskSizeAllocated > (totalDiskSize * Double.valueOf(overProvisionFactor) * threshold); + } + } + + public void setStorageAllocatedDisableThreshold(final Long totalDiskSize, final Long diskSizeAllocated, final String overProvisionFactor, final Double threshold) { + if (totalDiskSize != null && diskSizeAllocated != null && overProvisionFactor != null && threshold != null) { + this.storageAllocatedDisableThreshold = diskSizeAllocated > (totalDiskSize * Double.valueOf(overProvisionFactor) * threshold); + } + } +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/VmMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/VmMetricsResponse.java new file mode 100644 index 00000000000..a4057aeb059 --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/VmMetricsResponse.java @@ -0,0 +1,108 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.UserVmResponse; + +import java.util.Set; + +public class VmMetricsResponse extends UserVmResponse { + @SerializedName(ApiConstants.IP_ADDRESS) + @Param(description = "the VM's primary IP address") + private String ipAddress; + + @SerializedName("cputotal") + @Param(description = "the total cpu capacity in Ghz") + private String cpuTotal; + + @SerializedName("memorytotal") + @Param(description = "the total memory capacity in GiB") + private String memTotal; + + @SerializedName("networkread") + @Param(description = "network read in MiB") + private String networkRead; + + @SerializedName("networkwrite") + @Param(description = "network write in MiB") + private String networkWrite; + + @SerializedName("diskread") + @Param(description = "disk read in MiB") + private String diskRead; + + @SerializedName("diskwrite") + @Param(description = "disk write in MiB") + private String diskWrite; + + @SerializedName("diskiopstotal") + @Param(description = "the total disk iops") + private Long diskIopsTotal; + + public void setIpAddress(final Set nics) { + if (nics != null && nics.size() > 0) { + this.ipAddress = nics.iterator().next().getIpaddress(); + } + } + + public void setCpuTotal(final Integer cpuNumber, final Integer cpuSpeed) { + if (cpuNumber != null && cpuSpeed != null) { + this.cpuTotal = String.format("%.1f Ghz", cpuNumber * cpuSpeed / 1000.0); + } + } + + public void setMemTotal(final Integer memory) { + if (memory != null) { + this.memTotal = String.format("%.2f GB", memory / 1024.0); + } + } + + public void setNetworkRead(final Long networkReadKbs) { + if (networkReadKbs != null) { + this.networkRead = String.format("%.2f MB", networkReadKbs / 1024.0); + } + } + + public void setNetworkWrite(final Long networkWriteKbs) { + if (networkWriteKbs != null) { + this.networkWrite = String.format("%.2f MB", networkWriteKbs / 1024.0); + } + } + + public void setDiskRead(final Long diskReadKbs) { + if (diskReadKbs != null) { + this.networkRead = String.format("%.2f MB", diskReadKbs / 1024.0); + } + } + + public void setDiskWrite(final Long diskWriteKbs) { + if (diskWriteKbs != null) { + this.networkWrite = String.format("%.2f MB", diskWriteKbs / 1024.0); + } + } + + public void setDiskIopsTotal(final Long diskIoRead, final Long diskIoWrite) { + if (diskIoRead != null && diskIoWrite != null) { + this.diskIopsTotal = diskIoRead + diskIoWrite; + } + } +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/VolumeMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/VolumeMetricsResponse.java new file mode 100644 index 00000000000..ef8515f1396 --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/VolumeMetricsResponse.java @@ -0,0 +1,41 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.common.base.Strings; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.response.VolumeResponse; + +public class VolumeMetricsResponse extends VolumeResponse { + @SerializedName("sizegb") + @Param(description = "disk size in GiB") + private String diskSizeGB; + + public void setStorageType(final String storageType, final String volumeType) { + if (!Strings.isNullOrEmpty(storageType) && !Strings.isNullOrEmpty(volumeType)) { + this.setStorageType(String.format("%s (%s)", storageType.substring(0, 1).toUpperCase() + storageType.substring(1), volumeType)); + } + } + + public void setDiskSizeGB(final Long size) { + if (size != null) { + this.diskSizeGB = String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0)); + } + } +} diff --git a/plugins/metrics/src/org/apache/cloudstack/response/ZoneMetricsResponse.java b/plugins/metrics/src/org/apache/cloudstack/response/ZoneMetricsResponse.java new file mode 100644 index 00000000000..71560178564 --- /dev/null +++ b/plugins/metrics/src/org/apache/cloudstack/response/ZoneMetricsResponse.java @@ -0,0 +1,206 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.response.ZoneResponse; + +public class ZoneMetricsResponse extends ZoneResponse { + @SerializedName("state") + @Param(description = "state of the cluster") + private String state; + + @SerializedName("clusters") + @Param(description = "healthy / total clusters in the zone") + private String resources; + + @SerializedName("cputotal") + @Param(description = "the total cpu capacity in Ghz") + private String cpuTotal; + + @SerializedName("cpuused") + @Param(description = "the total cpu used in Ghz") + private String cpuUsed; + + @SerializedName("cpuallocated") + @Param(description = "the total cpu allocated in Ghz") + private String cpuAllocated; + + @SerializedName("cpumaxdeviation") + @Param(description = "the maximum cpu deviation") + private String cpuMaxDeviation; + + @SerializedName("memorytotal") + @Param(description = "the total cpu capacity in GiB") + private String memTotal; + + @SerializedName("memoryused") + @Param(description = "the total cpu used in GiB") + private String memUsed; + + @SerializedName("memoryallocated") + @Param(description = "the total cpu allocated in GiB") + private String memAllocated; + + @SerializedName("memorymaxdeviation") + @Param(description = "the maximum memory deviation") + private String memMaxDeviation; + + @SerializedName("cputhreshold") + @Param(description = "cpu usage notification threshold exceeded") + private Boolean cpuThresholdExceeded; + + @SerializedName("cpudisablethreshold") + @Param(description = "cpu usage disable threshold exceeded") + private Boolean cpuDisableThresholdExceeded; + + @SerializedName("cpuallocatedthreshold") + @Param(description = "cpu allocated notification threshold exceeded") + private Boolean cpuAllocatedThresholdExceeded; + + @SerializedName("cpuallocateddisablethreshold") + @Param(description = "cpu allocated disable threshold exceeded") + private Boolean cpuAllocatedDisableThresholdExceeded; + + @SerializedName("memorythreshold") + @Param(description = "memory usage notification threshold exceeded") + private Boolean memoryThresholdExceeded; + + @SerializedName("memorydisablethreshold") + @Param(description = "memory usage disable threshold exceeded") + private Boolean memoryDisableThresholdExceeded; + + @SerializedName("memoryallocatedthreshold") + @Param(description = "memory allocated notification threshold exceeded") + private Boolean memoryAllocatedThresholdExceeded; + + @SerializedName("memoryallocateddisablethreshold") + @Param(description = "memory allocated disable threshold exceeded") + private Boolean memoryAllocatedDisableThresholdExceeded; + + + public void setState(final String allocationState) { + this.state = allocationState; + } + + public void setResource(final Long upResources, final Long totalResources) { + if (upResources != null && totalResources != null) { + this.resources = String.format("%d / %d", upResources, totalResources); + } + } + + public void setCpuTotal(final Long cpuTotal) { + if (cpuTotal != null) { + this.cpuTotal = String.format("%.2f Ghz", cpuTotal / 1000.0); + } + } + + public void setCpuUsed(final Double cpuUsedPercentage, final Long totalHosts) { + if (cpuUsedPercentage != null && totalHosts != null && totalHosts != 0) { + this.cpuUsed = String.format("%.2f%%", 1.0 * cpuUsedPercentage / totalHosts); + } + } + + public void setCpuAllocated(final Long cpuAllocated, final Long cpuTotal) { + if (cpuAllocated != null && cpuTotal != null && cpuTotal != 0) { + this.cpuAllocated = String.format("%.2f%%", cpuAllocated * 100.0 / cpuTotal); + } + } + + public void setCpuMaxDeviation(final Double maxCpuDeviation, final Double totalCpuUsed, final Long totalHosts) { + if (maxCpuDeviation != null && totalCpuUsed != null && totalHosts != null && totalHosts != 0) { + final Double averageCpuUsage = totalCpuUsed / totalHosts; + this.cpuMaxDeviation = String.format("%.2f%%", (maxCpuDeviation - averageCpuUsage) * 100.0 / averageCpuUsage); + } + } + + public void setMemTotal(final Long memTotal) { + if (memTotal != null) { + this.memTotal = String.format("%.2f GB", memTotal / (1024.0 * 1024.0 * 1024.0)); + } + } + + public void setMemUsed( final Long memUsed, final Long memTotal) { + if (memUsed != null && memTotal != null) { + this.memUsed = String.format("%.2f%%", memUsed * 100.0 / memTotal); + } + } + + public void setMemAllocated(final Long memAllocated, final Long memTotal) { + if (memAllocated != null && memTotal != null && memTotal != 0) { + this.memAllocated = String.format("%.2f%%", memAllocated * 100.0 / memTotal); + } + } + + public void setMemMaxDeviation(final Long maxMemoryUsage, final Long totalMemory, final Long totalHosts) { + if (maxMemoryUsage != null && totalMemory != null && totalHosts != null && totalHosts != 0) { + final Long averageMemoryUsage = totalMemory / totalHosts; + this.memMaxDeviation = String.format("%.2f%%", (maxMemoryUsage - averageMemoryUsage) * 100.0 / averageMemoryUsage); + } + } + + public void setCpuUsageThreshold(final Double cpuUsed, final Long totalHosts, final Double threshold) { + if (cpuUsed != null && totalHosts != null && threshold != null && totalHosts != 0) { + this.cpuThresholdExceeded = (cpuUsed / (100.0 * totalHosts)) > threshold; + } + } + + public void setCpuUsageDisableThreshold(final Double cpuUsed, final Long totalHosts, final Float threshold) { + if (cpuUsed != null && totalHosts != null && threshold != null && totalHosts != 0) { + this.cpuDisableThresholdExceeded = (cpuUsed / (100.0 * totalHosts)) > threshold; + } + } + + public void setCpuAllocatedThreshold(final Long cpuAllocated, final Long cpuUsed, final Double threshold) { + if (cpuAllocated != null && cpuUsed != null && threshold != null && cpuUsed != 0) { + this.cpuAllocatedThresholdExceeded = (1.0 * cpuAllocated / cpuUsed) > threshold; + } + } + + public void setCpuAllocatedDisableThreshold(final Long cpuAllocated, final Long cpuUsed, final Float threshold) { + if (cpuAllocated != null && cpuUsed != null && threshold != null && cpuUsed != 0) { + this.cpuAllocatedDisableThresholdExceeded = (1.0 * cpuAllocated / cpuUsed) > threshold; + } + } + + public void setMemoryUsageThreshold(final Long memUsed, final Long memTotal, final Double threshold) { + if (memUsed != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryThresholdExceeded = (1.0 * memUsed / memTotal) > threshold; + } + } + + public void setMemoryUsageDisableThreshold(final Long memUsed, final Long memTotal, final Float threshold) { + if (memUsed != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryDisableThresholdExceeded = (1.0 * memUsed / memTotal) > threshold; + } + } + + + public void setMemoryAllocatedThreshold(final Long memAllocated, final Long memTotal, final Double threshold) { + if (memAllocated != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryAllocatedThresholdExceeded = (1.0 * memAllocated / memTotal) > threshold; + } + } + + public void setMemoryAllocatedDisableThreshold(final Long memAllocated, final Long memTotal, final Float threshold) { + if (memAllocated != null && memTotal != null && threshold != null && memTotal != 0) { + this.memoryAllocatedDisableThresholdExceeded = (1.0 * memAllocated / memTotal) > threshold; + } + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 40cee26541f..72a7bc1dbad 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -69,6 +69,7 @@ hypervisors/ucs hypervisors/hyperv hypervisors/ovm3 + metrics network-elements/elastic-loadbalancer network-elements/ovs network-elements/juniper-contrail diff --git a/server/src/com/cloud/api/query/dao/HostJoinDao.java b/server/src/com/cloud/api/query/dao/HostJoinDao.java index f0ac1831d45..e7dc5d5ff04 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDao.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDao.java @@ -41,4 +41,6 @@ public interface HostJoinDao extends GenericDao { List searchByIds(Long... ids); + List findByClusterId(Long clusterId, Host.Type type); + } diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java index 6c15a8be4d8..58a03664c13 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -65,6 +65,8 @@ public class HostJoinDaoImpl extends GenericDaoBase implements private final SearchBuilder hostIdSearch; + private final SearchBuilder ClusterSearch; + protected HostJoinDaoImpl() { hostSearch = createSearchBuilder(); @@ -75,6 +77,11 @@ public class HostJoinDaoImpl extends GenericDaoBase implements hostIdSearch.and("id", hostIdSearch.entity().getId(), SearchCriteria.Op.EQ); hostIdSearch.done(); + ClusterSearch = createSearchBuilder(); + ClusterSearch.and("clusterId", ClusterSearch.entity().getClusterId(), SearchCriteria.Op.EQ); + ClusterSearch.and("type", ClusterSearch.entity().getType(), SearchCriteria.Op.EQ); + ClusterSearch.done(); + this._count = "select count(distinct id) from host_view WHERE "; } @@ -432,4 +439,12 @@ public class HostJoinDaoImpl extends GenericDaoBase implements return uvList; } + @Override + public List findByClusterId(Long clusterId, Host.Type type) { + SearchCriteria sc = ClusterSearch.create(); + sc.setParameters("clusterId", clusterId); + sc.setParameters("type", type); + return listBy(sc); + } + } diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index ef0ad19079f..80c417e1f53 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -588,7 +588,7 @@ StateListener { List allDedicatedPods = _dedicatedDao.listAllPods(); allPodsInDc.retainAll(allDedicatedPods); - List allClustersInDc = _clusterDao.listAllCusters(dc.getId()); + List allClustersInDc = _clusterDao.listAllClusters(dc.getId()); List allDedicatedClusters = _dedicatedDao.listAllClusters(); allClustersInDc.retainAll(allDedicatedClusters); diff --git a/test/integration/smoke/test_metrics_api.py b/test/integration/smoke/test_metrics_api.py new file mode 100644 index 00000000000..27c4a1bd75b --- /dev/null +++ b/test/integration/smoke/test_metrics_api.py @@ -0,0 +1,210 @@ +# 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. + +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.lib.utils import * +from marvin.lib.base import * +from marvin.lib.common import * +from marvin.lib.utils import (random_gen) +from nose.plugins.attrib import attr + +import time + +_multiprocess_shared_ = True + +class TestMetrics(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.hypervisor = self.testClient.getHypervisorInfo() + self.dbclient = self.testClient.getDbConnection() + self.services = self.testClient.getParsedTestDataConfig() + self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests()) + self.pod = get_pod(self.apiclient, self.zone.id) + self.host = list_hosts(self.apiclient, + zoneid=self.zone.id, + type='Routing')[0] + self.cluster = self.apiclient.listClusters(listClusters.listClustersCmd())[0] + self.disk_offering = DiskOffering.create( + self.apiclient, + self.services["disk_offering"] + ) + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offering"] + ) + self.template = get_template( + self.apiclient, + self.zone.id, + self.services["ostype"] + ) + + self.cleanup = [] + self.cleanup.append(self.disk_offering) + self.cleanup.append(self.service_offering) + + def tearDown(self): + try: + #Clean up + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_hosts_metrics(self): + + cmd = listHostsMetrics.listHostsMetricsCmd() + cmd.id = self.host.id + cmd.type = 'Routing' + + host_metric = self.apiclient.listHostsMetrics(cmd)[0] + + self.assertEqual(host_metric.cpuallocated, self.host.cpuallocated) + self.assertEqual(host_metric.memoryallocated, self.host.memoryallocated) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_clusters_metrics(self): + + cmd = listClustersMetrics.listClustersMetricsCmd() + cmd.id = self.cluster.id + + cluster_metric = self.apiclient.listClustersMetrics(cmd)[0] + + self.assertEqual(cluster_metric.id, self.cluster.id) + self.assertTrue(hasattr(cluster_metric, 'cpuallocated')) + self.assertTrue(hasattr(cluster_metric, 'cpumaxdeviation')) + self.assertTrue(hasattr(cluster_metric, 'memoryallocated')) + self.assertTrue(hasattr(cluster_metric, 'memoryused')) + self.assertTrue(hasattr(cluster_metric, 'memorymaxdeviation')) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_zones_metrics(self): + cmd = listZonesMetrics.listZonesMetricsCmd() + cmd.id = self.zone.id + + zone_metrics = self.apiclient.listZonesMetrics(cmd)[0] + + self.assertTrue(hasattr(zone_metrics, 'cpuallocated')) + self.assertTrue(hasattr(zone_metrics, 'cpumaxdeviation')) + self.assertTrue(hasattr(zone_metrics, 'cputotal')) + self.assertTrue(hasattr(zone_metrics, 'cpuused')) + self.assertTrue(hasattr(zone_metrics, 'memoryallocated')) + self.assertTrue(hasattr(zone_metrics, 'memorymaxdeviation')) + self.assertTrue(hasattr(zone_metrics, 'memoryused')) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_vms_metrics(self): + #deploy VM + self.small_virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + serviceofferingid=self.service_offering.id, + templateid=self.template.id, + zoneid=self.zone.id + ) + self.cleanup.append(self.small_virtual_machine) + + + cmd = listVirtualMachinesMetrics.listVirtualMachinesMetricsCmd() + cmd.id = self.small_virtual_machine.id + + lvmm = self.apiclient.listVirtualMachinesMetrics(cmd)[0] + + self.assertEqual(lvmm.id, self.small_virtual_machine.id) + + self.assertTrue(hasattr(lvmm, 'cputotal')) + self.assertTrue(hasattr(lvmm, 'cpuused')) + self.assertTrue(hasattr(lvmm, 'diskiowrite')) + self.assertTrue(hasattr(lvmm, 'diskkbswrite')) + self.assertTrue(hasattr(lvmm, 'networkread')) + self.assertTrue(hasattr(lvmm, 'networkwrite')) + + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_pstorage_metrics(self): + #list StoragePools + sp = self.apiclient.listStoragePools(listStoragePools.listStoragePoolsCmd())[0] + + #list StoragePoolsMetrics + cmd = listStoragePoolsMetrics.listStoragePoolsMetricsCmd() + cmd.id = sp.id + + sp_metrics = self.apiclient.listStoragePoolsMetrics(cmd)[0] + + self.assertEqual(sp_metrics.disksizeallocated, sp.disksizeallocated) + self.assertEqual(sp_metrics.state, sp.state) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_volumes_metrics(self): + volume = Volume.create( + self.apiclient, + self.services['volume'], + zoneid=self.zone.id, + diskofferingid=self.disk_offering.id + ) + self.cleanup.append(volume) + + cmd = listVolumes.listVolumesCmd() + cmd.id = volume.id + + lv = self.apiclient.listVolumes(cmd)[0] + + cmd = listVolumesMetrics.listVolumesMetricsCmd() + cmd.id = lv.id + lvm = self.apiclient.listVolumesMetrics(cmd)[0] + + self.assertEqual(lv.size, lvm.size) + self.assertTrue(hasattr(lvm, 'diskBytesReadRate')) + self.assertTrue(hasattr(lvm, 'diskBytesWriteRate')) + self.assertTrue(hasattr(lvm, 'diskIopsReadRate')) + self.assertTrue(hasattr(lvm, 'diskIopsWriteRate')) + + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_list_infrastructure_metrics(self): + cmd = listInfrastructure.listInfrastructureCmd() + li = self.apiclient.listInfrastructure(cmd) + + self.assertTrue(hasattr(li, 'clusters')) + self.assertEqual(li.clusters, len(self.apiclient.listClusters(listClusters.listClustersCmd()))) + self.assertTrue(hasattr(li, 'hosts')) + + self.assertEqual(li.hosts, len(list_hosts(self.apiclient, + zoneid=self.zone.id, + type='Routing'))) + + self.assertTrue(hasattr(li, 'imagestores')) + self.assertEqual(li.imagestores, len(self.apiclient.listImageStores(listImageStores.listImageStoresCmd()))) + + self.assertTrue(hasattr(li, 'pods')) + self.assertEqual(li.pods, len(self.apiclient.listPods(listPods.listPodsCmd()))) + + self.assertTrue(hasattr(li, 'routers')) + + self.assertTrue(hasattr(li, 'storagepools')) + self.assertEqual(li.storagepools, len(self.apiclient.listStoragePools(listStoragePools.listStoragePoolsCmd()))) + + self.assertTrue(hasattr(li, 'zones')) + self.assertEqual(li.zones, len(self.apiclient.listZones(listZones.listZonesCmd()))) + + self.assertTrue(hasattr(li, 'systemvms')) + self.assertTrue(hasattr(li, 'cpusockets')) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index e6ef6748119..0fd97754176 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -168,7 +168,9 @@ known_categories = { 'CacheStore' : 'Cache Store', 'IAM' : 'IAM', 'OvsElement' : 'Ovs Element', - 'StratosphereSsp' : ' Stratosphere SSP' + 'StratosphereSsp' : ' Stratosphere SSP', + 'Metrics' : 'Metrics', + 'Infrastructure' : 'Metrics', } diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index 554aab777d1..3152af76a05 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -56,15 +56,15 @@ label: 'label.metrics.cpu.usage', collapsible: true, columns: { - cpuusedavg: { + cpuused: { label: 'label.metrics.cpu.used.avg', thresholdcolor: true, thresholds: { - notification: 'cpunotificationthreshold', + notification: 'cputhreshold', disable: 'cpudisablethreshold' } }, - cpumaxdev: { + cpumaxdeviation: { label: 'label.metrics.cpu.max.dev' } } @@ -77,8 +77,8 @@ label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'cpunotificationthreshold', - disable: 'cpudisablethreshold' + notification: 'cpuallocatedthreshold', + disable: 'cpuallocateddisablethreshold' } }, cputotal: { @@ -90,15 +90,15 @@ label: 'label.metrics.memory.usage', collapsible: true, columns: { - memusedavg: { + memoryused: { label: 'label.metrics.memory.used.avg', thresholdcolor: true, thresholds: { - notification: 'memnotificationthreshold', - disable: 'memdisablethreshold' + notification: 'memorythreshold', + disable: 'memorydisablethreshold' } }, - memmaxdev: { + memorymaxdeviation: { label: 'label.metrics.memory.max.dev' } } @@ -107,15 +107,15 @@ label: 'label.metrics.memory.allocated', collapsible: true, columns: { - memallocated: { + memoryallocated: { label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'memnotificationthreshold', - disable: 'memdisablethreshold' + notification: 'memoryallocatedthreshold', + disable: 'memoryallocateddisablethreshold' } }, - memtotal: { + memorytotal: { label: 'label.metrics.memory.total' } } @@ -125,129 +125,11 @@ var data = {}; listViewDataProvider(args, data); $.ajax({ - url: createURL('listZones'), + url: createURL('listZonesMetrics'), data: data, success: function(json) { - var items = json.listzonesresponse.zone; - if (items) { - $.each(items, function(idx, zone) { - items[idx].clusters = 0; - items[idx].clustersUp = 0; - items[idx].hosts = 0; - items[idx].cpuusedavg = 0.0; - items[idx].cpumaxdev = 0.0; - items[idx].cpuallocated = 0.0; - items[idx].cputotal = 0.0; - items[idx].maxCpuUsed = 0.0; - items[idx].memusedavg = 0.0; - items[idx].memmaxdev = 0.0; - items[idx].memallocated = 0.0; - items[idx].memtotal = 0.0; - items[idx].maxMemUsed = 0.0; - - // Threshold color coding - items[idx].cpunotificationthreshold = 75.0; - items[idx].cpudisablethreshold = 95.0; - items[idx].memnotificationthreshold = 75.0; - items[idx].memdisablethreshold = 95.0; - - $.ajax({ - url: createURL('listClusters'), - data: {zoneid: zone.id, pagesize: -1}, - success: function(json) { - if (json && json.listclustersresponse && json.listclustersresponse.cluster && json.listclustersresponse.count) { - items[idx].clusters += parseInt(json.listclustersresponse.count); - $.each(json.listclustersresponse.cluster, function(i, cluster) { - if (cluster.allocationstate == 'Enabled' && cluster.managedstate == 'Managed') { - items[idx].clustersUp += 1; - } - $.ajax({ - url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, - success: function(json) { - if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { - items[idx].hosts += parseInt(json.listhostsresponse.count); - $.each(json.listhostsresponse.host, function(i, host) { - if (host.hasOwnProperty('cpuused')) { - var hostCpuUsage = parseFloat(host.cpuused); - items[idx].cpuusedavg += hostCpuUsage; - if (hostCpuUsage > items[idx].maxCpuUsed) { - items[idx].maxCpuUsed = hostCpuUsage; - } - } - - if (host.hasOwnProperty('cpuallocated')) { - items[idx].cpuallocated += parseFloat(host.cpuallocated.replace('%', '')); - } - - if (host.hasOwnProperty('memoryused')) { - var hostMemoryUsage = 100.0 * parseFloat(host.memoryused) / parseFloat(host.memorytotal); - items[idx].memusedavg += hostMemoryUsage; - if (hostMemoryUsage > items[idx].maxMemUsed) { - items[idx].maxMemUsed = hostMemoryUsage; - } - } - - if (host.hasOwnProperty('memoryallocated')) { - items[idx].memallocated += parseFloat(100.0 * parseFloat(host.memoryallocated)/parseFloat(host.memorytotal)); - } - }); - } - }, - async: false - }); - }); - } - }, - async: false - }); - - $.ajax({ - url: createURL('listCapacity'), - data: {zoneid: zone.id}, - success: function(json) { - if (json && json.listcapacityresponse && json.listcapacityresponse.capacity) { - $.each(json.listcapacityresponse.capacity, function(i, capacity) { - // CPU - if (capacity.type == 1) { - items[idx].cputotal = parseInt(capacity.capacitytotal)/1000.0; - } - // Memory - if (capacity.type == 0) { - items[idx].memtotal = parseInt(capacity.capacitytotal)/(1024.0*1024.0*1024.0); - } - }); - } - }, - async: false - }); - - if (items[idx].hosts != 0) { - items[idx].cpuusedavg = (items[idx].cpuusedavg / items[idx].hosts); - items[idx].cpumaxdev = (items[idx].maxCpuUsed - items[idx].cpuusedavg); - items[idx].cpuallocated = (items[idx].cpuallocated / items[idx].hosts); - - items[idx].memusedavg = (items[idx].memusedavg / items[idx].hosts); - items[idx].memmaxdev = (items[idx].maxMemUsed - items[idx].memusedavg); - items[idx].memallocated = (items[idx].memallocated / items[idx].hosts); - } - // Format data - items[idx].cpuusedavg = (items[idx].cpuusedavg).toFixed(2) + "%"; - items[idx].cpumaxdev = (items[idx].cpumaxdev).toFixed(2) + "%"; - items[idx].cpuallocated = (items[idx].cpuallocated).toFixed(2) + "%"; - items[idx].cputotal = (items[idx].cputotal).toFixed(2) + " Ghz"; - - items[idx].memusedavg = (items[idx].memusedavg).toFixed(2) + "%"; - items[idx].memmaxdev = (items[idx].memmaxdev).toFixed(2) + "%"; - items[idx].memallocated = (items[idx].memallocated).toFixed(2) + "%"; - items[idx].memtotal = (items[idx].memtotal).toFixed(2) + " GB"; - - items[idx].clusters = items[idx].clustersUp + ' / ' + items[idx].clusters; - items[idx].state = items[idx].allocationstate; - }); - } args.response.success({ - data: items + data: json.listzonesmetricsresponse.zone }); } }); @@ -290,15 +172,15 @@ label: 'label.metrics.cpu.usage', collapsible: true, columns: { - cpuusedavg: { + cpuused: { label: 'label.metrics.cpu.used.avg', thresholdcolor: true, thresholds: { - notification: 'cpunotificationthreshold', + notification: 'cputhreshold', disable: 'cpudisablethreshold' } }, - cpumaxdev: { + cpumaxdeviation: { label: 'label.metrics.cpu.max.dev' } } @@ -311,8 +193,8 @@ label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'cpunotificationthreshold', - disable: 'cpudisablethreshold' + notification: 'cpuallocatedthreshold', + disable: 'cpuallocateddisablethreshold' } }, cputotal: { @@ -324,15 +206,15 @@ label: 'label.metrics.memory.usage', collapsible: true, columns: { - memusedavg: { + memoryused: { label: 'label.metrics.memory.used.avg', thresholdcolor: true, thresholds: { - notification: 'memnotificationthreshold', - disable: 'memdisablethreshold' + notification: 'memorythreshold', + disable: 'memorydisablethreshold' } }, - memmaxdev: { + memorymaxdeviation: { label: 'label.metrics.memory.max.dev' } } @@ -341,15 +223,15 @@ label: 'label.metrics.memory.allocated', collapsible: true, columns: { - memallocated: { + memoryallocated: { label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'memnotificationthreshold', - disable: 'memdisablethreshold' + notification: 'memoryallocatedthreshold', + disable: 'memoryallocateddisablethreshold' } }, - memtotal: { + memorytotal: { label: 'label.metrics.memory.total' } } @@ -372,154 +254,11 @@ } $.ajax({ - url: createURL('listClusters'), + url: createURL('listClustersMetrics'), data: data, success: function(json) { - var items = json.listclustersresponse.cluster; - if (items) { - $.each(items, function(idx, cluster) { - items[idx].hosts = 0; - items[idx].hostsUp = 0; - items[idx].cpuusedavg = 0.0; - items[idx].cpumaxdev = 0.0; - items[idx].cpuallocated = 0.0; - items[idx].cputotal = 0.0; - items[idx].maxCpuUsed = 0; - items[idx].memusedavg = 0.0; - items[idx].memmaxdev = 0.0; - items[idx].memallocated = 0.0; - items[idx].memtotal = 0.0; - items[idx].maxMemUsed = 0.0; - - // Threshold color coding - items[idx].cpunotificationthreshold = 75.0; - items[idx].cpudisablethreshold = 95.0; - items[idx].memnotificationthreshold = 75.0; - items[idx].memdisablethreshold = 95.0; - - $.ajax({ - url: createURL('listConfigurations'), - data: {clusterid: cluster.id, listAll: true}, - success: function(json) { - if (json.listconfigurationsresponse && json.listconfigurationsresponse.configuration) { - $.each(json.listconfigurationsresponse.configuration, function(i, config) { - switch (config.name) { - case 'cluster.cpu.allocated.capacity.disablethreshold': - items[idx].cpudisablethreshold = 100 * parseFloat(config.value); - break; - case 'cluster.cpu.allocated.capacity.notificationthreshold': - items[idx].cpunotificationthreshold = 100 * parseFloat(config.value); - break; - case 'cluster.memory.allocated.capacity.disablethreshold': - items[idx].memdisablethreshold = 100 * parseFloat(config.value); - break; - case 'cluster.memory.allocated.capacity.notificationthreshold': - items[idx].memnotificationthreshold = 100 * parseFloat(config.value); - break; - } - }); - } - }, - async: false - }); - - $.ajax({ - url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, - success: function(json) { - if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { - items[idx].hosts += parseInt(json.listhostsresponse.count); - $.each(json.listhostsresponse.host, function(i, host) { - if (host.state == 'Up') { - items[idx].hostsUp += 1; - } - if (host.hasOwnProperty('cpuused')) { - var hostCpuUsage = parseFloat(host.cpuused); - items[idx].cpuusedavg += hostCpuUsage; - if (hostCpuUsage > items[idx].maxCpuUsed) { - items[idx].maxCpuUsed = hostCpuUsage; - } - } - - if (host.hasOwnProperty('cpuallocated')) { - items[idx].cpuallocated += parseFloat(host.cpuallocated.replace('%', '')); - } - - if (host.hasOwnProperty('memoryused')) { - var hostMemoryUsage = 100.0 * parseFloat(host.memoryused) / parseFloat(host.memorytotal); - items[idx].memusedavg += hostMemoryUsage; - if (hostMemoryUsage > items[idx].maxMemUsed) { - items[idx].maxMemUsed = hostMemoryUsage; - } - } - - if (host.hasOwnProperty('memoryallocated')) { - items[idx].memallocated += parseFloat(100.0 * parseFloat(host.memoryallocated)/parseFloat(host.memorytotal)); - } - }); - } - }, - async: false - }); - - $.ajax({ - url: createURL('listCapacity'), - data: {clusterid: cluster.id}, - success: function(json) { - if (json && json.listcapacityresponse && json.listcapacityresponse.capacity) { - $.each(json.listcapacityresponse.capacity, function(i, capacity) { - // CPU - if (capacity.type == 1) { - items[idx].cputotal = parseInt(capacity.capacitytotal)/1000.0; - } - // Memory - if (capacity.type == 0) { - items[idx].memtotal = parseInt(capacity.capacitytotal)/(1024.0*1024.0*1024.0); - } - }); - } - }, - async: false - }); - - if (items[idx].hosts != 0) { - items[idx].cpuusedavg = (items[idx].cpuusedavg / items[idx].hosts); - items[idx].cpumaxdev = (items[idx].maxCpuUsed - items[idx].cpuusedavg); - items[idx].cpuallocated = (items[idx].cpuallocated / items[idx].hosts); - - items[idx].memusedavg = (items[idx].memusedavg / items[idx].hosts); - items[idx].memmaxdev = (items[idx].maxMemUsed - items[idx].memusedavg); - items[idx].memallocated = (items[idx].memallocated / items[idx].hosts); - } - - // Format data - items[idx].cpuusedavg = (items[idx].cpuusedavg).toFixed(2) + "%"; - items[idx].cpumaxdev = (items[idx].cpumaxdev).toFixed(2) + "%"; - items[idx].cpuallocated = (items[idx].cpuallocated).toFixed(2) + "%"; - items[idx].cputotal = (items[idx].cputotal).toFixed(2) + " Ghz"; - - items[idx].memusedavg = (items[idx].memusedavg).toFixed(2) + "%"; - items[idx].memmaxdev = (items[idx].memmaxdev).toFixed(2) + "%"; - items[idx].memallocated = (items[idx].memallocated).toFixed(2) + "%"; - items[idx].memtotal = (items[idx].memtotal).toFixed(2) + " GB"; - items[idx].hosts = items[idx].hostsUp + ' / ' + items[idx].hosts; - - items[idx].state = items[idx].allocationstate; - if (items[idx].managedstate == 'Unmanaged') { - items[idx].state = 'Unmanaged'; - } - - if (items[idx].managedstate == 'Managed' && items[idx].allocationstate == 'Enabled') { - items[idx].state = 'Enabled'; - } - - if (items[idx].managedstate == 'Managed' && items[idx].allocationstate == 'Disabled') { - items[idx].state = 'Disabled'; - } - }); - } args.response.success({ - data: items + data: json.listclustersmetricsresponse.cluster }); } }); @@ -560,7 +299,7 @@ }, compact: true }, - outofbandmanagementpowerstate: { + powerstate: { label: 'label.metrics.outofbandmanagementpowerstate', converter: function (str) { // For localization @@ -580,25 +319,25 @@ label: 'label.metrics.cpu.usage', collapsible: true, columns: { - cores: { - label: 'label.metrics.num.cpu.cores' + cpunumber: { + label: 'label.metrics.num.cpu.cores', }, - cputotal: { + cputotalghz: { label: 'label.metrics.cpu.total' }, - cpuusedavg: { + cpuusedghz: { label: 'label.metrics.cpu.used.avg', thresholdcolor: true, thresholds: { - notification: 'cpunotificationthreshold', + notification: 'cputhreshold', disable: 'cpudisablethreshold' } }, - cpuallocated: { + cpuallocatedghz: { label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'cpuallocatednotificationthreshold', + notification: 'cpuallocatedthreshold', disable: 'cpuallocateddisablethreshold' } } @@ -608,23 +347,23 @@ label: 'label.metrics.memory.usage', collapsible: true, columns: { - memtotal: { + memorytotalgb: { label: 'label.metrics.memory.total' }, - memusedavg: { + memoryusedgb: { label: 'label.metrics.memory.used.avg', thresholdcolor: true, thresholds: { - notification: 'memnotificationthreshold', - disable: 'memdisablethreshold' + notification: 'memorythreshold', + disable: 'memorydisablethreshold' } }, - memallocated: { + memoryallocatedgb: { label: 'label.metrics.allocated', thresholdcolor: true, thresholds: { - notification: 'memallocatednotificationthreshold', - disable: 'memallocateddisablethreshold' + notification: 'memoryallocatedthreshold', + disable: 'memoryallocateddisablethreshold' } } } @@ -670,123 +409,11 @@ } $.ajax({ - url: createURL('listHosts'), + url: createURL('listHostsMetrics'), data: data, success: function(json) { - var items = json.listhostsresponse.host; - if (items) { - $.each(items, function(idx, host) { - if (host && host.outofbandmanagement) { - items[idx].outofbandmanagementpowerstate = host.outofbandmanagement.powerstate; - } - items[idx].cores = host.cpunumber; - items[idx].cputotal = (parseFloat(host.cpunumber) * parseFloat(host.cpuspeed) / 1000.0).toFixed(2); - if (host.cpuused) { - items[idx].cpuusedavg = (parseFloat(host.cpuused) * items[idx].cputotal / 100.0).toFixed(2) + ' Ghz'; - } else { - items[idx].cpuusedavg = ''; - } - items[idx].cpuallocated = (parseFloat(host.cpuallocated) * items[idx].cputotal / 100.0).toFixed(2) + ' Ghz'; - items[idx].memtotal = (parseFloat(host.memorytotal)/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - items[idx].memallocated = (parseFloat(host.memoryallocated)/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - if (host.memoryused) { - items[idx].memusedavg = (parseFloat(host.memoryused)/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - } else { - items[idx].memusedavg = ''; - } - if (host.networkkbsread && host.networkkbswrite) { - items[idx].networkread = (parseFloat(host.networkkbsread)/(1024.0*1024.0)).toFixed(2) + ' GB'; - items[idx].networkwrite = (parseFloat(host.networkkbswrite)/(1024.0*1024.0)).toFixed(2) + ' GB'; - } else { - items[idx].networkread = ''; - items[idx].networkwrite = ''; - } - - var cpuOverCommit = 1.0; - var memOverCommit = 1.0; - $.ajax({ - url: createURL('listClusters'), - data: {clusterid: host.clusterid, listAll: true}, - success: function(json) { - if (json.listclustersresponse && json.listclustersresponse.cluster) { - var cluster = json.listclustersresponse.cluster[0]; - cpuOverCommit = parseFloat(cluster.cpuovercommitratio); - memOverCommit = parseFloat(cluster.memoryovercommitratio); - } - }, - async: false - }); - - // Threshold color coding - items[idx].cpunotificationthreshold = 0.75 * parseFloat(items[idx].cputotal); - items[idx].cpudisablethreshold = 0.95 * parseFloat(items[idx].cputotal); - items[idx].cpuallocatednotificationthreshold = 0.75 * cpuOverCommit * parseFloat(items[idx].cputotal); - items[idx].cpuallocateddisablethreshold = 0.95 * cpuOverCommit * parseFloat(items[idx].cputotal); - - items[idx].memnotificationthreshold = 0.75 * parseFloat(items[idx].memtotal); - items[idx].memdisablethreshold = 0.95 * parseFloat(items[idx].memtotal); - items[idx].memallocatednotificationthreshold = 0.75 * memOverCommit * parseFloat(items[idx].memtotal); - items[idx].memallocateddisablethreshold = 0.95 * memOverCommit * parseFloat(items[idx].memtotal); - - $.ajax({ - url: createURL('listConfigurations'), - data: {clusterid: host.clusterid, listAll: true}, - success: function(json) { - if (json.listconfigurationsresponse && json.listconfigurationsresponse.configuration) { - $.each(json.listconfigurationsresponse.configuration, function(i, config) { - switch (config.name) { - case 'cluster.cpu.allocated.capacity.disablethreshold': - items[idx].cpudisablethreshold = parseFloat(config.value) * parseFloat(items[idx].cputotal); - items[idx].cpuallocateddisablethreshold = parseFloat(config.value) * cpuOverCommit * parseFloat(items[idx].cputotal); - break; - case 'cluster.cpu.allocated.capacity.notificationthreshold': - items[idx].cpunotificationthreshold = parseFloat(config.value) * parseFloat(items[idx].cputotal); - items[idx].cpuallocatednotificationthreshold = parseFloat(config.value) * cpuOverCommit * parseFloat(items[idx].cputotal); - break; - case 'cluster.memory.allocated.capacity.disablethreshold': - items[idx].memdisablethreshold = parseFloat(config.value) * parseFloat(items[idx].memtotal); - items[idx].memallocateddisablethreshold = parseFloat(config.value) * memOverCommit * parseFloat(items[idx].memtotal); - break; - case 'cluster.memory.allocated.capacity.notificationthreshold': - items[idx].memnotificationthreshold = parseFloat(config.value) * parseFloat(items[idx].memtotal); - items[idx].memallocatednotificationthreshold = parseFloat(config.value) * memOverCommit * parseFloat(items[idx].memtotal); - break; - } - }); - } - }, - async: false - }); - - - items[idx].cputotal = items[idx].cputotal + ' Ghz (x' + cpuOverCommit + ')'; - items[idx].memtotal = items[idx].memtotal + ' (x' + memOverCommit + ')'; - - items[idx].instances = 0; - items[idx].instancesUp = 0; - $.ajax({ - url: createURL('listVirtualMachines'), - data: {hostid: host.id, listAll: true}, - success: function(json) { - if (json && json.listvirtualmachinesresponse && json.listvirtualmachinesresponse.virtualmachine) { - var vms = json.listvirtualmachinesresponse.virtualmachine; - if (vms) { - $.each(vms, function(_, vm) { - items[idx].instances += 1; - if (vm.state == 'Running') { - items[idx].instancesUp += 1; - } - }); - } - } - }, - async: false - }); - items[idx].instances = items[idx].instancesUp + ' / ' + items[idx].instances; - }); - } args.response.success({ - data: items + data: json.listhostsmetricsresponse.host }); } }); @@ -838,14 +465,14 @@ label: 'label.metrics.cpu.usage', collapsible: true, columns: { - cores: { - label: 'label.metrics.num.cpu.cores' + cpunumber: { + label: 'label.metrics.num.cpu.cores', }, cputotal: { label: 'label.metrics.cpu.total' }, cpuused: { - label: 'label.metrics.cpu.used.avg' + label: 'label.metrics.cpu.used.avg', } } }, @@ -853,7 +480,7 @@ label: 'label.metrics.memory.usage', collapsible: true, columns: { - memallocated: { + memorytotal: { label: 'label.metrics.allocated' } } @@ -874,10 +501,10 @@ label: 'label.metrics.disk.usage', collapsible: true, columns: { - diskread: { + diskioread: { label: 'label.metrics.disk.read' }, - diskwrite: { + diskiowrite: { label: 'label.metrics.disk.write' }, diskiopstotal: { @@ -899,45 +526,11 @@ } $.ajax({ - url: createURL('listVirtualMachines'), + url: createURL('listVirtualMachinesMetrics'), data: data, success: function(json) { - var items = []; - if (json && json.listvirtualmachinesresponse && json.listvirtualmachinesresponse.virtualmachine) { - items = json.listvirtualmachinesresponse.virtualmachine; - $.each(items, function(idx, vm) { - items[idx].cores = vm.cpunumber; - items[idx].cputotal = (parseFloat(vm.cpunumber) * parseFloat(vm.cpuspeed) / 1000.0).toFixed(1) + ' Ghz'; - items[idx].cpuusedavg = vm.cpuused; - items[idx].cpuallocated = vm.cpuallocated; - items[idx].memallocated = (parseFloat(vm.memory)/1024.0).toFixed(2) + ' GB'; - items[idx].networkread = (parseFloat(vm.networkkbsread)/(1024.0)).toFixed(2) + ' MB'; - items[idx].networkwrite = (parseFloat(vm.networkkbswrite)/(1024.0)).toFixed(2) + ' MB'; - items[idx].diskread = (parseFloat(vm.diskkbsread)/(1024.0)).toFixed(2) + ' MB'; - items[idx].diskwrite = (parseFloat(vm.diskkbswrite)/(1024.0)).toFixed(2) + ' MB'; - items[idx].diskiopstotal = parseFloat(vm.diskioread) + parseFloat(vm.diskiowrite); - if (vm.nic && vm.nic.length > 0 && vm.nic[0].ipaddress) { - items[idx].ipaddress = vm.nic[0].ipaddress; - } - - var keys = [{'cpuused': 'cpuusedavg'}, - {'networkkbsread': 'networkread'}, - {'networkkbswrite': 'networkwrite'}, - {'diskkbsread': 'diskread'}, - {'diskkbswrite': 'diskwrite'}, - {'diskioread': 'diskiopstotal'}]; - for (keyIdx in keys) { - var map = keys[keyIdx]; - var key = Object.keys(map)[0]; - var uiKey = map[key]; - if (!vm.hasOwnProperty(key)) { - items[idx][uiKey] = ''; - } - } - }); - } args.response.success({ - data: items + data: json.listvirtualmachinesmetricsresponse.virtualmachine }); } }); @@ -974,22 +567,22 @@ 'Expunging': 'off', 'Migrating': 'warning', 'UploadOp': 'transition', - 'Snapshotting': 'warning' + 'Snapshotting': 'warning', }, compact: true }, vmname: { label: 'label.metrics.vm.name' }, - disksize: { + sizegb: { label: 'label.metrics.disk.size' }, storagetype: { label: 'label.metrics.disk.storagetype' }, - storagepool: { + storage: { label: 'label.metrics.storagepool' - } + }, }, dataProvider: function(args) { var data = {listAll: true}; @@ -1008,25 +601,11 @@ } $.ajax({ - url: createURL('listVolumes'), + url: createURL('listVolumesMetrics'), data: data, success: function(json) { - var items = []; - if (json && json.listvolumesresponse && json.listvolumesresponse.volume) { - items = json.listvolumesresponse.volume; - $.each(items, function(idx, volume) { - items[idx].name = volume.name; - items[idx].state = volume.state; - items[idx].vmname = volume.vmname; - items[idx].disksize = parseFloat(volume.size)/(1024.0*1024.0*1024.0) + ' GB'; - items[idx].storagetype = volume.storagetype.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) + ' (' + volume.type + ')'; - if (volume.storage) { - items[idx].storagepool = volume.storage; - } - }); - } args.response.success({ - data: items + data: json.listvolumesmetricsresponse.volume }); } }); @@ -1062,7 +641,7 @@ 'ErrorInMaintenance': 'off', 'PrepareForMaintenance': 'transition', 'CancelMaintenance': 'warning', - 'Maintenance': 'warning' + 'Maintenance': 'warning', }, compact: true }, @@ -1078,26 +657,26 @@ label: 'label.metrics.disk', collapsible: true, columns: { - disksizeused: { + disksizeusedgb: { label: 'label.metrics.disk.used', thresholdcolor: true, thresholds: { - notification: 'storagenotificationthreshold', - disable: 'storagedisablethreshold' + notification: 'storageusagethreshold', + disable: 'storageusagedisablethreshold' } }, - disksizetotal: { + disksizetotalgb: { label: 'label.metrics.disk.total' }, - disksizeallocated: { + disksizeallocatedgb: { label: 'label.metrics.disk.allocated', thresholdcolor: true, thresholds: { - notification: 'storageallocatednotificationthreshold', + notification: 'storageallocatedthreshold', disable: 'storageallocateddisablethreshold' } }, - disksizeunallocated: { + disksizeunallocatedgb: { label: 'label.metrics.disk.unallocated' } } @@ -1124,74 +703,11 @@ } $.ajax({ - url: createURL('listStoragePools'), + url: createURL('listStoragePoolsMetrics'), data: data, success: function(json) { - var items = []; - if (json && json.liststoragepoolsresponse && json.liststoragepoolsresponse.storagepool) { - items = json.liststoragepoolsresponse.storagepool; - $.each(items, function(idx, pool) { - items[idx].name = pool.name; - items[idx].state = pool.state; - items[idx].scope = pool.scope; - items[idx].type = pool.type; - items[idx].overprovisionfactor = parseFloat(pool.overprovisionfactor); - if (pool.disksizeused) { - items[idx].disksizeused = (parseFloat(pool.disksizeused)/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - } else { - items[idx].disksizeused = ''; - } - items[idx].disksizetotal = parseFloat(pool.disksizetotal); - items[idx].disksizeallocated = parseFloat(pool.disksizeallocated); - items[idx].disksizeunallocated = (items[idx].overprovisionfactor * items[idx].disksizetotal) - items[idx].disksizeallocated; - - // Format presentation - items[idx].disksizetotal = (items[idx].disksizetotal/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB (x' + items[idx].overprovisionfactor + ')'; - items[idx].disksizeallocated = (items[idx].disksizeallocated/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - items[idx].disksizeunallocated = (items[idx].disksizeunallocated/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'; - - // Threshold color coding - items[idx].storagenotificationthreshold = 0.75 * parseFloat(items[idx].disksizetotal); - items[idx].storagedisablethreshold = 0.95 * parseFloat(items[idx].disksizetotal); - items[idx].storageallocatednotificationthreshold = 0.75 * parseFloat(items[idx].disksizetotal) * items[idx].overprovisionfactor; - items[idx].storageallocateddisablethreshold = 0.95 * parseFloat(items[idx].disksizetotal) * items[idx].overprovisionfactor; - - - var getThresholds = function(data, items, idx) { - data.listAll = true; - $.ajax({ - url: createURL('listConfigurations'), - data: data, - success: function(json) { - if (json.listconfigurationsresponse && json.listconfigurationsresponse.configuration) { - $.each(json.listconfigurationsresponse.configuration, function(i, config) { - switch (config.name) { - case 'cluster.storage.allocated.capacity.notificationthreshold': - items[idx].storageallocatednotificationthreshold = parseFloat(config.value) * items[idx].overprovisionfactor * parseFloat(items[idx].disksizetotal); - break; - case 'cluster.storage.capacity.notificationthreshold': - items[idx].storagenotificationthreshold = parseFloat(config.value) * parseFloat(items[idx].disksizetotal); - break; - case 'pool.storage.allocated.capacity.disablethreshold': - items[idx].storageallocateddisablethreshold = parseFloat(config.value) * items[idx].overprovisionfactor * parseFloat(items[idx].disksizetotal); - break; - case 'pool.storage.capacity.disablethreshold': - items[idx].storagedisablethreshold = parseFloat(config.value) * parseFloat(items[idx].disksizetotal); - break; - } - }); - } - }, - async: false - }); - }; - // Update global and cluster level thresholds - getThresholds({}, items, idx); - getThresholds({clusterid: pool.clusterid}, items, idx); - }); - } args.response.success({ - data: items + data: json.liststoragepoolsmetricsresponse.storagepool }); } }); diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 98403ed9cf6..682e0a2263a 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -225,322 +225,25 @@ // System dashboard dashboard: { dataProvider: function (args) { - var dataFns = { - zoneCount: function (data) { - $.ajax({ - url: createURL('listZones'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, - success: function (json) { - args.response.success({ - data: { - zoneCount: json.listzonesresponse.count ? json.listzonesresponse.count: 0, - zones: json.listzonesresponse.zone - } - }); - } + $.ajax({ + url: createURL('listInfrastructure'), + success: function (json) { + var response = json.listinfrastructureresponse.infrastructure; + var data = {}; + data.zoneCount = response.zones; + data.podCount = response.pods; + data.clusterCount = response.clusters; + data.hostCount = response.hosts; + data.primaryStorageCount = response.storagepools; + data.secondaryStorageCount = response.imagestores; + data.systemVmCount = response.systemvms; + data.virtualRouterCount = response.routers; + data.socketCount = response.cpusockets; + args.response.success({ + data: data }); - dataFns.podCount(); - }, - - podCount: function (data) { - $.ajax({ - url: createURL('listPods'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, - success: function (json) { - args.response.success({ - data: { - podCount: json.listpodsresponse.count ? json.listpodsresponse.count: 0 - } - }); - } - }); - dataFns.clusterCount(); - }, - - clusterCount: function (data) { - $.ajax({ - url: createURL('listClusters'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, - success: function (json) { - args.response.success({ - data: { - clusterCount: json.listclustersresponse.count ? json.listclustersresponse.count: 0 - } - }); - } - }); - dataFns.hostCount(); - }, - - hostCount: function (data) { - var data2 = { - type: 'routing', - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }; - $.ajax({ - url: createURL('listHosts'), - data: data2, - success: function (json) { - args.response.success({ - data: { - hostCount: json.listhostsresponse.count ? json.listhostsresponse.count: 0 - } - }); - } - }); - dataFns.primaryStorageCount(); - }, - - primaryStorageCount: function (data) { - var data2 = { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }; - $.ajax({ - url: createURL('listStoragePools'), - data: data2, - success: function (json) { - args.response.success({ - data: { - primaryStorageCount: json.liststoragepoolsresponse.count ? json.liststoragepoolsresponse.count: 0 - } - }); - } - }); - dataFns.secondaryStorageCount(); - }, - - secondaryStorageCount: function (data) { - var data2 = { - type: 'SecondaryStorage', - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }; - $.ajax({ - url: createURL('listImageStores'), - data: data2, - success: function (json) { - args.response.success({ - data: { - secondaryStorageCount: json.listimagestoresresponse.imagestore ? json.listimagestoresresponse.count: 0 - } - }); - } - }); - dataFns.systemVmCount(); - }, - - systemVmCount: function (data) { - $.ajax({ - url: createURL('listSystemVms'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, - success: function (json) { - args.response.success({ - data: { - systemVmCount: json.listsystemvmsresponse.count ? json.listsystemvmsresponse.count: 0 - } - }); - } - }); - dataFns.virtualRouterCount(); - }, - - virtualRouterCount: function (data) { - var data2 = { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }; - $.ajax({ - url: createURL('listRouters'), - data: data2, - success: function (json) { - var total1 = json.listroutersresponse.count ? json.listroutersresponse.count: 0; - var total2 = 0; //reset - - /* - * In project view, the first listRotuers API(without projectid=-1) will return the same objects as the second listRouters API(with projectid=-1), - * because in project view, all API calls are appended with projectid=[projectID]. - * Therefore, we only call the second listRouters API(with projectid=-1) in non-project view. - */ - if (cloudStack.context && cloudStack.context.projects == null) { //non-project view - var data3 = { - listAll: true, - projectid: -1, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }; - $.ajax({ - url: createURL('listRouters'), - data: data3, - async: false, - success: function (json) { - total2 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; - } - }); - } - - args.response.success({ - data: { - virtualRouterCount: (total1 + total2) - } - }); - } - }); - dataFns.capacity(); - }, - - capacity: function (data) { - $.ajax({ - url: createURL('listCapacity'), - success: function (json) { - var capacities = json.listcapacityresponse.capacity; - if(capacities) { - var capacityTotal = function (id, converter) { - var capacity = $.grep(capacities, function (capacity) { - return capacity.type == id; - })[0]; - - var total = capacity ? capacity.capacitytotal: 0; - - if (converter) { - return converter(total); - } - - return total; - }; - - args.response.success({ - data: { - cpuCapacityTotal: capacityTotal(1, cloudStack.converters.convertHz), - memCapacityTotal: capacityTotal(0, cloudStack.converters.convertBytes), - storageCapacityTotal: capacityTotal(2, cloudStack.converters.convertBytes) - } - }); - - } else { - - args.response.success({ - data: { - cpuCapacityTotal: cloudStack.converters.convertHz(0), - memCapacityTotal: cloudStack.converters.convertBytes(0), - storageCapacityTotal: cloudStack.converters.convertBytes(0) - } - }); - - } - } - }); - - dataFns.socketInfo(); - }, - - socketInfo: function (data) { - var socketCount = 0; - - function listHostFunction(hypervisor, pageSizeValue) { - var deferred = $.Deferred(); - var totalHostCount = 0; - var returnedHostCount = 0; - var returnedHostCpusocketsSum = 0; - - var callListHostsWithPage = function(page) { - $.ajax({ - url: createURL('listHosts'), - data: { - type: 'routing', - hypervisor: hypervisor, - page: page, - details: 'min', - pagesize: pageSizeValue - }, - success: function (json) { - if (json.listhostsresponse.count == undefined) { - deferred.resolve(); - return; - } - - totalHostCount = json.listhostsresponse.count; - returnedHostCount += json.listhostsresponse.host.length; - - var items = json.listhostsresponse.host; - for (var i = 0; i < items.length; i++) { - if (items[i].cpusockets != undefined && isNaN(items[i].cpusockets) == false) { - returnedHostCpusocketsSum += items[i].cpusockets; - } - } - - if (returnedHostCount < totalHostCount) { - callListHostsWithPage(++page); - } else { - socketCount += returnedHostCpusocketsSum; - deferred.resolve(); - } - } - }); - } - - callListHostsWithPage(1); - - return deferred; - - } - - $.ajax({ - url: createURL('listConfigurations'), - data: { - name : 'default.page.size' - }, - success: function (json) { - pageSizeValue = json.listconfigurationsresponse.configuration[0].value; - if(!pageSizeValue) { - return; - } - $.ajax({ - url: createURL('listHypervisors'), - success: function (json) { - var deferredArray = []; - - $(json.listhypervisorsresponse.hypervisor).map(function (index, hypervisor) { - deferredArray.push(listHostFunction(hypervisor.name, pageSizeValue)); - }); - - $.when.apply(null, deferredArray).then(function(){ - args.response.success({ - data: { - socketCount: socketCount - } - }); - }); - } - }); - } - }); - } - }; - - dataFns.zoneCount(); + }); } }, diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index e61f43c8372..fed61943861 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -1245,12 +1245,11 @@ if (field.thresholdcolor && field.thresholds) { if ((field.thresholds.disable in dataItem) && (field.thresholds.notification in dataItem)) { - var disableThreshold = parseFloat(dataItem[field.thresholds.disable]); - var notificationThreshold = parseFloat(dataItem[field.thresholds.notification]); - var value = parseFloat(content); - if (value >= disableThreshold) { + var disableThreshold = dataItem[field.thresholds.disable]; + var notificationThreshold = dataItem[field.thresholds.notification]; + if (disableThreshold) { $td.addClass('alert-disable-threshold'); - } else if (value >= notificationThreshold) { + } else if (notificationThreshold) { $td.addClass('alert-notification-threshold'); } }