Overview

Namespaces

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

Classes

  • BaseResource
  • NovaResource
  • PersistentResource
  • Overview
  • Namespace
  • Class
  • Tree
  • Download
  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\Resource;
 19: 
 20: use Guzzle\Http\Url;
 21: use OpenCloud\Common\Constants\State;
 22: use OpenCloud\Common\Exceptions\CreateError;
 23: use OpenCloud\Common\Exceptions\DeleteError;
 24: use OpenCloud\Common\Exceptions\IdRequiredError;
 25: use OpenCloud\Common\Exceptions\NameError;
 26: use OpenCloud\Common\Exceptions\UnsupportedExtensionError;
 27: use OpenCloud\Common\Exceptions\UpdateError;
 28: 
 29: abstract class PersistentResource extends BaseResource
 30: {
 31:     /**
 32:      * Create a new resource
 33:      *
 34:      * @param array $params
 35:      * @return \Guzzle\Http\Message\Response
 36:      */
 37:     public function create($params = array())
 38:     {
 39:         // set parameters
 40:         if (!empty($params)) {
 41:             $this->populate($params, false);
 42:         }
 43: 
 44:         // construct the JSON
 45:         $json = json_encode($this->createJson());
 46:         $this->checkJsonError();
 47: 
 48:         $createUrl = $this->createUrl();
 49: 
 50:         $response = $this->getClient()->post($createUrl, self::getJsonHeader(), $json)->send();
 51: 
 52:         // We have to try to parse the response body first because it should have precedence over a Location refresh.
 53:         // I'd like to reverse the order, but Nova instances return ephemeral properties on creation which are not
 54:         // available when you follow the Location link...
 55:         if (null !== ($decoded = $this->parseResponse($response))) {
 56:             $this->populate($decoded);
 57:         } elseif ($location = $response->getHeader('Location')) {
 58:             $this->refreshFromLocationUrl($location);
 59:         }
 60: 
 61:         return $response;
 62:     }
 63: 
 64:     /**
 65:      * Update a resource
 66:      *
 67:      * @param array $params
 68:      * @return \Guzzle\Http\Message\Response
 69:      */
 70:     public function update($params = array())
 71:     {
 72:         // set parameters
 73:         if (!empty($params)) {
 74:             $this->populate($params);
 75:         }
 76: 
 77:         // construct the JSON
 78:         $json = json_encode($this->updateJson($params));
 79:         $this->checkJsonError();
 80: 
 81:         // send the request
 82:         return $this->getClient()->put($this->getUrl(), self::getJsonHeader(), $json)->send();
 83:     }
 84: 
 85:     /**
 86:      * Delete this resource
 87:      *
 88:      * @return \Guzzle\Http\Message\Response
 89:      */
 90:     public function delete()
 91:     {
 92:         return $this->getClient()->delete($this->getUrl())->send();
 93:     }
 94: 
 95:     /**
 96:      * Refresh the state of a resource
 97:      *
 98:      * @param null $id
 99:      * @param null $url
100:      * @return \Guzzle\Http\Message\Response
101:      * @throws IdRequiredError
102:      */
103:     public function refresh($id = null, $url = null)
104:     {
105:         $primaryKey = $this->primaryKeyField();
106:         $primaryKeyVal = $this->getProperty($primaryKey);
107: 
108:         if (!$url) {
109:             if (!$id = $id ?: $primaryKeyVal) {
110:                 $message = sprintf("This resource cannot be refreshed because it has no %s", $primaryKey);
111:                 throw new IdRequiredError($message);
112:             }
113: 
114:             if ($primaryKeyVal != $id) {
115:                 $this->setProperty($primaryKey, $id);
116:             }
117: 
118:             $url = $this->getUrl();
119:         }
120: 
121:         // reset status, if available
122:         if ($this->getProperty('status')) {
123:             $this->setProperty('status', null);
124:         }
125: 
126:         $response = $this->getClient()->get($url)->send();
127: 
128:         if (null !== ($decoded = $this->parseResponse($response))) {
129:             $this->populate($decoded);
130:         }
131: 
132:         return $response;
133:     }
134: 
135:     /**
136:      * Given a `location` URL, refresh this resource
137:      *
138:      * @param $url
139:      */
140:     public function refreshFromLocationUrl($url)
141:     {
142:         $fullUrl = Url::factory($url);
143: 
144:         $response = $this->getClient()->get($fullUrl)->send();
145: 
146:         if (null !== ($decoded = $this->parseResponse($response))) {
147:             $this->populate($decoded);
148:         }
149:     }
150: 
151:     /**
152:      * A method to repeatedly poll the API resource, waiting for an eventual state change
153:      *
154:      * @param null $state    The expected state of the resource
155:      * @param null $timeout  The maximum timeout to wait
156:      * @param null $callback The callback to use to check the state
157:      * @param null $interval How long between each refresh request
158:      */
159:     public function waitFor($state = null, $timeout = null, $callback = null, $interval = null)
160:     {
161:         $state    = $state ?: State::ACTIVE;
162:         $timeout  = $timeout ?: State::DEFAULT_TIMEOUT;
163:         $interval = $interval ?: State::DEFAULT_INTERVAL;
164: 
165:         // save stats
166:         $startTime = time();
167: 
168:         $states = array('ERROR', $state);
169: 
170:         while (true) {
171: 
172:             $this->refresh($this->getProperty($this->primaryKeyField()));
173: 
174:             if ($callback) {
175:                 call_user_func($callback, $this);
176:             }
177: 
178:             if (in_array($this->status(), $states) || (time() - $startTime) > $timeout) {
179:                 return;
180:             }
181: 
182:             sleep($interval);
183:         }
184:     }
185: 
186:     /**
187:      * Provides JSON for create request body
188:      *
189:      * @return object
190:      * @throws \RuntimeException
191:      */
192:     protected function createJson()
193:     {
194:         if (!isset($this->createKeys)) {
195:             throw new \RuntimeException(sprintf(
196:                 'This resource object [%s] must have a visible createKeys array',
197:                 get_class($this)
198:             ));
199:         }
200: 
201:         $element = (object) array();
202: 
203:         foreach ($this->createKeys as $key) {
204:             if (null !== ($property = $this->getProperty($key))) {
205:                 $element->{$this->getAlias($key)} = $property;
206:             }
207:         }
208: 
209:         if (isset($this->metadata) && count($this->metadata)) {
210:             $element->metadata = (object) $this->metadata->toArray();
211:         }
212: 
213:         return (object) array($this->jsonName() => (object) $element);
214:     }
215: 
216:     /**
217:      * Returns the alias configured for the given key. If no alias exists
218:      * it returns the original key.
219:      *
220:      * @param  string $key
221:      * @return string
222:      */
223:     protected function getAlias($key)
224:     {
225:         if (false !== ($alias = array_search($key, $this->aliases))) {
226:             return $alias;
227:         }
228: 
229:         return $key;
230:     }
231: 
232:     /**
233:      * Provides JSON for update request body
234:      */
235:     protected function updateJson($params = array())
236:     {
237:         throw new UpdateError('updateJson() must be overriden in order for an update to happen');
238:     }
239: 
240:     /**
241:      * @throws CreateError
242:      */
243:     protected function noCreate()
244:     {
245:         throw new CreateError('This resource does not support the create operation');
246:     }
247: 
248:     /**
249:      * @throws DeleteError
250:      */
251:     protected function noDelete()
252:     {
253:         throw new DeleteError('This resource does not support the delete operation');
254:     }
255: 
256:     /**
257:      * @throws UpdateError
258:      */
259:     protected function noUpdate()
260:     {
261:         throw new UpdateError('his resource does not support the update operation');
262:     }
263: 
264:     /**
265:      * Check whether an extension is valid
266:      *
267:      * @param mixed $alias The extension name
268:      * @return bool
269:      * @throws UnsupportedExtensionError
270:      */
271:     public function checkExtension($alias)
272:     {
273:         if (!in_array($alias, $this->getService()->namespaces())) {
274:             throw new UnsupportedExtensionError(sprintf("%s extension is not installed", $alias));
275:         }
276: 
277:         return true;
278:     }
279: 
280:     /********  DEPRECATED METHODS ********/
281: 
282:     /**
283:      * @deprecated
284:      * @return string
285:      * @throws NameError
286:      */
287:     public function name()
288:     {
289:         if (null !== ($name = $this->getProperty('name'))) {
290:             return $name;
291:         } else {
292:             throw new NameError('Name attribute does not exist for this resource');
293:         }
294:     }
295: 
296:     /**
297:      * @deprecated
298:      * @return mixed
299:      */
300:     public function id()
301:     {
302:         return $this->id;
303:     }
304: 
305:     /**
306:      * @deprecated
307:      * @return string
308:      */
309:     public function status()
310:     {
311:         return (isset($this->status)) ? $this->status : 'N/A';
312:     }
313: 
314:     /**
315:      * @deprecated
316:      * @return mixed
317:      */
318:     public function region()
319:     {
320:         return $this->getService()->region();
321:     }
322: 
323:     /**
324:      * @deprecated
325:      * @return \Guzzle\Http\Url
326:      */
327:     public function createUrl()
328:     {
329:         return $this->getParent()->getUrl($this->resourceName());
330:     }
331: }
332: 
PHP OpenCloud API API documentation generated by ApiGen 2.8.0