diff -r 877f952ae2bd -r 6b6c2214f778 web/lib/Zend/Cloud/Infrastructure/Adapter/Rackspace.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/Zend/Cloud/Infrastructure/Adapter/Rackspace.php Thu Mar 21 19:52:38 2013 +0100 @@ -0,0 +1,483 @@ + Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING, + 'SUSPENDED' => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED, + 'BUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'REBUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'QUEUE_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'PREP_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'VERIFY_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'PASSWORD' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'RESCUE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, + 'HARD_REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, + 'SHARE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'SHARE_IP_NO_CONFIG' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'DELETE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'UNKNOWN' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING + ); + /** + * Constructor + * + * @param array|Zend_Config $options + * @return void + */ + public function __construct($options = array()) + { + if (is_object($options)) { + if (method_exists($options, 'toArray')) { + $options= $options->toArray(); + } elseif ($options instanceof Traversable) { + $options = iterator_to_array($options); + } + } + + if (empty($options) || !is_array($options)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided'); + } + + if (!isset($options[self::RACKSPACE_USER])) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('Rackspace access user not specified!'); + } + + if (!isset($options[self::RACKSPACE_KEY])) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('Rackspace access key not specified!'); + } + + $this->accessUser = $options[self::RACKSPACE_USER]; + $this->accessKey = $options[self::RACKSPACE_KEY]; + + if (isset($options[self::RACKSPACE_REGION])) { + switch ($options[self::RACKSPACE_REGION]) { + case self::RACKSPACE_ZONE_UK: + $this->region= Zend_Service_Rackspace_Servers::UK_AUTH_URL; + break; + case self::RACKSPACE_ZONE_USA: + $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; + break; + default: + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The region is not valid'); + } + } else { + $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; + } + + try { + $this->rackspace = new Zend_Service_Rackspace_Servers($this->accessUser,$this->accessKey, $this->region); + } catch (Exception $e) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->rackspace->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + + } + /** + * Convert the attributes of Rackspace server into attributes of Infrastructure + * + * @param array $attr + * @return array|boolean + */ + protected function convertAttributes($attr) + { + $result = array(); + if (!empty($attr) && is_array($attr)) { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID] = $attr['id']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_NAME] = $attr['name']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS] = $this->mapStatus[$attr['status']]; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID] = $attr['imageId']; + if ($this->region==Zend_Service_Rackspace_Servers::US_AUTH_URL) { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_USA; + } else { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_UK; + } + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = $this->flavors[$attr['flavorId']]['ram']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = $this->flavors[$attr['flavorId']]['disk']; + } + return $result; + } + /** + * Return a list of the available instancies + * + * @return InstanceList|boolean + */ + public function listInstances() + { + $this->adapterResult = $this->rackspace->listServers(true); + if ($this->adapterResult===false) { + return false; + } + $array= $this->adapterResult->toArray(); + $result = array(); + foreach ($array as $instance) { + $result[]= $this->convertAttributes($instance); + } + return new Zend_Cloud_Infrastructure_InstanceList($this, $result); + } + /** + * Return the status of an instance + * + * @param string + * @return string|boolean + */ + public function statusInstance($id) + { + $this->adapterResult = $this->rackspace->getServer($id); + if ($this->adapterResult===false) { + return false; + } + $array= $this->adapterResult->toArray(); + return $this->mapStatus[$array['status']]; + } + /** + * Return the public DNS name/Ip address of the instance + * + * @param string $id + * @return string|boolean + */ + public function publicDnsInstance($id) + { + $this->adapterResult = $this->rackspace->getServerPublicIp($id); + if (empty($this->adapterResult)) { + return false; + } + return $this->adapterResult[0]; + } + /** + * Reboot an instance + * + * @param string $id + * @return boolean + */ + public function rebootInstance($id) + { + return $this->rackspace->rebootServer($id,true); + } + /** + * Create a new instance + * + * @param string $name + * @param array $options + * @return Instance|boolean + */ + public function createInstance($name, $options) + { + if (empty($name)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('You must specify the name of the instance'); + } + if (empty($options) || !is_array($options)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); + } + // @todo create an generic abstract definition for an instance? + $metadata= array(); + if (isset($options['metadata'])) { + $metadata= $options['metadata']; + unset($options['metadata']); + } + $files= array(); + if (isset($options['files'])) { + $files= $options['files']; + unset($options['files']); + } + $options['name']= $name; + $this->adapterResult = $this->rackspace->createServer($options,$metadata,$files); + if ($this->adapterResult===false) { + return false; + } + return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult->toArray())); + } + /** + * Stop an instance + * + * @param string $id + * @return boolean + */ + public function stopInstance($id) + { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter'); + } + + /** + * Start an instance + * + * @param string $id + * @return boolean + */ + public function startInstance($id) + { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter'); + } + + /** + * Destroy an instance + * + * @param string $id + * @return boolean + */ + public function destroyInstance($id) + { + $this->adapterResult= $this->rackspace->deleteServer($id); + return $this->adapterResult; + } + /** + * Return a list of all the available instance images + * + * @return ImageList|boolean + */ + public function imagesInstance() + { + $this->adapterResult = $this->rackspace->listImages(true); + if ($this->adapterResult===false) { + return false; + } + + $images= $this->adapterResult->toArray(); + $result= array(); + + foreach ($images as $image) { + if (strtolower($image['status'])==='active') { + if (strpos($image['name'],'Windows')!==false) { + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS; + } else { + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX; + } + if (strpos($image['name'],'x64')!==false) { + $arch = Zend_Cloud_Infrastructure_Image::ARCH_64BIT; + } else { + $arch = Zend_Cloud_Infrastructure_Image::ARCH_32BIT; + } + $result[]= array ( + Zend_Cloud_Infrastructure_Image::IMAGE_ID => $image['id'], + Zend_Cloud_Infrastructure_Image::IMAGE_NAME => $image['name'], + Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION => $image['name'], + Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $arch, + Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM => $platform, + ); + } + } + return new Zend_Cloud_Infrastructure_ImageList($result,$this->adapterResult); + } + /** + * Return all the available zones + * + * @return array + */ + public function zonesInstance() + { + return array(self::RACKSPACE_ZONE_USA,self::RACKSPACE_ZONE_UK); + } + /** + * Return the system information about the $metric of an instance + * NOTE: it works only for Linux servers + * + * @param string $id + * @param string $metric + * @param null|array $options + * @return array|boolean + */ + public function monitorInstance($id, $metric, $options = null) + { + if (!function_exists("ssh2_connect")) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('Monitor requires the PHP "SSH" extension (ext/ssh2)'); + } + if (empty($id)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('You must specify the id of the instance to monitor'); + } + if (empty($metric)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('You must specify the metric to monitor'); + } + if (!in_array($metric,$this->validMetrics)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception(sprintf('The metric "%s" is not valid', $metric)); + } + if (!empty($options) && !is_array($options)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); + } + + switch ($metric) { + case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: + $cmd= 'top -b -n '.self::MONITOR_CPU_SAMPLES.' | grep \'Cpu\''; + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: + $cmd= 'top -b -n 1 | grep \'Mem\''; + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: + $cmd= 'df --total | grep total'; + break; + } + if (empty($cmd)) { + require_once 'Zend/Cloud/Infrastructure/Exception.php'; + throw new Zend_Cloud_Infrastructure_Exception('The metric specified is not supported by the adapter'); + } + + $params= array( + Zend_Cloud_Infrastructure_Instance::SSH_USERNAME => $options['username'], + Zend_Cloud_Infrastructure_Instance::SSH_PASSWORD => $options['password'] + ); + $exec_time= time(); + $result= $this->deployInstance($id,$params,$cmd); + + if (empty($result)) { + return false; + } + + $monitor = array(); + $num = 0; + $average = 0; + + $outputs= explode("\n",$result); + foreach ($outputs as $output) { + if (!empty($output)) { + switch ($metric) { + case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: + if (preg_match('/(\d+\.\d)%us/', $output,$match)) { + $usage = (float) $match[1]; + } + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: + if (preg_match('/(\d+)k total/', $output,$match)) { + $total = (integer) $match[1]; + } + if (preg_match('/(\d+)k used/', $output,$match)) { + $used = (integer) $match[1]; + } + if ($total>0) { + $usage= (float) $used/$total; + } + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: + if (preg_match('/(\d+)%/', $output,$match)) { + $usage = (float) $match[1]; + } + break; + } + + $monitor['series'][] = array ( + 'timestamp' => $exec_time, + 'value' => number_format($usage,2).'%' + ); + + $average += $usage; + $exec_time+= 60; // seconds + $num++; + } + } + + if ($num>0) { + $monitor['average'] = number_format($average/$num,2).'%'; + } + return $monitor; + } + /** + * Get the adapter + * + * @return Zend_Service_Rackspace_Servers + */ + public function getAdapter() + { + return $this->rackspace; + } + /** + * Get last HTTP request + * + * @return string + */ + public function getLastHttpRequest() + { + return $this->rackspace->getHttpClient()->getLastRequest(); + } + /** + * Get the last HTTP response + * + * @return Zend_Http_Response + */ + public function getLastHttpResponse() + { + return $this->rackspace->getHttpClient()->getLastResponse(); + } +}