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/Rackspace/Servers.php'; 0011 // require_once 'Zend/Cloud/Infrastructure/Instance.php'; 0012 // require_once 'Zend/Cloud/Infrastructure/InstanceList.php'; 0013 // require_once 'Zend/Cloud/Infrastructure/Image.php'; 0014 // require_once 'Zend/Cloud/Infrastructure/ImageList.php'; 0015 // require_once 'Zend/Cloud/Infrastructure/Adapter/AbstractAdapter.php'; 0016 0017 /** 0018 * Rackspace servers adapter for infrastructure service 0019 * 0020 * @package Zend_Cloud_Infrastructure 0021 * @subpackage Adapter 0022 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0023 * @license http://framework.zend.com/license/new-bsd New BSD License 0024 */ 0025 class Zend_Cloud_Infrastructure_Adapter_Rackspace extends Zend_Cloud_Infrastructure_Adapter_AbstractAdapter 0026 { 0027 /** 0028 * RACKSPACE constants 0029 */ 0030 const RACKSPACE_USER = 'rackspace_user'; 0031 const RACKSPACE_KEY = 'rackspace_key'; 0032 const RACKSPACE_REGION = 'rackspace_region'; 0033 const RACKSPACE_ZONE_USA = 'USA'; 0034 const RACKSPACE_ZONE_UK = 'UK'; 0035 const MONITOR_CPU_SAMPLES = 3; 0036 /** 0037 * Rackspace Servers Instance 0038 * 0039 * @var Zend_Service_Rackspace_Servers 0040 */ 0041 protected $rackspace; 0042 /** 0043 * Rackspace access user 0044 * 0045 * @var string 0046 */ 0047 protected $accessUser; 0048 0049 /** 0050 * Rackspace access key 0051 * 0052 * @var string 0053 */ 0054 protected $accessKey; 0055 /** 0056 * Rackspace Region 0057 * 0058 * @var string 0059 */ 0060 protected $region; 0061 /** 0062 * Flavors 0063 * 0064 * @var array 0065 */ 0066 protected $flavors; 0067 /** 0068 * Map array between Rackspace and Infrastructure status 0069 * 0070 * @var array 0071 */ 0072 protected $mapStatus = array ( 0073 'ACTIVE' => Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING, 0074 'SUSPENDED' => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED, 0075 'BUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, 0076 'REBUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, 0077 'QUEUE_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0078 'PREP_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0079 'RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, 0080 'VERIFY_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, 0081 'PASSWORD' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0082 'RESCUE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0083 'REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, 0084 'HARD_REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, 0085 'SHARE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0086 'SHARE_IP_NO_CONFIG' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0087 'DELETE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, 0088 'UNKNOWN' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING 0089 ); 0090 /** 0091 * Constructor 0092 * 0093 * @param array|Zend_Config $options 0094 * @return void 0095 */ 0096 public function __construct($options = array()) 0097 { 0098 if (is_object($options)) { 0099 if (method_exists($options, 'toArray')) { 0100 $options= $options->toArray(); 0101 } elseif ($options instanceof Traversable) { 0102 $options = iterator_to_array($options); 0103 } 0104 } 0105 0106 if (empty($options) || !is_array($options)) { 0107 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0108 throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided'); 0109 } 0110 0111 if (!isset($options[self::RACKSPACE_USER])) { 0112 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0113 throw new Zend_Cloud_Infrastructure_Exception('Rackspace access user not specified!'); 0114 } 0115 0116 if (!isset($options[self::RACKSPACE_KEY])) { 0117 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0118 throw new Zend_Cloud_Infrastructure_Exception('Rackspace access key not specified!'); 0119 } 0120 0121 $this->accessUser = $options[self::RACKSPACE_USER]; 0122 $this->accessKey = $options[self::RACKSPACE_KEY]; 0123 0124 if (isset($options[self::RACKSPACE_REGION])) { 0125 switch ($options[self::RACKSPACE_REGION]) { 0126 case self::RACKSPACE_ZONE_UK: 0127 $this->region= Zend_Service_Rackspace_Servers::UK_AUTH_URL; 0128 break; 0129 case self::RACKSPACE_ZONE_USA: 0130 $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; 0131 break; 0132 default: 0133 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0134 throw new Zend_Cloud_Infrastructure_Exception('The region is not valid'); 0135 } 0136 } else { 0137 $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; 0138 } 0139 0140 try { 0141 $this->rackspace = new Zend_Service_Rackspace_Servers($this->accessUser,$this->accessKey, $this->region); 0142 } catch (Exception $e) { 0143 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0144 throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e); 0145 } 0146 0147 if (isset($options[self::HTTP_ADAPTER])) { 0148 $this->rackspace->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); 0149 } 0150 0151 } 0152 /** 0153 * Convert the attributes of Rackspace server into attributes of Infrastructure 0154 * 0155 * @param array $attr 0156 * @return array|boolean 0157 */ 0158 protected function convertAttributes($attr) 0159 { 0160 $result = array(); 0161 if (!empty($attr) && is_array($attr)) { 0162 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID] = $attr['id']; 0163 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_NAME] = $attr['name']; 0164 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS] = $this->mapStatus[$attr['status']]; 0165 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID] = $attr['imageId']; 0166 if ($this->region==Zend_Service_Rackspace_Servers::US_AUTH_URL) { 0167 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_USA; 0168 } else { 0169 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_UK; 0170 } 0171 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = $this->flavors[$attr['flavorId']]['ram']; 0172 $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = $this->flavors[$attr['flavorId']]['disk']; 0173 } 0174 return $result; 0175 } 0176 /** 0177 * Return a list of the available instancies 0178 * 0179 * @return InstanceList|boolean 0180 */ 0181 public function listInstances() 0182 { 0183 $this->adapterResult = $this->rackspace->listServers(true); 0184 if ($this->adapterResult===false) { 0185 return false; 0186 } 0187 $array= $this->adapterResult->toArray(); 0188 $result = array(); 0189 foreach ($array as $instance) { 0190 $result[]= $this->convertAttributes($instance); 0191 } 0192 return new Zend_Cloud_Infrastructure_InstanceList($this, $result); 0193 } 0194 /** 0195 * Return the status of an instance 0196 * 0197 * @param string 0198 * @return string|boolean 0199 */ 0200 public function statusInstance($id) 0201 { 0202 $this->adapterResult = $this->rackspace->getServer($id); 0203 if ($this->adapterResult===false) { 0204 return false; 0205 } 0206 $array= $this->adapterResult->toArray(); 0207 return $this->mapStatus[$array['status']]; 0208 } 0209 /** 0210 * Return the public DNS name/Ip address of the instance 0211 * 0212 * @param string $id 0213 * @return string|boolean 0214 */ 0215 public function publicDnsInstance($id) 0216 { 0217 $this->adapterResult = $this->rackspace->getServerPublicIp($id); 0218 if (empty($this->adapterResult)) { 0219 return false; 0220 } 0221 return $this->adapterResult[0]; 0222 } 0223 /** 0224 * Reboot an instance 0225 * 0226 * @param string $id 0227 * @return boolean 0228 */ 0229 public function rebootInstance($id) 0230 { 0231 return $this->rackspace->rebootServer($id,true); 0232 } 0233 /** 0234 * Create a new instance 0235 * 0236 * @param string $name 0237 * @param array $options 0238 * @return Instance|boolean 0239 */ 0240 public function createInstance($name, $options) 0241 { 0242 if (empty($name)) { 0243 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0244 throw new Zend_Cloud_Infrastructure_Exception('You must specify the name of the instance'); 0245 } 0246 if (empty($options) || !is_array($options)) { 0247 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0248 throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); 0249 } 0250 // @todo create an generic abstract definition for an instance? 0251 $metadata= array(); 0252 if (isset($options['metadata'])) { 0253 $metadata= $options['metadata']; 0254 unset($options['metadata']); 0255 } 0256 $files= array(); 0257 if (isset($options['files'])) { 0258 $files= $options['files']; 0259 unset($options['files']); 0260 } 0261 $options['name']= $name; 0262 $this->adapterResult = $this->rackspace->createServer($options,$metadata,$files); 0263 if ($this->adapterResult===false) { 0264 return false; 0265 } 0266 return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult->toArray())); 0267 } 0268 /** 0269 * Stop an instance 0270 * 0271 * @param string $id 0272 * @return boolean 0273 */ 0274 public function stopInstance($id) 0275 { 0276 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0277 throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter'); 0278 } 0279 0280 /** 0281 * Start an instance 0282 * 0283 * @param string $id 0284 * @return boolean 0285 */ 0286 public function startInstance($id) 0287 { 0288 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0289 throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter'); 0290 } 0291 0292 /** 0293 * Destroy an instance 0294 * 0295 * @param string $id 0296 * @return boolean 0297 */ 0298 public function destroyInstance($id) 0299 { 0300 $this->adapterResult= $this->rackspace->deleteServer($id); 0301 return $this->adapterResult; 0302 } 0303 /** 0304 * Return a list of all the available instance images 0305 * 0306 * @return ImageList|boolean 0307 */ 0308 public function imagesInstance() 0309 { 0310 $this->adapterResult = $this->rackspace->listImages(true); 0311 if ($this->adapterResult===false) { 0312 return false; 0313 } 0314 0315 $images= $this->adapterResult->toArray(); 0316 $result= array(); 0317 0318 foreach ($images as $image) { 0319 if (strtolower($image['status'])==='active') { 0320 if (strpos($image['name'],'Windows')!==false) { 0321 $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS; 0322 } else { 0323 $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX; 0324 } 0325 if (strpos($image['name'],'x64')!==false) { 0326 $arch = Zend_Cloud_Infrastructure_Image::ARCH_64BIT; 0327 } else { 0328 $arch = Zend_Cloud_Infrastructure_Image::ARCH_32BIT; 0329 } 0330 $result[]= array ( 0331 Zend_Cloud_Infrastructure_Image::IMAGE_ID => $image['id'], 0332 Zend_Cloud_Infrastructure_Image::IMAGE_NAME => $image['name'], 0333 Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION => $image['name'], 0334 Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $arch, 0335 Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM => $platform, 0336 ); 0337 } 0338 } 0339 return new Zend_Cloud_Infrastructure_ImageList($result,$this->adapterResult); 0340 } 0341 /** 0342 * Return all the available zones 0343 * 0344 * @return array 0345 */ 0346 public function zonesInstance() 0347 { 0348 return array(self::RACKSPACE_ZONE_USA,self::RACKSPACE_ZONE_UK); 0349 } 0350 /** 0351 * Return the system information about the $metric of an instance 0352 * NOTE: it works only for Linux servers 0353 * 0354 * @param string $id 0355 * @param string $metric 0356 * @param null|array $options 0357 * @return array|boolean 0358 */ 0359 public function monitorInstance($id, $metric, $options = null) 0360 { 0361 if (!function_exists("ssh2_connect")) { 0362 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0363 throw new Zend_Cloud_Infrastructure_Exception('Monitor requires the PHP "SSH" extension (ext/ssh2)'); 0364 } 0365 if (empty($id)) { 0366 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0367 throw new Zend_Cloud_Infrastructure_Exception('You must specify the id of the instance to monitor'); 0368 } 0369 if (empty($metric)) { 0370 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0371 throw new Zend_Cloud_Infrastructure_Exception('You must specify the metric to monitor'); 0372 } 0373 if (!in_array($metric,$this->validMetrics)) { 0374 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0375 throw new Zend_Cloud_Infrastructure_Exception(sprintf('The metric "%s" is not valid', $metric)); 0376 } 0377 if (!empty($options) && !is_array($options)) { 0378 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0379 throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); 0380 } 0381 0382 switch ($metric) { 0383 case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: 0384 $cmd= 'top -b -n '.self::MONITOR_CPU_SAMPLES.' | grep \'Cpu\''; 0385 break; 0386 case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: 0387 $cmd= 'top -b -n 1 | grep \'Mem\''; 0388 break; 0389 case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: 0390 $cmd= 'df --total | grep total'; 0391 break; 0392 } 0393 if (empty($cmd)) { 0394 // require_once 'Zend/Cloud/Infrastructure/Exception.php'; 0395 throw new Zend_Cloud_Infrastructure_Exception('The metric specified is not supported by the adapter'); 0396 } 0397 0398 $params= array( 0399 Zend_Cloud_Infrastructure_Instance::SSH_USERNAME => $options['username'], 0400 Zend_Cloud_Infrastructure_Instance::SSH_PASSWORD => $options['password'] 0401 ); 0402 $exec_time= time(); 0403 $result= $this->deployInstance($id,$params,$cmd); 0404 0405 if (empty($result)) { 0406 return false; 0407 } 0408 0409 $monitor = array(); 0410 $num = 0; 0411 $average = 0; 0412 0413 $outputs= explode("\n",$result); 0414 foreach ($outputs as $output) { 0415 if (!empty($output)) { 0416 switch ($metric) { 0417 case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: 0418 if (preg_match('/(\d+\.\d)%us/', $output,$match)) { 0419 $usage = (float) $match[1]; 0420 } 0421 break; 0422 case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: 0423 if (preg_match('/(\d+)k total/', $output,$match)) { 0424 $total = (integer) $match[1]; 0425 } 0426 if (preg_match('/(\d+)k used/', $output,$match)) { 0427 $used = (integer) $match[1]; 0428 } 0429 if ($total>0) { 0430 $usage= (float) $used/$total; 0431 } 0432 break; 0433 case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: 0434 if (preg_match('/(\d+)%/', $output,$match)) { 0435 $usage = (float) $match[1]; 0436 } 0437 break; 0438 } 0439 0440 $monitor['series'][] = array ( 0441 'timestamp' => $exec_time, 0442 'value' => number_format($usage,2).'%' 0443 ); 0444 0445 $average += $usage; 0446 $exec_time+= 60; // seconds 0447 $num++; 0448 } 0449 } 0450 0451 if ($num>0) { 0452 $monitor['average'] = number_format($average/$num,2).'%'; 0453 } 0454 return $monitor; 0455 } 0456 /** 0457 * Get the adapter 0458 * 0459 * @return Zend_Service_Rackspace_Servers 0460 */ 0461 public function getAdapter() 0462 { 0463 return $this->rackspace; 0464 } 0465 /** 0466 * Get last HTTP request 0467 * 0468 * @return string 0469 */ 0470 public function getLastHttpRequest() 0471 { 0472 return $this->rackspace->getHttpClient()->getLastRequest(); 0473 } 0474 /** 0475 * Get the last HTTP response 0476 * 0477 * @return Zend_Http_Response 0478 */ 0479 public function getLastHttpResponse() 0480 { 0481 return $this->rackspace->getHttpClient()->getLastResponse(); 0482 } 0483 }