PageRenderTime 60ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/Cloud/Infrastructure/Adapter/Ec2.php

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