web/lib/Zend/Cloud/Infrastructure/Adapter/Ec2.php
changeset 808 6b6c2214f778
child 1230 68c69c656a2c
equal deleted inserted replaced
807:877f952ae2bd 808:6b6c2214f778
       
     1 <?php
       
     2 /**
       
     3  * @category   Zend
       
     4  * @package    Zend_Cloud_Infrastructure
       
     5  * @subpackage Adapter
       
     6  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
       
     7  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
     8  */
       
     9 
       
    10 require_once 'Zend/Service/Amazon/Ec2/Instance.php';
       
    11 require_once 'Zend/Service/Amazon/Ec2/Image.php';
       
    12 require_once 'Zend/Service/Amazon/Ec2/Availabilityzones.php';
       
    13 require_once 'Zend/Service/Amazon/Ec2/CloudWatch.php';
       
    14 require_once 'Zend/Cloud/Infrastructure/Instance.php';
       
    15 require_once 'Zend/Cloud/Infrastructure/InstanceList.php';
       
    16 require_once 'Zend/Cloud/Infrastructure/Image.php';
       
    17 require_once 'Zend/Cloud/Infrastructure/ImageList.php';
       
    18 require_once 'Zend/Cloud/Infrastructure/Adapter/AbstractAdapter.php';
       
    19 
       
    20 /**
       
    21  * Amazon EC2 adapter for infrastructure service
       
    22  *
       
    23  * @package    Zend_Cloud_Infrastructure
       
    24  * @subpackage Adapter
       
    25  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
       
    26  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    27  */
       
    28 class Zend_Cloud_Infrastructure_Adapter_Ec2 extends Zend_Cloud_Infrastructure_Adapter_AbstractAdapter
       
    29 {
       
    30     /**
       
    31      * AWS constants
       
    32      */
       
    33     const AWS_ACCESS_KEY     = 'aws_accesskey';
       
    34     const AWS_SECRET_KEY     = 'aws_secretkey';
       
    35     const AWS_REGION         = 'aws_region';
       
    36     const AWS_SECURITY_GROUP = 'securityGroup';
       
    37 
       
    38     /**
       
    39      * Ec2 Instance 
       
    40      * 
       
    41      * @var Ec2Instance
       
    42      */
       
    43     protected $ec2;
       
    44 
       
    45     /**
       
    46      * Ec2 Image
       
    47      * 
       
    48      * @var Ec2Image
       
    49      */
       
    50     protected $ec2Image;
       
    51 
       
    52     /**
       
    53      * Ec2 Zone
       
    54      * 
       
    55      * @var Ec2Zone
       
    56      */
       
    57     protected $ec2Zone;
       
    58 
       
    59     /**
       
    60      * Ec2 Monitor 
       
    61      * 
       
    62      * @var Ec2Monitor
       
    63      */
       
    64     protected $ec2Monitor;
       
    65 
       
    66     /**
       
    67      * AWS Access Key
       
    68      * 
       
    69      * @var string 
       
    70      */
       
    71     protected $accessKey;
       
    72 
       
    73     /**
       
    74      * AWS Access Secret
       
    75      * 
       
    76      * @var string 
       
    77      */
       
    78     protected $accessSecret;
       
    79 
       
    80     /**
       
    81      * Region zone 
       
    82      * 
       
    83      * @var string 
       
    84      */
       
    85     protected $region;
       
    86 
       
    87     /**
       
    88      * Map array between EC2 and Infrastructure status
       
    89      * 
       
    90      * @var array 
       
    91      */
       
    92     protected $mapStatus = array (
       
    93         'running'       => Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING,
       
    94         'terminated'    => Zend_Cloud_Infrastructure_Instance::STATUS_TERMINATED,
       
    95         'pending'       => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING,
       
    96         'shutting-down' => Zend_Cloud_Infrastructure_Instance::STATUS_SHUTTING_DOWN,
       
    97         'stopping'      => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING,
       
    98         'stopped'       => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED,
       
    99         'rebooting'     => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING,
       
   100     );
       
   101 
       
   102     /**
       
   103      * Map monitor metrics between Infrastructure and EC2
       
   104      * 
       
   105      * @var array 
       
   106      */
       
   107     protected $mapMetrics= array (
       
   108         Zend_Cloud_Infrastructure_Instance::MONITOR_CPU         => 'CPUUtilization',
       
   109         Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_READ   => 'DiskReadBytes',
       
   110         Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_WRITE  => 'DiskWriteBytes',
       
   111         Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_IN  => 'NetworkIn',
       
   112         Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_OUT => 'NetworkOut',
       
   113     );
       
   114 
       
   115     /**
       
   116      * Constructor
       
   117      *
       
   118      * @param  array|Zend_Config $options
       
   119      * @return void
       
   120      */
       
   121     public function __construct($options = array())
       
   122     {
       
   123         if (is_object($options)) {
       
   124             if (method_exists($options, 'toArray')) {
       
   125                 $options= $options->toArray();
       
   126             } elseif ($options instanceof Traversable) {
       
   127                 $options = iterator_to_array($options);
       
   128             }
       
   129         }
       
   130         
       
   131         if (empty($options) || !is_array($options)) {
       
   132             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   133             throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided');
       
   134         }
       
   135         
       
   136         if (!isset($options[self::AWS_ACCESS_KEY]) 
       
   137             || !isset($options[self::AWS_SECRET_KEY])
       
   138         ) {
       
   139             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   140             throw new Zend_Cloud_Infrastructure_Exception('AWS keys not specified!');
       
   141         }
       
   142 
       
   143         $this->accessKey    = $options[self::AWS_ACCESS_KEY];
       
   144         $this->accessSecret = $options[self::AWS_SECRET_KEY];
       
   145         $this->region       = '';
       
   146 
       
   147         if (isset($options[self::AWS_REGION])) {
       
   148             $this->region= $options[self::AWS_REGION];
       
   149         }
       
   150 
       
   151         try {
       
   152             $this->ec2 = new Zend_Service_Amazon_Ec2_Instance($options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY], $this->region);
       
   153         } catch (Exception  $e) {
       
   154             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   155             throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e);
       
   156         }
       
   157 
       
   158         if (isset($options[self::HTTP_ADAPTER])) {
       
   159             $this->ec2->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]);
       
   160         }
       
   161     }
       
   162 
       
   163     /**
       
   164      * Convert the attributes of EC2 into attributes of Infrastructure
       
   165      * 
       
   166      * @param  array $attr
       
   167      * @return array|boolean 
       
   168      */
       
   169     private function convertAttributes($attr)
       
   170     {
       
   171         $result = array();       
       
   172         if (!empty($attr) && is_array($attr)) {
       
   173             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID]         = $attr['instanceId'];
       
   174             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS]     = $this->mapStatus[$attr['instanceState']['name']];
       
   175             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID]    = $attr['imageId'];
       
   176             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE]       = $attr['availabilityZone'];
       
   177             $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_LAUNCHTIME] = $attr['launchTime'];
       
   178 
       
   179             switch ($attr['instanceType']) {
       
   180                 case Zend_Service_Amazon_Ec2_Instance::MICRO:
       
   181                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '1 virtual core';
       
   182                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '613MB';
       
   183                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '0GB';
       
   184                     break;
       
   185                 case Zend_Service_Amazon_Ec2_Instance::SMALL:
       
   186                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '1 virtual core';
       
   187                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '1.7GB';
       
   188                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '160GB';
       
   189                     break;
       
   190                 case Zend_Service_Amazon_Ec2_Instance::LARGE:
       
   191                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '2 virtual core';
       
   192                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '7.5GB';
       
   193                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '850GB';
       
   194                     break;
       
   195                 case Zend_Service_Amazon_Ec2_Instance::XLARGE:
       
   196                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '4 virtual core';
       
   197                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '15GB';
       
   198                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB';
       
   199                     break;
       
   200                 case Zend_Service_Amazon_Ec2_Instance::HCPU_MEDIUM:
       
   201                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '2 virtual core';
       
   202                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '1.7GB';
       
   203                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '350GB';
       
   204                     break;
       
   205                 case Zend_Service_Amazon_Ec2_Instance::HCPU_XLARGE:
       
   206                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU]     = '8 virtual core';
       
   207                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM]     = '7GB';
       
   208                     $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB';
       
   209                     break;
       
   210             }
       
   211         }
       
   212         return $result;
       
   213     }
       
   214 
       
   215     /**
       
   216      * Return a list of the available instancies
       
   217      *
       
   218      * @return Zend_Cloud_Infrastructure_InstanceList
       
   219      */ 
       
   220     public function listInstances() 
       
   221     {
       
   222         $this->adapterResult = $this->ec2->describe();
       
   223 
       
   224         $result = array();
       
   225         foreach ($this->adapterResult['instances'] as $instance) {
       
   226             $result[]= $this->convertAttributes($instance);
       
   227         }
       
   228         return new Zend_Cloud_Infrastructure_InstanceList($this, $result);
       
   229     }
       
   230 
       
   231     /**
       
   232      * Return the status of an instance
       
   233      *
       
   234      * @param  string
       
   235      * @return string|boolean
       
   236      */ 
       
   237     public function statusInstance($id)
       
   238     {
       
   239         $this->adapterResult = $this->ec2->describe($id);
       
   240         if (empty($this->adapterResult['instances'])) {
       
   241             return false;
       
   242         }    
       
   243         $result = $this->adapterResult['instances'][0];
       
   244         return $this->mapStatus[$result['instanceState']['name']];
       
   245     }
       
   246 
       
   247     /**
       
   248      * Return the public DNS name of the instance
       
   249      * 
       
   250      * @param  string $id
       
   251      * @return string|boolean 
       
   252      */
       
   253     public function publicDnsInstance($id) 
       
   254     {
       
   255         $this->adapterResult = $this->ec2->describe($id);
       
   256         if (empty($this->adapterResult['instances'])) {
       
   257             return false;
       
   258         }    
       
   259         $result = $this->adapterResult['instances'][0];
       
   260         return $result['dnsName'];
       
   261     }
       
   262 
       
   263     /**
       
   264      * Reboot an instance
       
   265      *
       
   266      * @param string $id
       
   267      * @return boolean
       
   268      */ 
       
   269     public function rebootInstance($id)
       
   270     {
       
   271         $this->adapterResult= $this->ec2->reboot($id);
       
   272         return $this->adapterResult;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Create a new instance
       
   277      *
       
   278      * @param string $name
       
   279      * @param array $options
       
   280      * @return Instance|boolean
       
   281      */ 
       
   282     public function createInstance($name, $options)
       
   283     {
       
   284         // @todo instance's name management?
       
   285         $this->adapterResult = $this->ec2->run($options);
       
   286         if (empty($this->adapterResult['instances'])) {
       
   287             return false;
       
   288         }
       
   289         $this->error= false;
       
   290         return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult['instances'][0]));
       
   291     }
       
   292 
       
   293     /**
       
   294      * Stop an instance
       
   295      *
       
   296      * @param  string $id
       
   297      * @return boolean
       
   298      */ 
       
   299     public function stopInstance($id)
       
   300     {
       
   301         require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   302         throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter');
       
   303     }
       
   304  
       
   305     /**
       
   306      * Start an instance
       
   307      *
       
   308      * @param  string $id
       
   309      * @return boolean
       
   310      */ 
       
   311     public function startInstance($id)
       
   312     {
       
   313         require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   314         throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter');
       
   315     }
       
   316  
       
   317     /**
       
   318      * Destroy an instance
       
   319      *
       
   320      * @param  string $id
       
   321      * @return boolean
       
   322      */ 
       
   323     public function destroyInstance($id)
       
   324     {
       
   325         $this->adapterResult = $this->ec2->terminate($id);
       
   326         return (!empty($this->adapterResult));
       
   327     }
       
   328  
       
   329     /**
       
   330      * Return a list of all the available instance images
       
   331      *
       
   332      * @return ImageList
       
   333      */ 
       
   334     public function imagesInstance()
       
   335     {
       
   336         if (!isset($this->ec2Image)) {
       
   337             $this->ec2Image = new Zend_Service_Amazon_Ec2_Image($this->accessKey, $this->accessSecret, $this->region);
       
   338         }
       
   339 
       
   340         $this->adapterResult = $this->ec2Image->describe();
       
   341                 
       
   342         $images = array();
       
   343 
       
   344         foreach ($this->adapterResult as $result) {
       
   345             switch (strtolower($result['platform'])) {
       
   346                 case 'windows' :
       
   347                     $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS;
       
   348                     break;
       
   349                 default:
       
   350                     $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX;
       
   351                     break;
       
   352             }
       
   353 
       
   354             $images[]= array (
       
   355                 Zend_Cloud_Infrastructure_Image::IMAGE_ID           => $result['imageId'],
       
   356                 Zend_Cloud_Infrastructure_Image::IMAGE_NAME         => '',
       
   357                 Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION  => $result['imageLocation'],
       
   358                 Zend_Cloud_Infrastructure_Image::IMAGE_OWNERID      => $result['imageOwnerId'],
       
   359                 Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $result['architecture'],
       
   360                 Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM     => $platform,
       
   361             );
       
   362         }
       
   363         return new Zend_Cloud_Infrastructure_ImageList($images,$this->ec2Image);
       
   364     }
       
   365 
       
   366     /**
       
   367      * Return all the available zones
       
   368      * 
       
   369      * @return array
       
   370      */
       
   371     public function zonesInstance()
       
   372     {
       
   373         if (!isset($this->ec2Zone)) {
       
   374             $this->ec2Zone = new Zend_Service_Amazon_Ec2_AvailabilityZones($this->accessKey,$this->accessSecret,$this->region);
       
   375         }
       
   376         $this->adapterResult = $this->ec2Zone->describe();
       
   377 
       
   378         $zones = array();
       
   379         foreach ($this->adapterResult as $zone) {
       
   380             if (strtolower($zone['zoneState']) === 'available') {
       
   381                 $zones[] = array (
       
   382                     Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE => $zone['zoneName'],
       
   383                 );
       
   384             }
       
   385         }
       
   386         return $zones;
       
   387     }
       
   388 
       
   389     /**
       
   390      * Return the system information about the $metric of an instance
       
   391      * 
       
   392      * @param  string $id
       
   393      * @param  string $metric
       
   394      * @param  null|array $options
       
   395      * @return array
       
   396      */ 
       
   397     public function monitorInstance($id, $metric, $options = null)
       
   398     {
       
   399         if (empty($id) || empty($metric)) {
       
   400             return false;
       
   401         }
       
   402 
       
   403         if (!in_array($metric,$this->validMetrics)) {
       
   404             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   405             throw new Zend_Cloud_Infrastructure_Exception(sprintf(
       
   406                 'The metric "%s" is not valid', 
       
   407                 $metric
       
   408             ));
       
   409         }
       
   410 
       
   411         if (!empty($options) && !is_array($options)) {
       
   412             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   413             throw new Zend_Cloud_Infrastructure_Exception('The options must be an array');
       
   414         }
       
   415 
       
   416         if (!empty($options) 
       
   417             && (empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME]) 
       
   418                 || empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME]))
       
   419         ) {
       
   420             require_once 'Zend/Cloud/Infrastructure/Exception.php';
       
   421             throw new Zend_Cloud_Infrastructure_Exception(sprintf(
       
   422                 'The options array must contain: "%s" and "%s"',
       
   423                 $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME],
       
   424                 $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME]
       
   425             ));
       
   426         }      
       
   427 
       
   428         if (!isset($this->ec2Monitor)) {
       
   429             $this->ec2Monitor = new Zend_Service_Amazon_Ec2_CloudWatch($this->accessKey, $this->accessSecret, $this->region);
       
   430         }
       
   431 
       
   432         $param = array(
       
   433             'MeasureName' => $this->mapMetrics[$metric],
       
   434             'Statistics'  => array('Average'),
       
   435             'Dimensions'  => array('InstanceId' => $id),
       
   436         );
       
   437 
       
   438         if (!empty($options)) {
       
   439             $param['StartTime'] = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME];
       
   440             $param['EndTime']   = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME];
       
   441         }
       
   442 
       
   443         $this->adapterResult = $this->ec2Monitor->getMetricStatistics($param);
       
   444 
       
   445         $monitor             = array();
       
   446         $num                 = 0;
       
   447         $average             = 0;
       
   448 
       
   449         if (!empty($this->adapterResult['datapoints'])) {
       
   450             foreach ($this->adapterResult['datapoints'] as $result) {
       
   451                 $monitor['series'][] = array (
       
   452                     'timestamp' => $result['Timestamp'],
       
   453                     'value'     => $result['Average'],
       
   454                 );
       
   455                 $average += $result['Average'];
       
   456                 $num++;
       
   457             }
       
   458         }
       
   459 
       
   460         if ($num > 0) {
       
   461             $monitor['average'] = $average / $num;
       
   462         }
       
   463 
       
   464         return $monitor;
       
   465     }
       
   466 
       
   467     /**
       
   468      * Get the adapter 
       
   469      * 
       
   470      * @return Zend_Service_Amazon_Ec2_Instance
       
   471      */
       
   472     public function getAdapter()
       
   473     {
       
   474         return $this->ec2;
       
   475     }
       
   476 
       
   477     /**
       
   478      * Get last HTTP request
       
   479      * 
       
   480      * @return string 
       
   481      */
       
   482     public function getLastHttpRequest()
       
   483     {
       
   484         return $this->ec2->getHttpClient()->getLastRequest();
       
   485     }
       
   486 
       
   487     /**
       
   488      * Get the last HTTP response
       
   489      * 
       
   490      * @return Zend_Http_Response 
       
   491      */
       
   492     public function getLastHttpResponse()
       
   493     {
       
   494         return $this->ec2->getHttpClient()->getLastResponse();
       
   495     }
       
   496 }