PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/rackspace-cloud-files-cdn/lib/php-opencloud-1.5.10/lib/OpenCloud/Common/Service.php

https://bitbucket.org/theshipswakecreative/psw
PHP | 420 lines | 213 code | 52 blank | 155 comment | 40 complexity | fdbc7d579c1f2710b0d28c08a954a3fd MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0
  1. <?php
  2. /**
  3. * An abstraction that defines a cloud service
  4. *
  5. * @copyright 2012-2013 Rackspace Hosting, Inc.
  6. * See COPYING for licensing information
  7. *
  8. * @package phpOpenCloud
  9. * @version 1.0
  10. * @author Glen Campbell <glen.campbell@rackspace.com>
  11. */
  12. namespace OpenCloud\Common;
  13. use OpenCloud\Common\Base;
  14. use OpenCloud\Common\Lang;
  15. use OpenCloud\OpenStack;
  16. use OpenCloud\Common\Exceptions;
  17. /**
  18. * This class defines a "service"—a relationship between a specific OpenStack
  19. * and a provided service, represented by a URL in the service catalog.
  20. *
  21. * Because Service is an abstract class, it cannot be called directly. Provider
  22. * services such as Rackspace Cloud Servers or OpenStack Swift are each
  23. * subclassed from Service.
  24. *
  25. * @author Glen Campbell <glen.campbell@rackspace.com>
  26. */
  27. abstract class Service extends Base
  28. {
  29. protected $conn;
  30. private $service_type;
  31. private $service_name;
  32. private $service_region;
  33. private $service_url;
  34. protected $_namespaces = array();
  35. /**
  36. * Creates a service on the specified connection
  37. *
  38. * Usage: `$x = new Service($conn, $type, $name, $region, $urltype);`
  39. * The service's URL is defined in the OpenStack's serviceCatalog; it
  40. * uses the $type, $name, $region, and $urltype to find the proper URL
  41. * and set it. If it cannot find a URL in the service catalog that matches
  42. * the criteria, then an exception is thrown.
  43. *
  44. * @param OpenStack $conn - a Connection object
  45. * @param string $type - the service type (e.g., "compute")
  46. * @param string $name - the service name (e.g., "cloudServersOpenStack")
  47. * @param string $region - the region (e.g., "ORD")
  48. * @param string $urltype - the specified URL from the catalog
  49. * (e.g., "publicURL")
  50. */
  51. public function __construct(
  52. OpenStack $conn,
  53. $type,
  54. $name,
  55. $region,
  56. $urltype = RAXSDK_URL_PUBLIC
  57. ) {
  58. $this->conn = $conn;
  59. $this->service_type = $type;
  60. $this->service_name = $name;
  61. $this->service_region = $region;
  62. $this->service_url = $this->get_endpoint($type, $name, $region, $urltype);
  63. }
  64. /**
  65. * Returns the connection used to create the Service.
  66. *
  67. * @return OpenCloud\OpenStack
  68. */
  69. public function Connection() {
  70. return $this->conn;
  71. }
  72. /**
  73. * Returns the URL for the Service
  74. *
  75. * @param string $resource optional sub-resource
  76. * @param array $query optional k/v pairs for query strings
  77. * @return string
  78. */
  79. public function Url($resource = '', array $param = array())
  80. {
  81. $baseurl = $this->service_url;
  82. if ($resource) {
  83. $baseurl = Lang::noslash($baseurl).'/'.$resource;
  84. }
  85. if (!empty($param)) {
  86. $baseurl .= '?'.$this->MakeQueryString($param);
  87. }
  88. return $baseurl;
  89. }
  90. /**
  91. * Returns the /extensions for the service
  92. *
  93. * @api
  94. * @return array of objects
  95. */
  96. public function Extensions()
  97. {
  98. $ext = $this->GetMetaUrl('extensions');
  99. if (is_object($ext) && isset($ext->extensions)) {
  100. return $ext->extensions;
  101. } else {
  102. return array();
  103. }
  104. }
  105. /**
  106. * Returns the /limits for the service
  107. *
  108. * @api
  109. * @return array of limits
  110. */
  111. public function Limits()
  112. {
  113. $lim = $this->GetMetaUrl('limits');
  114. if (is_object($lim)) {
  115. return $lim->limits;
  116. } else {
  117. return array();
  118. }
  119. }
  120. /**
  121. * Performs an authenticated request
  122. *
  123. * This method handles the addition of authentication headers to each
  124. * request. It always adds the X-Auth-Token: header and will add the
  125. * X-Auth-Project-Id: header if there is a tenant defined on the
  126. * connection.
  127. *
  128. * @param string $url The URL of the request
  129. * @param string $method The HTTP method (defaults to "GET")
  130. * @param array $headers An associative array of headers
  131. * @param string $body An optional body for POST/PUT requests
  132. * @return \OpenCloud\HttpResult
  133. */
  134. public function Request(
  135. $url,
  136. $method = 'GET',
  137. array $headers = array(),
  138. $body = null
  139. ) {
  140. $headers['X-Auth-Token'] = $this->conn->Token();
  141. if ($tenant = $this->conn->Tenant()) {
  142. $headers['X-Auth-Project-Id'] = $tenant;
  143. }
  144. return $this->conn->Request($url, $method, $headers, $body);
  145. }
  146. /**
  147. * returns a collection of objects
  148. *
  149. * @param string $class the class of objects to fetch
  150. * @param string $url (optional) the URL to retrieve
  151. * @param mixed $parent (optional) the parent service/object
  152. * @param array $parm (optional) array of key/value pairs to use as
  153. * query strings
  154. * @return \OpenCloud\Collection
  155. */
  156. public function Collection($class, $url = null, $parent = null, array $parm = array())
  157. {
  158. // set the element name
  159. $collection = $class::JsonCollectionName();
  160. $element = $class::JsonCollectionElement();
  161. // save the parent
  162. if (!isset($parent)) {
  163. $parent = $this;
  164. }
  165. // determine the URL
  166. if (!$url) {
  167. $url = $parent->Url($class::ResourceName());
  168. }
  169. // add query string parameters
  170. if (count($parm)) {
  171. $url .= '?' . $this->MakeQueryString($parm);
  172. }
  173. // save debug info
  174. $this->debug('%s:Collection(%s, %s, %s)', get_class($this), $url, $class, $collection);
  175. // fetch the list
  176. $response = $this->Request($url);
  177. $this->debug('response %d [%s]', $response->HttpStatus(), $response->HttpBody());
  178. // check return code
  179. if ($response->HttpStatus() > 204) {
  180. throw new Exceptions\CollectionError(sprintf(
  181. Lang::translate('Unable to retrieve [%s] list from [%s], status [%d] response [%s]'),
  182. $class,
  183. $url,
  184. $response->HttpStatus(),
  185. $response->HttpBody()
  186. ));
  187. }
  188. // handle empty response
  189. if (strlen($response->HttpBody()) == 0) {
  190. return new Collection($parent, $class, array());
  191. }
  192. // Parse the return
  193. $the_response = $response->HttpBody();
  194. $obj = json_decode($the_response, true);
  195. if ($this->CheckJsonError()) {
  196. return false;
  197. }
  198. // see if there is a "next" link
  199. if (isset($obj->links)) {
  200. if (is_array($obj->links)) {
  201. foreach($obj->links as $link) {
  202. if (isset($link->rel) && ($link->rel=='next')) {
  203. if (isset($link->href)) {
  204. $next_page_url = $link->href;
  205. } else {
  206. throw new Exceptions\DomainError(Lang::translate('unexpected [links] found with no [href]'));
  207. }
  208. }
  209. }
  210. }
  211. }
  212. // and say goodbye
  213. if (!$collection) {
  214. // $coll_obj = new Collection($parent, $class, $obj);
  215. $coll_obj = $obj;
  216. } elseif (isset($obj->$collection)) {
  217. if (!$element) {
  218. // $coll_obj = new Collection($parent, $class, $obj->$collection);
  219. $coll_obj = $obj[$collection];
  220. } else {
  221. // handle element levels
  222. $arr = array();
  223. foreach($obj->$collection as $index => $item) {
  224. $arr[] = $item->$element;
  225. }
  226. // $coll_obj = new Collection($parent, $class, $arr);
  227. $coll_obj = $arr;
  228. }
  229. } else {
  230. // $coll_obj = new Collection($parent, $class, array());
  231. $coll_obj = array();
  232. }
  233. // if there's a $next_page_url, then we need to establish a callback method
  234. if (isset($next_page_url)) {
  235. $coll_obj->SetNextPageCallback(array($this, 'Collection'), $next_page_url);
  236. }
  237. return $coll_obj;
  238. }
  239. /**
  240. * returns the Region associated with the service
  241. *
  242. * @api
  243. * @return string
  244. */
  245. public function Region()
  246. {
  247. return $this->service_region;
  248. }
  249. /**
  250. * returns the serviceName associated with the service
  251. *
  252. * This is used by DNS for PTR record lookups
  253. *
  254. * @api
  255. * @return string
  256. */
  257. public function Name()
  258. {
  259. return $this->service_name;
  260. }
  261. /**
  262. * Returns a list of supported namespaces
  263. *
  264. * @return array
  265. */
  266. public function namespaces()
  267. {
  268. if (!isset($this->_namespaces)) {
  269. return array();
  270. }
  271. if (is_array($this->_namespaces)) {
  272. return $this->_namespaces;
  273. }
  274. return array();
  275. }
  276. /**
  277. * Given a service type, name, and region, return the url
  278. *
  279. * This function ensures that services are represented by an entry in the
  280. * service catalog, and NOT by an arbitrarily-constructed URL.
  281. *
  282. * Note that it will always return the first match found in the
  283. * service catalog (there *should* be only one, but you never know...)
  284. *
  285. * @param string $type The OpenStack service type ("compute" or
  286. * "object-store", for example
  287. * @param string $name The name of the service in the service catlog
  288. * @param string $region The region of the service
  289. * @param string $urltype The URL type; defaults to "publicURL"
  290. * @return string The URL of the service
  291. */
  292. private function get_endpoint($type, $name, $region, $urltype = 'publicURL')
  293. {
  294. $found = 0;
  295. $catalog = $this->conn->serviceCatalog();
  296. // search each service to find The One
  297. foreach($catalog as $service) {
  298. // first, compare the type ("compute") and name ("openstack")
  299. if (!strcasecmp($service->type, $type) && !strcasecmp($service->name, $name)) {
  300. // found the service, now we need to find the region
  301. foreach($service->endpoints as $endpoint) {
  302. // regionless service
  303. if (!isset($endpoint->region) && isset($endpoint->$urltype)) {
  304. ++$found;
  305. return $endpoint->$urltype;
  306. } elseif (!strcasecmp($endpoint->region, $region) && isset($endpoint->$urltype)) {
  307. // now we have a match! Yay!
  308. ++$found;
  309. return $endpoint->$urltype;
  310. }
  311. }
  312. }
  313. }
  314. // error if not found
  315. if (!$found) {
  316. throw new Exceptions\EndpointError(
  317. sprintf(Lang::translate('No endpoints for service type [%s], name [%s], region [%s] and urlType [%s]'),
  318. $type,
  319. $name,
  320. $region,
  321. $urltype
  322. ));
  323. }
  324. }
  325. /**
  326. * Constructs a specified URL from the subresource
  327. *
  328. * Given a subresource (e.g., "extensions"), this constructs the proper
  329. * URL and retrieves the resource.
  330. *
  331. * @param string $resource The resource requested; should NOT have slashes
  332. * at the beginning or end
  333. * @return \stdClass object
  334. */
  335. private function GetMetaUrl($resource)
  336. {
  337. $urlbase = $this->get_endpoint(
  338. $this->service_type,
  339. $this->service_name,
  340. $this->service_region,
  341. RAXSDK_URL_PUBLIC
  342. );
  343. if ($urlbase == '') {
  344. return array();
  345. }
  346. $ext_url = Lang::noslash($urlbase) . '/' . $resource;
  347. $response = $this->Request($ext_url);
  348. // check for NOT FOUND response
  349. if ($response->HttpStatus() == 404) {
  350. return array();
  351. }
  352. // check for error status
  353. if ($response->HttpStatus() >= 300) {
  354. throw new Exceptions\HttpError(sprintf(
  355. Lang::translate('Error accessing [%s] - status [%d], response [%s]'),
  356. $urlbase,
  357. $response->HttpStatus(),
  358. $response->HttpBody()
  359. ));
  360. }
  361. // we're good; proceed
  362. $obj = json_decode($response->HttpBody());
  363. if ($this->CheckJsonError()) {
  364. return false;
  365. }
  366. return $obj;
  367. }
  368. }