1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17
18 namespace OpenCloud;
19
20 use Guzzle\Http\Url;
21 use OpenCloud\Common\Exceptions;
22 use OpenCloud\Common\Http\Client;
23 use OpenCloud\Common\Http\Message\Formatter;
24 use OpenCloud\Common\Http\Message\RequestSubscriber;
25 use OpenCloud\Common\Lang;
26 use OpenCloud\Common\Log\Logger;
27 use OpenCloud\Common\Service\Catalog;
28 use OpenCloud\Common\Service\ServiceBuilder;
29 use OpenCloud\Identity\Resource\Tenant;
30 use OpenCloud\Identity\Resource\Token;
31 use OpenCloud\Identity\Resource\User;
32 use OpenCloud\Identity\Service as IdentityService;
33 use Psr\Log\LoggerInterface;
34
35 define('RACKSPACE_US', 'https://identity.api.rackspacecloud.com/v2.0/');
36 define('RACKSPACE_UK', 'https://lon.identity.api.rackspacecloud.com/v2.0/');
37
38 39 40 41 42
43 class OpenStack extends Client
44 {
45 46 47
48 private $secret = array();
49
50 51 52
53 private $token;
54
55 56 57
58 private $tenant;
59
60 61 62
63 private $catalog;
64
65 66 67
68 private $logger;
69
70 71 72
73 private $authUrl;
74
75 76 77
78 private $user;
79
80 public function __construct($url, array $secret, array $options = array())
81 {
82 if (isset($options['logger']) && $options['logger'] instanceof LoggerInterface) {
83 $this->setLogger($options['logger']);
84 }
85
86 $this->setSecret($secret);
87 $this->setAuthUrl($url);
88
89 parent::__construct($url, $options);
90
91 $this->addSubscriber(RequestSubscriber::getInstance());
92 $this->setDefaultOption('headers/Accept', 'application/json');
93 }
94
95 96 97 98 99 100
101 public function setSecret(array $secret = array())
102 {
103 $this->secret = $secret;
104
105 return $this;
106 }
107
108 109 110 111 112
113 public function getSecret()
114 {
115 return $this->secret;
116 }
117
118 119 120 121 122 123 124 125
126 public function setToken($token)
127 {
128 $identity = IdentityService::factory($this);
129
130 if (is_string($token)) {
131 if (!$this->token) {
132 $this->setTokenObject($identity->resource('Token'));
133 }
134 $this->token->setId($token);
135 } else {
136 $this->setTokenObject($identity->resource('Token', $token));
137 }
138
139 return $this;
140 }
141
142 143 144 145 146
147 public function getToken()
148 {
149 return ($this->getTokenObject()) ? $this->getTokenObject()->getId() : null;
150 }
151
152 153 154
155 public function setTokenObject(Token $token)
156 {
157 $this->token = $token;
158 }
159
160 161 162
163 public function getTokenObject()
164 {
165 return $this->token;
166 }
167
168 169 170
171 public function setExpiration($expiration)
172 {
173 $this->getLogger()->warning(Logger::deprecated(__METHOD__, '::getTokenObject()->setExpires()'));
174 if ($this->getTokenObject()) {
175 $this->getTokenObject()->setExpires($expiration);
176 }
177
178 return $this;
179 }
180
181 182 183
184 public function getExpiration()
185 {
186 $this->getLogger()->warning(Logger::deprecated(__METHOD__, '::getTokenObject()->getExpires()'));
187 if ($this->getTokenObject()) {
188 return $this->getTokenObject()->getExpires();
189 }
190 }
191
192 193 194 195 196 197 198 199
200 public function setTenant($tenant)
201 {
202 $identity = IdentityService::factory($this);
203
204 if (is_numeric($tenant) || is_string($tenant)) {
205 if (!$this->tenant) {
206 $this->setTenantObject($identity->resource('Tenant'));
207 }
208 $this->tenant->setId($tenant);
209 } else {
210 $this->setTenantObject($identity->resource('Tenant', $tenant));
211 }
212
213 return $this;
214 }
215
216 217 218 219 220
221 public function getTenant()
222 {
223 return ($this->getTenantObject()) ? $this->getTenantObject()->getId() : null;
224 }
225
226 227 228 229 230
231 public function setTenantObject(Tenant $tenant)
232 {
233 $this->tenant = $tenant;
234 }
235
236 237 238 239 240
241 public function getTenantObject()
242 {
243 return $this->tenant;
244 }
245
246 247 248 249 250 251
252 public function setCatalog($catalog)
253 {
254 $this->catalog = Catalog::factory($catalog);
255
256 return $this;
257 }
258
259 260 261 262 263
264 public function getCatalog()
265 {
266 return $this->catalog;
267 }
268
269 270 271 272 273
274 public function setLogger(LoggerInterface $logger)
275 {
276 $this->logger = $logger;
277
278 return $this;
279 }
280
281 282 283
284 public function getLogger()
285 {
286 if (null === $this->logger) {
287 $this->setLogger(new Common\Log\Logger);
288 }
289
290 return $this->logger;
291 }
292
293 294 295
296 public function hasLogger()
297 {
298 return (null !== $this->logger);
299 }
300
301 302 303
304 public function hasExpired()
305 {
306 $this->getLogger()->warning(Logger::deprecated(__METHOD__, 'getTokenObject()->hasExpired()'));
307
308 return $this->getTokenObject() && $this->getTokenObject()->hasExpired();
309 }
310
311 312 313 314 315 316
317 public function getCredentials()
318 {
319 if (!empty($this->secret['username']) && !empty($this->secret['password'])) {
320 $credentials = array('auth' => array(
321 'passwordCredentials' => array(
322 'username' => $this->secret['username'],
323 'password' => $this->secret['password']
324 )
325 ));
326
327 if (!empty($this->secret['tenantName'])) {
328 $credentials['auth']['tenantName'] = $this->secret['tenantName'];
329 } elseif (!empty($this->secret['tenantId'])) {
330 $credentials['auth']['tenantId'] = $this->secret['tenantId'];
331 }
332
333 return json_encode($credentials);
334 } else {
335 throw new Exceptions\CredentialError(
336 Lang::translate('Unrecognized credential secret')
337 );
338 }
339 }
340
341 342 343 344
345 public function setAuthUrl($url)
346 {
347 $this->authUrl = Url::factory($url);
348
349 return $this;
350 }
351
352 353 354
355 public function getAuthUrl()
356 {
357 return $this->authUrl;
358 }
359
360 361 362 363 364
365 public function setUser(User $user)
366 {
367 $this->user = $user;
368 }
369
370 371 372
373 public function getUser()
374 {
375 return $this->user;
376 }
377
378 379 380 381 382 383
384 public function authenticate()
385 {
386
387
388 $this->updateTokenHeader('');
389
390 $identity = IdentityService::factory($this);
391 $response = $identity->generateToken($this->getCredentials());
392
393 $body = Formatter::decode($response);
394
395 $this->setCatalog($body->access->serviceCatalog);
396 $this->setTokenObject($identity->resource('Token', $body->access->token));
397 $this->setUser($identity->resource('User', $body->access->user));
398
399 if (isset($body->access->token->tenant)) {
400 $this->setTenantObject($identity->resource('Tenant', $body->access->token->tenant));
401 }
402
403
404 $this->updateTokenHeader($this->getToken());
405 }
406
407 408 409
410 public function getUrl()
411 {
412 return $this->getBaseUrl();
413 }
414
415 416 417 418
419 public function exportCredentials()
420 {
421 if ($this->hasExpired()) {
422 $this->authenticate();
423 }
424
425 return array(
426 'token' => $this->getToken(),
427 'expiration' => $this->getExpiration(),
428 'tenant' => $this->getTenant(),
429 'catalog' => $this->getCatalog()
430 );
431 }
432
433 434 435 436 437
438 public function importCredentials(array $values)
439 {
440 if (!empty($values['token'])) {
441 $this->setToken($values['token']);
442 $this->updateTokenHeader($this->getToken());
443 }
444 if (!empty($values['expiration'])) {
445 $this->setExpiration($values['expiration']);
446 }
447 if (!empty($values['tenant'])) {
448 $this->setTenant($values['tenant']);
449 }
450 if (!empty($values['catalog'])) {
451 $this->setCatalog($values['catalog']);
452 }
453 }
454
455 456 457 458 459 460
461 private function updateTokenHeader($token)
462 {
463 $this->setDefaultOption('headers/X-Auth-Token', (string) $token);
464 }
465
466 467 468 469 470 471 472 473
474 public function objectStoreService($name = null, $region = null, $urltype = null)
475 {
476 return ServiceBuilder::factory($this, 'OpenCloud\ObjectStore\Service', array(
477 'name' => $name,
478 'region' => $region,
479 'urlType' => $urltype
480 ));
481 }
482
483 484 485 486 487 488 489 490
491 public function computeService($name = null, $region = null, $urltype = null)
492 {
493 return ServiceBuilder::factory($this, 'OpenCloud\Compute\Service', array(
494 'name' => $name,
495 'region' => $region,
496 'urlType' => $urltype
497 ));
498 }
499
500 501 502 503 504 505 506 507 508
509 public function orchestrationService($name = null, $region = null, $urltype = null)
510 {
511 return ServiceBuilder::factory($this, 'OpenCloud\Orchestration\Service', array(
512 'name' => $name,
513 'region' => $region,
514 'urlType' => $urltype
515 ));
516 }
517
518 519 520 521 522 523 524 525
526 public function volumeService($name = null, $region = null, $urltype = null)
527 {
528 return ServiceBuilder::factory($this, 'OpenCloud\Volume\Service', array(
529 'name' => $name,
530 'region' => $region,
531 'urlType' => $urltype
532 ));
533 }
534
535 536 537 538 539
540 public function identityService()
541 {
542 $service = IdentityService::factory($this);
543 $this->authenticate();
544
545 return $service;
546 }
547
548 549 550 551 552 553 554 555
556 public function imageService($name = null, $region = null, $urltype = null)
557 {
558 return ServiceBuilder::factory($this, 'OpenCloud\Image\Service', array(
559 'name' => $name,
560 'region' => $region,
561 'urlType' => $urltype
562 ));
563 }
564
565 566 567 568 569 570 571 572 573
574 public function networkingService($name = null, $region = null, $urltype = null)
575 {
576 return ServiceBuilder::factory($this, 'OpenCloud\Networking\Service', array(
577 'name' => $name,
578 'region' => $region,
579 'urlType' => $urltype
580 ));
581 }
582 }
583