1: <?php
2: /**
3: * Copyright 2012-2014 Rackspace US, Inc.
4: *
5: * Licensed under the Apache License, Version 2.0 (the "License");
6: * you may not use this file except in compliance with the License.
7: * You may obtain a copy of the License at
8: *
9: * http://www.apache.org/licenses/LICENSE-2.0
10: *
11: * Unless required by applicable law or agreed to in writing, software
12: * distributed under the License is distributed on an "AS IS" BASIS,
13: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14: * See the License for the specific language governing permissions and
15: * limitations under the License.
16: */
17:
18: namespace OpenCloud\Common\Service;
19:
20: use Guzzle\Http\Url;
21: use OpenCloud\OpenStack;
22: use OpenCloud\Common\Http\Message\Formatter;
23: use OpenCloud\Common\Exceptions\UnsupportedVersionError;
24:
25: /**
26: * An endpoint serves as a location which receives and emits API interactions. It will therefore also host
27: * particular API resources. Each endpoint object has different access methods - one receives network connections over
28: * the public Internet, another receives traffic through an internal network. You will be able to access the latter
29: * from a Server, for example, in the same Region - which will incur no bandwidth charges, and be quicker.
30: */
31: class Endpoint
32: {
33: /**
34: * @var \Guzzle\Http\Url
35: */
36: private $publicUrl;
37:
38: /**
39: * @var \Guzzle\Http\Url
40: */
41: private $privateUrl;
42:
43: /**
44: * @var string
45: */
46: private $region;
47:
48: /**
49: * @param $object
50: * @param string $supportedServiceVersion Service version supported by the SDK
51: * @param OpenCloud\OpenStack $client OpenStack client
52: * @return Endpoint
53: */
54: public static function factory($object, $supportedServiceVersion, OpenStack $client)
55: {
56: $endpoint = new self();
57:
58: if (isset($object->publicURL)) {
59: $endpoint->setPublicUrl($endpoint->getVersionedUrl($object->publicURL, $supportedServiceVersion, $client));
60: }
61: if (isset($object->internalURL)) {
62: $endpoint->setPrivateUrl($endpoint->getVersionedUrl($object->internalURL, $supportedServiceVersion, $client));
63: }
64: if (isset($object->region)) {
65: $endpoint->setRegion($object->region);
66: }
67:
68: return $endpoint;
69: }
70:
71: /**
72: * @param $publicUrl
73: * @return $this
74: */
75: public function setPublicUrl(Url $publicUrl)
76: {
77: $this->publicUrl = $publicUrl;
78:
79: return $this;
80: }
81:
82: /**
83: * @return Url
84: */
85: public function getPublicUrl()
86: {
87: return $this->publicUrl;
88: }
89:
90: /**
91: * @param $privateUrl
92: * @return $this
93: */
94: public function setPrivateUrl(Url $privateUrl)
95: {
96: $this->privateUrl = $privateUrl;
97:
98: return $this;
99: }
100:
101: /**
102: * @return Url
103: */
104: public function getPrivateUrl()
105: {
106: return $this->privateUrl;
107: }
108:
109: /**
110: * @param $region
111: * @return $this
112: */
113: public function setRegion($region)
114: {
115: $this->region = $region;
116:
117: return $this;
118: }
119:
120: /**
121: * @return string
122: */
123: public function getRegion()
124: {
125: return $this->region;
126: }
127:
128: /**
129: * Returns the endpoint URL with a version in it
130: *
131: * @param string $url Endpoint URL
132: * @param string $supportedServiceVersion Service version supported by the SDK
133: * @param OpenCloud\OpenStack $client OpenStack client
134: * @return Guzzle/Http/Url Endpoint URL with version in it
135: */
136: private function getVersionedUrl($url, $supportedServiceVersion, OpenStack $client)
137: {
138: $versionRegex = '/\/[vV][0-9][0-9\.]*/';
139: if (1 === preg_match($versionRegex, $url)) {
140: // URL has version in it; use it as-is
141: return Url::factory($url);
142: }
143:
144: // If there is no version in $url but no $supportedServiceVersion
145: // is specified, just return $url as-is but log a warning
146: if (is_null($supportedServiceVersion)) {
147: $client->getLogger()->warning('Service version supported by SDK not specified. Using versionless service URL as-is, without negotiating version.');
148: return Url::factory($url);
149: }
150:
151: // Make GET request to URL
152: $response = Formatter::decode($client->get($url)->send());
153:
154: // Attempt to parse response and determine URL for given $version
155: if (!isset($response->versions) || !is_array($response->versions)) {
156: throw new UnsupportedVersionError('Could not negotiate version with service.');
157: }
158:
159: foreach ($response->versions as $version) {
160: if (($version->status == 'CURRENT' || $version->status == 'SUPPORTED')
161: && $version->id == $supportedServiceVersion) {
162: foreach ($version->links as $link) {
163: if ($link->rel == 'self') {
164: return Url::factory($link->href);
165: }
166: }
167: }
168: }
169:
170: // If we've reached this point, we could not find a versioned
171: // URL in the response; throw an error
172: throw new UnsupportedVersionError(sprintf(
173: 'SDK supports version %s which is not currently provided by service.',
174: $supportedServiceVersion
175: ));
176: }
177: }
178: