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