File indexing completed on 2024-12-29 05:27:29

0001 <?php
0002 /**
0003  * @category   Zend
0004  * @package    Zend_Cloud_Infrastructure
0005  * @subpackage Adapter
0006  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0007  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0008  */
0009 
0010 // require_once 'Zend/Service/Amazon/Ec2/Instance.php';
0011 // require_once 'Zend/Service/Amazon/Ec2/Image.php';
0012 // require_once 'Zend/Service/Amazon/Ec2/Availabilityzones.php';
0013 // require_once 'Zend/Service/Amazon/Ec2/CloudWatch.php';
0014 // require_once 'Zend/Cloud/Infrastructure/Instance.php';
0015 // require_once 'Zend/Cloud/Infrastructure/InstanceList.php';
0016 // require_once 'Zend/Cloud/Infrastructure/Image.php';
0017 // require_once 'Zend/Cloud/Infrastructure/ImageList.php';
0018 // require_once 'Zend/Cloud/Infrastructure/Adapter/AbstractAdapter.php';
0019 
0020 /**
0021  * Amazon EC2 adapter for infrastructure service
0022  *
0023  * @package    Zend_Cloud_Infrastructure
0024  * @subpackage Adapter
0025  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0026  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0027  */
0028 class Zend_Cloud_Infrastructure_Adapter_Ec2 extends Zend_Cloud_Infrastructure_Adapter_AbstractAdapter
0029 {
0030     /**
0031      * AWS constants
0032      */
0033     const AWS_ACCESS_KEY     = 'aws_accesskey';
0034     const AWS_SECRET_KEY     = 'aws_secretkey';
0035     const AWS_REGION         = 'aws_region';
0036     const AWS_SECURITY_GROUP = 'securityGroup';
0037 
0038     /**
0039      * Ec2 Instance 
0040      * 
0041      * @var Ec2Instance
0042      */
0043     protected $ec2;
0044 
0045     /**
0046      * Ec2 Image
0047      * 
0048      * @var Ec2Image
0049      */
0050     protected $ec2Image;
0051 
0052     /**
0053      * Ec2 Zone
0054      * 
0055      * @var Ec2Zone
0056      */
0057     protected $ec2Zone;
0058 
0059     /**
0060      * Ec2 Monitor 
0061      * 
0062      * @var Ec2Monitor
0063      */
0064     protected $ec2Monitor;
0065 
0066     /**
0067      * AWS Access Key
0068      * 
0069      * @var string 
0070      */
0071     protected $accessKey;
0072 
0073     /**
0074      * AWS Access Secret
0075      * 
0076      * @var string 
0077      */
0078     protected $accessSecret;
0079 
0080     /**
0081      * Region zone 
0082      * 
0083      * @var string 
0084      */
0085     protected $region;
0086 
0087     /**
0088      * Map array between EC2 and Infrastructure status
0089      * 
0090      * @var array 
0091      */
0092     protected $mapStatus = array (
0093         'running'       => Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING,
0094         'terminated'    => Zend_Cloud_Infrastructure_Instance::STATUS_TERMINATED,
0095         'pending'       => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING,
0096         'shutting-down' => Zend_Cloud_Infrastructure_Instance::STATUS_SHUTTING_DOWN,
0097         'stopping'      => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING,
0098         'stopped'       => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED,
0099         'rebooting'     => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING,
0100     );
0101 
0102     /**
0103      * Map monitor metrics between Infrastructure and EC2
0104      * 
0105      * @var array 
0106      */
0107     protected $mapMetrics= array (
0108         Zend_Cloud_Infrastructure_Instance::MONITOR_CPU         => 'CPUUtilization',
0109         Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_READ   => 'DiskReadBytes',
0110         Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_WRITE  => 'DiskWriteBytes',
0111         Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_IN  => 'NetworkIn',
0112         Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_OUT => 'NetworkOut',
0113     );
0114 
0115     /**
0116      * Constructor
0117      *
0118      * @param  array|Zend_Config $options
0119      * @return void
0120      */
0121     public function __construct($options = array())
0122     {
0123         if (is_object($options)) {
0124             if (method_exists($options, 'toArray')) {
0125                 $options= $options->toArray();
0126             } elseif ($options instanceof Traversable) {
0127                 $options = iterator_to_array($options);
0128             }
0129         }
0130         
0131         if (empty($options) || !is_array($options)) {
0132             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0133             throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided');
0134         }
0135         
0136         if (!isset($options[self::AWS_ACCESS_KEY]) 
0137             || !isset($options[self::AWS_SECRET_KEY])
0138         ) {
0139             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0140             throw new Zend_Cloud_Infrastructure_Exception('AWS keys not specified!');
0141         }
0142 
0143         $this->accessKey    = $options[self::AWS_ACCESS_KEY];
0144         $this->accessSecret = $options[self::AWS_SECRET_KEY];
0145         $this->region       = '';
0146 
0147         if (isset($options[self::AWS_REGION])) {
0148             $this->region= $options[self::AWS_REGION];
0149         }
0150 
0151         try {
0152             $this->ec2 = new Zend_Service_Amazon_Ec2_Instance($options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY], $this->region);
0153         } catch (Exception  $e) {
0154             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0155             throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e);
0156         }
0157 
0158         if (isset($options[self::HTTP_ADAPTER])) {
0159             $this->ec2->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]);
0160         }
0161     }
0162 
0163     /**
0164      * Convert the attributes of EC2 into attributes of Infrastructure
0165      * 
0166      * @param  array $attr
0167      * @return array|boolean 
0168      */
0169     private function convertAttributes($attr)
0170     {
0171         $result = array();       
0172         if (!empty($attr) && is_array($attr)) {
0173             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID]         = $attr['instanceId'];
0174             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS]     = $this->mapStatus[$attr['instanceState']['name']];
0175             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID]    = $attr['imageId'];
0176             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE]       = $attr['availabilityZone'];
0177             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_LAUNCHTIME] = $attr['launchTime'];
0178 
0179             switch ($attr['instanceType']) {
0180                 case Zend_Service_Amazon_Ec2_Instance::MICRO:
0181                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '1 virtual core';
0182                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '613MB';
0183                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '0GB';
0184                     break;
0185                 case Zend_Service_Amazon_Ec2_Instance::SMALL:
0186                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '1 virtual core';
0187                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '1.7GB';
0188                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '160GB';
0189                     break;
0190                 case Zend_Service_Amazon_Ec2_Instance::LARGE:
0191                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '2 virtual core';
0192                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '7.5GB';
0193                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '850GB';
0194                     break;
0195                 case Zend_Service_Amazon_Ec2_Instance::XLARGE:
0196                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '4 virtual core';
0197                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '15GB';
0198                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB';
0199                     break;
0200                 case Zend_Service_Amazon_Ec2_Instance::HCPU_MEDIUM:
0201                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '2 virtual core';
0202                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '1.7GB';
0203                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '350GB';
0204                     break;
0205                 case Zend_Service_Amazon_Ec2_Instance::HCPU_XLARGE:
0206                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '8 virtual core';
0207                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '7GB';
0208                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB';
0209                     break;
0210             }
0211         }
0212         return $result;
0213     }
0214 
0215     /**
0216      * Return a list of the available instancies
0217      *
0218      * @return Zend_Cloud_Infrastructure_InstanceList
0219      */ 
0220     public function listInstances() 
0221     {
0222         $this->adapterResult = $this->ec2->describe();
0223 
0224         $result = array();
0225         foreach ($this->adapterResult['instances'] as $instance) {
0226             $result[]= $this->convertAttributes($instance);
0227         }
0228         return new Zend_Cloud_Infrastructure_InstanceList($this, $result);
0229     }
0230 
0231     /**
0232      * Return the status of an instance
0233      *
0234      * @param  string
0235      * @return string|boolean
0236      */ 
0237     public function statusInstance($id)
0238     {
0239         $this->adapterResult = $this->ec2->describe($id);
0240         if (empty($this->adapterResult['instances'])) {
0241             return false;
0242         }    
0243         $result = $this->adapterResult['instances'][0];
0244         return $this->mapStatus[$result['instanceState']['name']];
0245     }
0246 
0247     /**
0248      * Return the public DNS name of the instance
0249      * 
0250      * @param  string $id
0251      * @return string|boolean 
0252      */
0253     public function publicDnsInstance($id) 
0254     {
0255         $this->adapterResult = $this->ec2->describe($id);
0256         if (empty($this->adapterResult['instances'])) {
0257             return false;
0258         }    
0259         $result = $this->adapterResult['instances'][0];
0260         return $result['dnsName'];
0261     }
0262 
0263     /**
0264      * Reboot an instance
0265      *
0266      * @param string $id
0267      * @return boolean
0268      */ 
0269     public function rebootInstance($id)
0270     {
0271         $this->adapterResult= $this->ec2->reboot($id);
0272         return $this->adapterResult;
0273     }
0274 
0275     /**
0276      * Create a new instance
0277      *
0278      * @param string $name
0279      * @param array $options
0280      * @return Instance|boolean
0281      */ 
0282     public function createInstance($name, $options)
0283     {
0284         // @todo instance's name management?
0285         $this->adapterResult = $this->ec2->run($options);
0286         if (empty($this->adapterResult['instances'])) {
0287             return false;
0288         }
0289         $this->error= false;
0290         return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult['instances'][0]));
0291     }
0292 
0293     /**
0294      * Stop an instance
0295      *
0296      * @param  string $id
0297      * @return boolean
0298      */ 
0299     public function stopInstance($id)
0300     {
0301         // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0302         throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter');
0303     }
0304  
0305     /**
0306      * Start an instance
0307      *
0308      * @param  string $id
0309      * @return boolean
0310      */ 
0311     public function startInstance($id)
0312     {
0313         // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0314         throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter');
0315     }
0316  
0317     /**
0318      * Destroy an instance
0319      *
0320      * @param  string $id
0321      * @return boolean
0322      */ 
0323     public function destroyInstance($id)
0324     {
0325         $this->adapterResult = $this->ec2->terminate($id);
0326         return (!empty($this->adapterResult));
0327     }
0328  
0329     /**
0330      * Return a list of all the available instance images
0331      *
0332      * @return ImageList
0333      */ 
0334     public function imagesInstance()
0335     {
0336         if (!isset($this->ec2Image)) {
0337             $this->ec2Image = new Zend_Service_Amazon_Ec2_Image($this->accessKey, $this->accessSecret, $this->region);
0338         }
0339 
0340         $this->adapterResult = $this->ec2Image->describe();
0341                 
0342         $images = array();
0343 
0344         foreach ($this->adapterResult as $result) {
0345             switch (strtolower($result['platform'])) {
0346                 case 'windows' :
0347                     $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS;
0348                     break;
0349                 default:
0350                     $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX;
0351                     break;
0352             }
0353 
0354             $images[]= array (
0355                 Zend_Cloud_Infrastructure_Image::IMAGE_ID           => $result['imageId'],
0356                 Zend_Cloud_Infrastructure_Image::IMAGE_NAME         => '',
0357                 Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION  => $result['imageLocation'],
0358                 Zend_Cloud_Infrastructure_Image::IMAGE_OWNERID      => $result['imageOwnerId'],
0359                 Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $result['architecture'],
0360                 Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM     => $platform,
0361             );
0362         }
0363         return new Zend_Cloud_Infrastructure_ImageList($images,$this->ec2Image);
0364     }
0365 
0366     /**
0367      * Return all the available zones
0368      * 
0369      * @return array
0370      */
0371     public function zonesInstance()
0372     {
0373         if (!isset($this->ec2Zone)) {
0374             $this->ec2Zone = new Zend_Service_Amazon_Ec2_AvailabilityZones($this->accessKey,$this->accessSecret,$this->region);
0375         }
0376         $this->adapterResult = $this->ec2Zone->describe();
0377 
0378         $zones = array();
0379         foreach ($this->adapterResult as $zone) {
0380             if (strtolower($zone['zoneState']) === 'available') {
0381                 $zones[] = array (
0382                     Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE => $zone['zoneName'],
0383                 );
0384             }
0385         }
0386         return $zones;
0387     }
0388 
0389     /**
0390      * Return the system information about the $metric of an instance
0391      * 
0392      * @param  string $id
0393      * @param  string $metric
0394      * @param  null|array $options
0395      * @return array
0396      */ 
0397     public function monitorInstance($id, $metric, $options = null)
0398     {
0399         if (empty($id) || empty($metric)) {
0400             return false;
0401         }
0402 
0403         if (!in_array($metric,$this->validMetrics)) {
0404             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0405             throw new Zend_Cloud_Infrastructure_Exception(sprintf(
0406                 'The metric "%s" is not valid', 
0407                 $metric
0408             ));
0409         }
0410 
0411         if (!empty($options) && !is_array($options)) {
0412             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0413             throw new Zend_Cloud_Infrastructure_Exception('The options must be an array');
0414         }
0415 
0416         if (!empty($options) 
0417             && (empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME]) 
0418                 || empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME]))
0419         ) {
0420             // require_once 'Zend/Cloud/Infrastructure/Exception.php';
0421             throw new Zend_Cloud_Infrastructure_Exception(sprintf(
0422                 'The options array must contain: "%s" and "%s"',
0423                 $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME],
0424                 $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME]
0425             ));
0426         }      
0427 
0428         if (!isset($this->ec2Monitor)) {
0429             $this->ec2Monitor = new Zend_Service_Amazon_Ec2_CloudWatch($this->accessKey, $this->accessSecret, $this->region);
0430         }
0431 
0432         $param = array(
0433             'MeasureName' => $this->mapMetrics[$metric],
0434             'Statistics'  => array('Average'),
0435             'Dimensions'  => array('InstanceId' => $id),
0436         );
0437 
0438         if (!empty($options)) {
0439             $param['StartTime'] = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME];
0440             $param['EndTime']   = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME];
0441         }
0442 
0443         $this->adapterResult = $this->ec2Monitor->getMetricStatistics($param);
0444 
0445         $monitor             = array();
0446         $num                 = 0;
0447         $average             = 0;
0448 
0449         if (!empty($this->adapterResult['datapoints'])) {
0450             foreach ($this->adapterResult['datapoints'] as $result) {
0451                 $monitor['series'][] = array (
0452                     'timestamp' => $result['Timestamp'],
0453                     'value'     => $result['Average'],
0454                 );
0455                 $average += $result['Average'];
0456                 $num++;
0457             }
0458         }
0459 
0460         if ($num > 0) {
0461             $monitor['average'] = $average / $num;
0462         }
0463 
0464         return $monitor;
0465     }
0466 
0467     /**
0468      * Get the adapter 
0469      * 
0470      * @return Zend_Service_Amazon_Ec2_Instance
0471      */
0472     public function getAdapter()
0473     {
0474         return $this->ec2;
0475     }
0476 
0477     /**
0478      * Get last HTTP request
0479      * 
0480      * @return string 
0481      */
0482     public function getLastHttpRequest()
0483     {
0484         return $this->ec2->getHttpClient()->getLastRequest();
0485     }
0486 
0487     /**
0488      * Get the last HTTP response
0489      * 
0490      * @return Zend_Http_Response 
0491      */
0492     public function getLastHttpResponse()
0493     {
0494         return $this->ec2->getHttpClient()->getLastResponse();
0495     }
0496 }