Overview

Namespaces

  • OpenCloud
    • Autoscale
      • Resource
    • CloudMonitoring
      • Exception
      • Resource
    • Common
      • Collection
      • Constants
      • Exceptions
      • Http
        • Message
      • Identity
      • Log
      • Service
    • Compute
      • Constants
      • Exception
      • Resource
    • Database
      • Resource
    • DNS
      • Resource
    • LoadBalancer
      • Resource
    • ObjectStore
      • Constants
      • Exception
      • Resource
      • Upload
    • Orchestration
    • Queues
      • Exception
      • Resource
    • Volume
      • Resource
  • PHP

Classes

  • AbstractService
  • Catalog
  • CatalogItem
  • Endpoint
  • NovaService
  • ServiceBuilder
  • Overview
  • Namespace
  • Class
  • Tree
  • Download
  1: <?php
  2: /**
  3:  * PHP OpenCloud library.
  4:  * 
  5:  * @copyright 2013 Rackspace Hosting, Inc. See LICENSE for information.
  6:  * @license   https://www.apache.org/licenses/LICENSE-2.0
  7:  * @author    Glen Campbell <glen.campbell@rackspace.com>
  8:  * @author    Jamie Hannaford <jamie.hannaford@rackspace.com>
  9:  */
 10: 
 11: namespace OpenCloud\Common\Service;
 12: 
 13: use OpenCloud\Common\Base;
 14: use OpenCloud\Common\Exceptions;
 15: use OpenCloud\Common\Collection\PaginatedIterator;
 16: use OpenCloud\Common\Http\Client;
 17: use OpenCloud\Common\PersistentObject;
 18: use OpenCloud\Common\Http\Message\Formatter;
 19: use Guzzle\Http\Url;
 20: use Guzzle\Http\Exception\BadResponseException;
 21: use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 22: 
 23: /**
 24:  * This class defines a cloud service; a relationship between a specific OpenStack
 25:  * and a provided service, represented by a URL in the service catalog.
 26:  *
 27:  * Because Service is an abstract class, it cannot be called directly. Provider
 28:  * services such as Rackspace Cloud Servers or OpenStack Swift are each
 29:  * subclassed from Service.
 30:  */
 31: abstract class AbstractService extends Base
 32: {
 33:     const DEFAULT_REGION   = 'DFW';
 34:     const DEFAULT_URL_TYPE = 'publicURL';
 35:     
 36:     /**
 37:      * @var OpenCloud\Common\Http\Client The client which interacts with the API.
 38:      */
 39:     protected $client;
 40:     
 41:     /**
 42:      * @var string The type of this service, as set in Catalog. 
 43:      */
 44:     private $type;
 45:     
 46:     /**
 47:      * @var string The name of this service, as set in Catalog.
 48:      */
 49:     private $name;
 50:     
 51:     /**
 52:      * @var string The chosen region(s) for this service.
 53:      */
 54:     private $region;
 55:     
 56:     /**
 57:      * @var string Either 'publicURL' or 'privateURL'.
 58:      */
 59:     private $urlType;
 60:     
 61:     /**
 62:      * @var \OpenCloud\Common\Service\Endpoint The endpoints for this service.
 63:      */
 64:     private $endpoint;
 65:     
 66:     /**
 67:      * @var array Namespaces for this service.
 68:      */
 69:     protected $namespaces = array();
 70: 
 71:     /**
 72:      * @var array A collection of resource models that this service has control over.
 73:      */
 74:     protected $resources = array();
 75: 
 76:     /**
 77:      * Creates a service object, based off the specified client.
 78:      *
 79:      * The service's URL is defined in the client's serviceCatalog; it
 80:      * uses the $type, $name, $region, and $urlType to find the proper endpoint
 81:      * and set it. If it cannot find a URL in the service catalog that matches
 82:      * the criteria, then an exception is thrown.
 83:      *
 84:      * @param Client $client  Client object
 85:      * @param string $type    Service type (e.g. 'compute')
 86:      * @param string $name    Service name (e.g. 'cloudServersOpenStack')
 87:      * @param string $region  Service region (e.g. 'DFW', 'ORD', 'IAD', 'LON', 'SYD')
 88:      * @param string $urlType Either 'publicURL' or 'privateURL'
 89:      */
 90:     public function __construct(Client $client, $type = null, $name = null, $region = null, $urlType = null)
 91:     {
 92:         $this->setClient($client);
 93: 
 94:         $this->type = $type ?: static::DEFAULT_TYPE;
 95:         $this->name = $name ?: static::DEFAULT_NAME;
 96:         $this->region = $region ?: static::DEFAULT_REGION;
 97:         $this->urlType = $urlType ?: static::DEFAULT_URL_TYPE;
 98: 
 99:         $this->endpoint = $this->findEndpoint();
100:         $this->client->setBaseUrl($this->getBaseUrl());
101: 
102:         if ($this instanceof EventSubscriberInterface) {
103:             $this->client->getEventDispatcher()->addSubscriber($this);
104:         }
105:     }
106: 
107:     /**
108:      * @param Client $client
109:      */
110:     public function setClient(Client $client)
111:     {
112:         $this->client = $client;
113:     }
114: 
115:     /**
116:      * @return OpenCloud\Common\Http\Client
117:      */
118:     public function getClient()
119:     {
120:         return $this->client;
121:     }
122: 
123:     /**
124:      * @return string
125:      */
126:     public function getType()
127:     {
128:         return $this->type;
129:     }
130: 
131:     /**
132:      * @return string
133:      */
134:     public function getRegion()
135:     {
136:         return $this->region;
137:     }
138: 
139:     /**
140:      * @return string
141:      */
142:     public function getName()
143:     {
144:         return $this->name;
145:     }
146: 
147:     /**
148:      * @return string
149:      */
150:     public function getUrlType()
151:     {
152:         return $this->urlType;
153:     }
154: 
155:     /**
156:      * @return Endpoint|OpenCloud\Common\Service\Endpoint
157:      */
158:     public function getEndpoint()
159:     {
160:         return $this->endpoint;
161:     }
162:     
163:     /**
164:      * @deprecated
165:      */
166:     public function region()
167:     {
168:         return $this->getRegion();
169:     }
170: 
171:     /**
172:      * @deprecated
173:      */
174:     public function name()
175:     {
176:         return $this->name;
177:     }
178:     
179:     /**
180:      * Returns the URL for the Service
181:      *
182:      * @param  string $path  URL path segment
183:      * @param  array  $query Array of query pairs
184:      * @return Guzzle\Http\Url
185:      */
186:     public function getUrl($path = null, array $query = array())
187:     {
188:         return Url::factory($this->getBaseUrl())
189:             ->addPath($path)
190:             ->setQuery($query);
191:     }
192:     
193:     /**
194:      * @deprecated
195:      */
196:     public function url($path = null, array $query = array()) 
197:     {
198:         return $this->getUrl($path, $query);
199:     }
200: 
201:     /**
202:      * Returns the /extensions for the service
203:      *
204:      * @api
205:      * @return array of objects
206:      */
207:     public function getExtensions()
208:     {
209:         $ext = $this->getMetaUrl('extensions');
210:         return (is_object($ext) && isset($ext->extensions)) ? $ext->extensions : array();
211:     }
212: 
213:     /**
214:      * Returns the limits for the service
215:      *
216:      * @return array of limits
217:      */
218:     public function limits()
219:     {
220:         $limits = $this->getMetaUrl('limits');
221:         return (is_object($limits)) ? $limits->limits : array();
222:     }
223: 
224:     /**
225:      * Returns a list of supported namespaces
226:      *
227:      * @return array
228:      */
229:     public function namespaces()
230:     {
231:         return (isset($this->namespaces) && is_array($this->namespaces)) 
232:             ? $this->namespaces 
233:             : array();
234:     }
235: 
236:     /**
237:      * Extracts the appropriate endpoint from the service catalog based on the
238:      * name and type of a service, and sets for further use.
239:      *
240:      * @return \OpenCloud\Common\Service\Endpoint
241:      * @throws \OpenCloud\Common\Exceptions\EndpointError
242:      */
243:     private function findEndpoint()
244:     {
245:         if (!$this->getClient()->getCatalog()) {
246:             $this->getClient()->authenticate();
247:         }
248:         
249:         $catalog = $this->getClient()->getCatalog();
250: 
251:         // Search each service to find The One
252:         foreach ($catalog->getItems() as $service) {
253:             if ($service->hasType($this->type) && $service->hasName($this->name)) {
254:                 return Endpoint::factory($service->getEndpointFromRegion($this->region));
255:             }
256:         }
257: 
258:         throw new Exceptions\EndpointError(sprintf(
259:             'No endpoints for service type [%s], name [%s], region [%s] and urlType [%s]',
260:             $this->type,
261:             $this->name,
262:             $this->region,
263:             $this->urlType
264:         ));
265:     }
266: 
267:     /**
268:      * Constructs a specified URL from the subresource
269:      *
270:      * Given a subresource (e.g., "extensions"), this constructs the proper
271:      * URL and retrieves the resource.
272:      *
273:      * @param string $resource The resource requested; should NOT have slashes
274:      *      at the beginning or end
275:      * @return \stdClass object
276:      */
277:     private function getMetaUrl($resource)
278:     {
279:         $url = clone $this->getBaseUrl();
280:         $url->addPath($resource);
281:         try {
282:             $response = $this->getClient()->get($url)->send();
283:             return Formatter::decode($response);
284:         } catch (BadResponseException $e) {
285:             // @codeCoverageIgnoreStart
286:             return array();
287:             // @codeCoverageIgnoreEnd
288:         }
289:     }
290:     
291:     /**
292:      * Get all associated resources for this service.
293:      * 
294:      * @access public
295:      * @return void
296:      */
297:     public function getResources()
298:     {
299:         return $this->resources;
300:     }
301: 
302:     /**
303:      * Internal method for accessing child namespace from parent scope.
304:      * 
305:      * @return type
306:      */
307:     protected function getCurrentNamespace()
308:     {
309:         $namespace = get_class($this);
310:         return substr($namespace, 0, strrpos($namespace, '\\'));
311:     }
312:     
313:     /**
314:      * Resolves FQCN for local resource.
315:      *
316:      * @param  $resourceName
317:      * @return string
318:      * @throws \OpenCloud\Common\Exceptions\UnrecognizedServiceError
319:      */
320:     protected function resolveResourceClass($resourceName)
321:     {
322:         $className = substr_count($resourceName, '\\') 
323:             ? $resourceName 
324:             : $this->getCurrentNamespace() . '\\Resource\\' . ucfirst($resourceName);
325:         
326:         if (!class_exists($className)) {
327:             throw new Exceptions\UnrecognizedServiceError(sprintf(
328:                 '%s resource does not exist, please try one of the following: %s', 
329:                 $resourceName, 
330:                 implode(', ', $this->getResources())
331:             ));
332:         }
333:         
334:         return $className;
335:     }
336:     
337:     /**
338:      * Factory method for instantiating resource objects.
339:      *
340:      * @param  string $resourceName
341:      * @param  mixed $info (default: null)
342:      * @param  mixed $parent The parent object
343:      * @return object
344:      */
345:     public function resource($resourceName, $info = null, $parent = null)
346:     {
347:         $className = $this->resolveResourceClass($resourceName);
348: 
349:         $resource = new $className($this);
350:         if ($parent) {
351:             $resource->setParent($parent);
352:         }
353: 
354:         $resource->populate($info);
355: 
356:         return $resource;
357:     }
358:     
359:     /**
360:      * Factory method for instantiating a resource collection.
361:      *
362:      * @param string      $resourceName
363:      * @param string|null $url
364:      * @param string|null $service
365:      * @return OpenCloud\Common\Collection
366:      */
367:     public function resourceList($resourceName, $url = null, $parent = null)
368:     {
369:         $className = $this->resolveResourceClass($resourceName);
370:         return $this->collection($className, $url, $parent);
371:     }
372: 
373:     /**
374:      * Get the base URL for this service, based on the set URL type.
375:      * @return \Guzzle\Http\Url
376:      * @throws \OpenCloud\Common\Exceptions\ServiceException
377:      */
378:     public function getBaseUrl()
379:     {
380:         $url = ($this->urlType == 'publicURL') 
381:             ? $this->endpoint->getPublicUrl() 
382:             : $this->endpoint->getPrivateUrl();
383: 
384:         if ($url === null) {
385:             throw new Exceptions\ServiceException(sprintf(
386:                 'The base %s could not be found. Perhaps the service '
387:                 . 'you are using requires a different URL type, or does '
388:                 . 'not support this region.',
389:                 $this->urlType
390:             ));
391:         }
392:         
393:         return $url;
394:     }
395: 
396:     /**
397:      * @codeCoverageIgnore
398:      */
399:     public function collection($class, $url = null, $parent = null, $data = null)
400:     {
401:         if (!$parent) {
402:             $parent = $this;
403:         }
404: 
405:         $resource = $this->resolveResourceClass($class);
406: 
407:         if (!$url) {
408:             $url = $parent->getUrl($resource::resourceName());
409:         }
410: 
411:         $options = $this->makeResourceIteratorOptions($this->resolveResourceClass($class));
412:         $options['baseUrl'] = $url;
413: 
414:         return PaginatedIterator::factory($parent, $options, $data);
415:     }
416: 
417: }
PHP OpenCloud API API documentation generated by ApiGen 2.8.0