File indexing completed on 2025-03-02 05:29:46

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Service_Amazon
0017  * @subpackage Ec2
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * @see Zend_Service_Amazon_Ec2_Abstract
0025  */
0026 // require_once 'Zend/Service/Amazon/Ec2/Abstract.php';
0027 
0028 /**
0029  * An Amazon EC2 interface that allows yout to run, terminate, reboot and describe Amazon
0030  * Ec2 Instances.
0031  *
0032  * @category   Zend
0033  * @package    Zend_Service_Amazon
0034  * @subpackage Ec2
0035  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0036  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0037  */
0038 class Zend_Service_Amazon_Ec2_CloudWatch extends Zend_Service_Amazon_Ec2_Abstract
0039 {
0040     /**
0041      * The HTTP query server
0042      */
0043     protected $_ec2Endpoint = 'monitoring.amazonaws.com';
0044 
0045     /**
0046      * The API version to use
0047      */
0048     protected $_ec2ApiVersion = '2009-05-15';
0049 
0050     /**
0051      * XML Namespace for the CloudWatch Stuff
0052      */
0053     protected $_xmlNamespace = 'http://monitoring.amazonaws.com/doc/2009-05-15/';
0054 
0055     /**
0056      * The following metrics are available from each EC2 instance.
0057      *
0058      * CPUUtilization: The percentage of allocated EC2 compute units that are
0059      *  currently in use on the instance. This metric identifies the processing
0060      *  power required to run an application upon a selected instance.
0061      *
0062      * NetworkIn: The number of bytes received on all network interfaces by
0063      *  the instance. This metric identifies the volume of incoming network
0064      *  traffic to an application on a single instance.
0065      *
0066      * NetworkOut: The number of bytes sent out on all network interfaces
0067      *  by the instance. This metric identifies the volume of outgoing network
0068      *  traffic to an application on a single instance.
0069      *
0070      * DiskWriteOps: Completed write operations to all hard disks available to
0071      *  the instance. This metric identifies the rate at which an application
0072      *  writes to a hard disk. This can be used to determine the speed in which
0073      *  an application saves data to a hard disk.
0074      *
0075      * DiskReadBytes: Bytes read from all disks available to the instance. This
0076      *  metric is used to determine the volume of the data the application reads
0077      *  from the hard disk of the instance. This can be used to determine the
0078      *  speed of the application for the customer.
0079      *
0080      * DiskReadOps: Completed read operations from all disks available to the
0081      *  instances. This metric identifies the rate at which an application reads
0082      *  a disk. This can be used to determine the speed in which an application
0083      *  reads data from a hard disk.
0084      *
0085      * DiskWriteBytes: Bytes written to all disks available to the instance. This
0086      *  metric is used to determine the volume of the data the application writes
0087      *  onto the hard disk of the instance. This can be used to determine the speed
0088      *  of the application for the customer.
0089      *
0090      * Latency: Time taken between a request and the corresponding response as seen
0091      *  by the load balancer.
0092      *
0093      * RequestCount: The number of requests processed by the LoadBalancer.
0094      *
0095      * HealthyHostCount: The number of healthy instances. Both Load Balancing dimensions,
0096      *  LoadBalancerName and AvailabilityZone, should be specified when retreiving
0097      *  HealthyHostCount.
0098      *
0099      * UnHealthyHostCount: The number of unhealthy instances. Both Load Balancing dimensions,
0100      *  LoadBalancerName and AvailabilityZone, should be specified when retreiving
0101      *  UnHealthyHostCount.
0102      *
0103      * Amazon CloudWatch data for a new EC2 instance becomes available typically
0104      * within one minute of the end of the first aggregation period for the new
0105      * instance. You can use the currently available dimensions for EC2 instances
0106      * along with these metrics in order to refine the slice of data you want returned,
0107      * such as metric CPUUtilization and dimension ImageId to get all CPUUtilization
0108      * data for instances using the specified AMI.
0109      *
0110      * @var array
0111      */
0112     protected $_validMetrics = array('CPUUtilization', 'NetworkIn', 'NetworkOut',
0113                                     'DiskWriteOps', 'DiskReadBytes', 'DiskReadOps',
0114                                     'DiskWriteBytes', 'Latency', 'RequestCount',
0115                                     'HealthyHostCount', 'UnHealthyHostCount');
0116 
0117     /**
0118      * Amazon CloudWatch not only aggregates the raw data coming in, it also computes
0119      * several statistics on the data. The following table lists the statistics that you can request:
0120      *
0121      * Minimum: The lowest value observed during the specified period. This can be used to
0122      *  determine low volumes of activity for your application.
0123      *
0124      * Maximum: The highest value observed during the specified period. You can use this to
0125      *  determine high volumes of activity for your application.
0126      *
0127      * Sum: The sum of all values received (if appropriate, for example a rate would not be
0128      *  summed, but a number of items would be). This statistic is useful for determining
0129      *  the total volume of a metric.
0130      *
0131      * Average: The Average of all values received during the specified period. By comparing
0132      *  this statistic with the minimum and maximum statistics, you can determine the full
0133      *  scope of a metric and how close the average use is to the minimum and the maximum.
0134      *  This will allow you to increase or decrease your resources as needed.
0135      *
0136      * Samples: The count (number) of measures used. This statistic is always returned to
0137      *  show the user the size of the dataset collected. This will allow the user to properly
0138      *  weight the data.
0139      *
0140      * Statistics are computed within a period you specify, such as all CPUUtilization within a
0141      * five minute period. At a minimum, all data is aggregated into one minute intervals. This
0142      * is the minimum resolution of the data. It is this data that can be aggregated into larger
0143      * periods of time that you request.
0144      *
0145      * Aggregate data is generally available from the service within one minute from the end of the
0146      * aggregation period. Delays in data propagation might cause late or partially late data in
0147      * some cases. If your data is delayed, you should check the service’s Health Dashboard for
0148      * any current operational issues with either Amazon CloudWatch or the services collecting
0149      * the data, such as EC2 or Elastic Load Balancing.
0150      *
0151      * @var array
0152      */
0153     protected $_validStatistics = array('Average', 'Maximum', 'Minimum', 'Samples', 'Sum');
0154 
0155     /**
0156      * Valid Dimention Keys for getMetricStatistics
0157      *
0158      * ImageId: This dimension filters the data you request for all instances running
0159      *  this EC2 Amazon Machine Image (AMI).
0160      *
0161      * AvailabilityZone: This dimension filters the data you request for all instances
0162      *  running in that EC2 Availability Zone.
0163      *
0164      * AutoScalingGroupName: This dimension filters the data you request for all instances
0165      *  in a specified capacity group. An AutoScalingGroup is a collection of instances
0166      *  defined by customers of the Auto Scaling service. This dimension is only available
0167      *  for EC2 metrics when the instances are in such an AutoScalingGroup.
0168      *
0169      * InstanceId: This dimension filters the data you request for only the identified
0170      *  instance. This allows a user to pinpoint an exact instance from which to monitor data.
0171      *
0172      * InstanceType: This dimension filters the data you request for all instances running
0173      *  with this specified instance type. This allows a user to catagorize his data by the
0174      *  type of instance running. For example, a user might compare data from an m1.small instance
0175      *  and an m1.large instance to determine which has the better business value for his application.
0176      *
0177      * LoadBalancerName: This dimension filters the data you request for the specified LoadBalancer
0178      *  name. A LoadBalancer is represented by a DNS name and provides the single destination to
0179      *  which all requests intended for your application should be directed. This metric allows
0180      *  you to examine data from all instances connected to a single LoadBalancer.
0181      *
0182      * @var array
0183      */
0184     protected $_validDimensionsKeys = array('ImageId', 'AvailabilityZone', 'AutoScalingGroupName',
0185                                             'InstanceId', 'InstanceType', 'LoadBalancerName');
0186 
0187     /**
0188      * Returns data for one or more statistics of given a metric
0189      *
0190      * Note:
0191      * The maximum number of datapoints that the Amazon CloudWatch service will
0192      * return in a single GetMetricStatistics request is 1,440. If a request is
0193      * made that would generate more datapoints than this amount, Amazon CloudWatch
0194      * will return an error. You can alter your request by narrowing the time range
0195      * (StartTime, EndTime) or increasing the Period in your single request. You may
0196      * also get all of the data at the granularity you originally asked for by making
0197      * multiple requests with adjacent time ranges.
0198      *
0199      * @param array $options            The options you want to get statistics for:
0200      *                                  ** Required **
0201      *                                  MeasureName: The measure name that corresponds to
0202      *                                      the measure for the gathered metric. Valid EC2 Values are
0203      *                                      CPUUtilization, NetworkIn, NetworkOut, DiskWriteOps
0204      *                                      DiskReadBytes, DiskReadOps, DiskWriteBytes. Valid Elastic
0205      *                                      Load Balancing Metrics are Latency, RequestCount, HealthyHostCount
0206      *                                      UnHealthyHostCount
0207      *                                  Statistics: The statistics to be returned for the given metric. Valid
0208      *                                      values are Average, Maximum, Minimum, Samples, Sum.  You can specify
0209      *                                      this as a string or as an array of values.  If you don't specify one
0210      *                                      it will default to Average instead of failing out.  If you specify an incorrect
0211      *                                      option it will just skip it.
0212      *                                  ** Optional **
0213      *                                  Dimensions: Amazon CloudWatch allows you to specify one Dimension to further filter
0214      *                                      metric data on. If you don't specify a dimension, the service returns the aggregate
0215      *                                      of all the measures with the given measure name and time range.
0216      *                                  Unit: The standard unit of Measurement for a given Measure. Valid Values: Seconds,
0217      *                                      Percent, Bytes, Bits, Count, Bytes/Second, Bits/Second, Count/Second, and None
0218      *                                      Constraints: When using count/second as the unit, you should use Sum as the statistic
0219      *                                      instead of Average. Otherwise, the sample returns as equal to the number of requests
0220      *                                      instead of the number of 60-second intervals. This will cause the Average to
0221      *                                      always equals one when the unit is count/second.
0222      *                                  StartTime: The timestamp of the first datapoint to return, inclusive. For example,
0223      *                                      2008-02-26T19:00:00+00:00. We round your value down to the nearest minute.
0224      *                                      You can set your start time for more than two weeks in the past. However,
0225      *                                      you will only get data for the past two weeks. (in ISO 8601 format)
0226      *                                      Constraints: Must be before EndTime
0227      *                                  EndTime: The timestamp to use for determining the last datapoint to return. This is
0228      *                                      the last datapoint to fetch, exclusive. For example, 2008-02-26T20:00:00+00:00.
0229      *                                      (in ISO 8601 format)
0230      */
0231     public function getMetricStatistics(array $options)
0232     {
0233         $_usedStatistics = array();
0234 
0235         $params = array();
0236         $params['Action'] = 'GetMetricStatistics';
0237 
0238         if (!isset($options['Period'])) {
0239             $options['Period'] = 60;
0240         }
0241         if (!isset($options['Namespace'])) {
0242             $options['Namespace'] = 'AWS/EC2';
0243         }
0244 
0245         if (!isset($options['MeasureName']) || !in_array($options['MeasureName'], $this->_validMetrics, true)) {
0246             throw new Zend_Service_Amazon_Ec2_Exception('Invalid Metric Type: ' . $options['MeasureName']);
0247         }
0248 
0249         if(!isset($options['Statistics'])) {
0250             $options['Statistics'][] = 'Average';
0251         } elseif(!is_array($options['Statistics'])) {
0252             $options['Statistics'][] = $options['Statistics'];
0253         }
0254 
0255         foreach($options['Statistics'] as $k=>$s) {
0256             if(!in_array($s, $this->_validStatistics, true)) continue;
0257             $options['Statistics.member.' . ($k+1)] = $s;
0258             $_usedStatistics[] = $s;
0259         }
0260         unset($options['Statistics']);
0261 
0262         if(isset($options['StartTime'])) {
0263             if(!is_numeric($options['StartTime'])) $options['StartTime'] = strtotime($options['StartTime']);
0264             $options['StartTime'] = gmdate('c', $options['StartTime']);
0265         } else {
0266             $options['StartTime'] = gmdate('c', strtotime('-1 hour'));
0267         }
0268 
0269         if(isset($options['EndTime'])) {
0270             if(!is_numeric($options['EndTime'])) $options['EndTime'] = strtotime($options['EndTime']);
0271             $options['EndTime'] = gmdate('c', $options['EndTime']);
0272         } else {
0273             $options['EndTime'] = gmdate('c');
0274         }
0275 
0276         if(isset($options['Dimensions'])) {
0277             $x = 1;
0278             foreach($options['Dimensions'] as $dimKey=>$dimVal) {
0279                 if(!in_array($dimKey, $this->_validDimensionsKeys, true)) continue;
0280                 $options['Dimensions.member.' . $x . '.Name'] = $dimKey;
0281                 $options['Dimensions.member.' . $x . '.Value'] = $dimVal;
0282                 $x++;
0283             }
0284 
0285             unset($options['Dimensions']);
0286         }
0287 
0288         $params = array_merge($params, $options);
0289 
0290         $response = $this->sendRequest($params);
0291         $response->setNamespace($this->_xmlNamespace);
0292 
0293         $xpath = $response->getXPath();
0294         $nodes = $xpath->query('//ec2:GetMetricStatisticsResult/ec2:Datapoints/ec2:member');
0295 
0296         $return = array();
0297         $return['label'] = $xpath->evaluate('string(//ec2:GetMetricStatisticsResult/ec2:Label/text())');
0298         foreach ( $nodes as $node ) {
0299             $item = array();
0300 
0301             $item['Timestamp'] = $xpath->evaluate('string(ec2:Timestamp/text())', $node);
0302             $item['Unit'] = $xpath->evaluate('string(ec2:Unit/text())', $node);
0303             $item['Samples'] = $xpath->evaluate('string(ec2:Samples/text())', $node);
0304             foreach($_usedStatistics as $us) {
0305                 $item[$us] = $xpath->evaluate('string(ec2:' . $us . '/text())', $node);
0306             }
0307 
0308             $return['datapoints'][] = $item;
0309             unset($item, $node);
0310         }
0311 
0312         return $return;
0313 
0314     }
0315 
0316     /**
0317      * Return the Metrics that are aviable for your current monitored instances
0318      *
0319      * @param string $nextToken     The NextToken parameter is an optional parameter
0320      *                                 that allows you to retrieve the next set of results
0321      *                                 for your ListMetrics query.
0322      * @return array
0323      */
0324     public function listMetrics($nextToken = null)
0325     {
0326         $params = array();
0327         $params['Action'] = 'ListMetrics';
0328         if (!empty($nextToken)) {
0329             $params['NextToken'] = $nextToken;
0330         }
0331 
0332         $response = $this->sendRequest($params);
0333         $response->setNamespace($this->_xmlNamespace);
0334 
0335         $xpath = $response->getXPath();
0336         $nodes = $xpath->query('//ec2:ListMetricsResult/ec2:Metrics/ec2:member');
0337 
0338         $return = array();
0339         foreach ( $nodes as $node ) {
0340             $item = array();
0341 
0342             $item['MeasureName'] = $xpath->evaluate('string(ec2:MeasureName/text())', $node);
0343             $item['Namespace'] = $xpath->evaluate('string(ec2:Namespace/text())', $node);
0344             $item['Deminsions']['name'] = $xpath->evaluate('string(ec2:Dimensions/ec2:member/ec2:Name/text())', $node);
0345             $item['Deminsions']['value'] = $xpath->evaluate('string(ec2:Dimensions/ec2:member/ec2:Value/text())', $node);
0346 
0347             if (empty($item['Deminsions']['name'])) {
0348                 $item['Deminsions'] = array();
0349             }
0350 
0351             $return[] = $item;
0352             unset($item, $node);
0353         }
0354 
0355         return $return;
0356     }
0357 }