Overview

Namespaces

  • None
  • OpenCloud
    • Autoscale
      • Resource
    • CloudMonitoring
      • Exception
      • Resource
    • Common
      • Exceptions
      • Log
      • Request
        • Response
    • Compute
    • Database
    • DNS
    • LoadBalancer
      • Resources
    • ObjectStore
      • Resource
    • Orchestration
    • Volume
  • PHP

Classes

  • Flavor
  • Image
  • Network
  • Server
  • ServerMetadata
  • Service
  • VolumeAttachment
  • Overview
  • Namespace
  • Class
  • Tree
  • Download
  1: <?php
  2: /**
  3:  * PHP OpenCloud library.
  4:  * 
  5:  * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
  6:  * @license   https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
  7:  * @version   1.6.0
  8:  * @author    Glen Campbell <glen.campbell@rackspace.com>
  9:  * @author    Jamie Hannaford <jamie.hannaford@rackspace.com>
 10:  */
 11: 
 12: namespace OpenCloud\Compute;
 13: 
 14: use OpenCloud\Common\PersistentObject;
 15: use OpenCloud\Volume\Volume;
 16: use OpenCloud\Common\Exceptions;
 17: use OpenCloud\Common\Lang;
 18: 
 19: /**
 20:  * The Server class represents a single server node.
 21:  *
 22:  * A Server is always associated with a (Compute) Service. This implementation
 23:  * supports extension attributes OS-DCF:diskConfig, RAX-SERVER:bandwidth,
 24:  * rax-bandwidth:bandwith
 25:  */
 26: class Server extends PersistentObject
 27: {
 28:     // Ideally these should have data types defined in docblocks
 29: 
 30:     public $status;             // Server status
 31:     public $updated;            // date and time of last update
 32:     public $hostId;             // the ID of the host holding the server instance
 33:     public $addresses;          // an object holding the server's network addresses
 34:     public $links;              // an object with server's permanent and bookmark links
 35:     public $image;              // the object object of the server
 36:     public $flavor;             // the flavor object of the server
 37:     public $networks = array(); // array of attached networks
 38:     public $id;                 // the server's ID
 39:     public $user_id;            // the user ID that created the server
 40:     public $name;               // the server's name
 41:     public $created;            // date and time the server was created
 42:     public $tenant_id;          // tenant/customer ID that created the server
 43:     public $accessIPv4;         // the IPv4 access address
 44:     public $accessIPv6;         // the IPv6 access address
 45:     public $progress;           // build progress, from 0 (%) to 100 (%)
 46:     public $adminPass;          // the root password returned from the Create() method
 47:     public $metadata;           // a Metadata object associated with the server
 48: 
 49:     protected static $json_name = 'server';
 50:     protected static $url_resource = 'servers';
 51: 
 52:     private $personality = array(); // uploaded file attachments
 53:     private $imageRef;              // image reference (for create)
 54:     private $flavorRef;             // flavor reference (for create)
 55: 
 56:     /**
 57:      * Creates a new Server object and associates it with a Compute service
 58:      *
 59:      * @param mixed $info
 60:      * * If NULL, an empty Server object is created
 61:      * * If an object, then a Server object is created from the data in the
 62:      *      object
 63:      * * If a string, then it's treated as a Server ID and retrieved from the
 64:      *      service
 65:      * The normal use case for SDK clients is to treat it as either NULL or an
 66:      *      ID. The object value parameter is a special case used to construct
 67:      *      a Server object from a ServerList element to avoid a secondary
 68:      *      call to the Service.
 69:      * @throws ServerNotFound if a 404 is returned
 70:      * @throws UnknownError if another error status is reported
 71:      */
 72:     public function __construct(Service $service, $info = null)
 73:     {
 74:         // make the service persistent
 75:         parent::__construct($service, $info);
 76: 
 77:         // the metadata item is an object, not an array
 78:         $this->metadata = $this->Metadata();
 79:     }
 80: 
 81:     /**
 82:      * Returns the primary external IP address of the server
 83:      *
 84:      * This function is based upon the accessIPv4 and accessIPv6 values.
 85:      * By default, these are set to the public IP address of the server.
 86:      * However, these values can be modified by the user; this might happen,
 87:      * for example, if the server is behind a firewall and needs to be
 88:      * routed through a NAT device to be reached.
 89:      *
 90:      * @api
 91:      * @param integer $ip_type the type of IP version (4 or 6) to return
 92:      * @return string IP address
 93:      */
 94:     public function ip($ip_type = RAXSDK_DEFAULT_IP_VERSION)
 95:     {
 96:         switch($ip_type) {
 97:             case 4:
 98:                 return $this->accessIPv4;
 99:             case 6:
100:                 return $this->accessIPv6;
101:             default:
102:                 throw new Exceptions\InvalidIpTypeError(Lang::translate('Invalid IP address type; must be 4 or 6'));
103:         }
104:     }
105: 
106:     /**
107:      * {@inheritDoc}
108:      */
109:     public function create($params = array())
110:     {
111:         $this->id     = null;
112:         $this->status = null;
113:         
114:         return parent::create($params);
115:     }
116:     
117:     /**
118:      * {@inheritDoc}
119:      */
120:     public function createUrl()
121:     {
122:         return $this->getService()->url();
123:     }
124: 
125:     /**
126:      * Rebuilds an existing server
127:      *
128:      * @api
129:      * @param array $params - an associative array of key/value pairs of
130:      *      attributes to set on the new server
131:      */
132:     public function rebuild($params = array())
133:     {
134:         if (!isset($params['adminPass'])) {
135:             throw new Exceptions\RebuildError(
136:                 Lang::Translate('adminPass required when rebuilding server')
137:             );
138:         }
139:         
140:         if (!isset($params['image'])) {
141:             throw new Exceptions\RebuildError(
142:                 Lang::Translate('image required when rebuilding server')
143:             );
144:         }
145:         
146:         $obj = new \stdClass();
147:         $obj->rebuild = new \stdClass();
148:         $obj->rebuild->imageRef = $params['image']->Id();
149:         $obj->rebuild->adminPass = $params['adminPass'];
150:         return $this->Action($obj);
151:     }
152: 
153:     /**
154:      * Reboots a server
155:      *
156:      * You can pass the parameter RAXSDK_SOFT_REBOOT (default) or
157:      * RAXSDK_HARD_REBOOT to specify the type of reboot. A "soft" reboot
158:      * requests that the operating system reboot itself; a "hard" reboot
159:      * is the equivalent of pulling the power plug and then turning it back
160:      * on, with a possibility of data loss.
161:      *
162:      * @api
163:      * @param string $type - either 'soft' (the default) or 'hard' to
164:      *      indicate the type of reboot
165:      * @return boolean TRUE on success; FALSE on failure
166:      */
167:     public function reboot($type = RAXSDK_SOFT_REBOOT)
168:     {
169:         // create object and json
170:         $obj = new \stdClass();
171:         $obj->reboot = new \stdClass();
172:         $obj->reboot->type = strtoupper($type);
173:         return $this->Action($obj);
174:     }
175: 
176:     /**
177:      * Creates a new image from a server
178:      *
179:      * @api
180:      * @param string $name The name of the new image
181:      * @param array $metadata Optional metadata to be stored on the image
182:      * @return boolean TRUE on success; FALSE on failure
183:      */
184:     public function createImage($name, $metadata = array())
185:     {
186:         if (empty($name)) {
187:             throw new Exceptions\ImageError(
188:                 Lang::translate('Image name is required to create an image')
189:             );
190:         }
191: 
192:         // construct a createImage object for jsonization
193:         $obj = new \stdClass;
194:         $obj->createImage = new \stdClass;
195:         $obj->createImage->name = $name;
196:         $obj->createImage->metadata = new \stdClass;
197: 
198:         foreach ($metadata as $name => $value) {
199:             $obj->createImage->metadata->$name = $value;
200:         }
201: 
202:         $response = $this->action($obj);
203:         
204:         if (!$response || !($location = $response->header('Location'))) {
205:             return false;
206:         }
207: 
208:         return new Image($this->getService(), basename($location));
209:     }
210: 
211:     /**
212:      * Schedule daily image backups
213:      *
214:      * @api
215:      * @param mixed $retention - false (default) indicates you want to
216:      *      retrieve the image schedule. $retention <= 0 indicates you
217:      *      want to delete the current schedule. $retention > 0 indicates
218:      *      you want to schedule image backups and you would like to
219:      *      retain $retention backups.
220:      * @return mixed an object or FALSE on error
221:      * @throws ServerImageScheduleError if an error is encountered
222:      */
223:     public function imageSchedule($retention = false)
224:     {
225:         $url = Lang::noslash($this->url('rax-si-image-schedule'));
226: 
227:         $response = null;
228: 
229:         if ($retention === false) { 
230:             // Get current retention
231:             $response = $this->getService()->request($url);
232:         } elseif ($retention <= 0) { 
233:             // Delete image schedule
234:             $response = $this->getService()->request($url, 'DELETE');
235:         } else { 
236:             // Set image schedule
237:             $object = new \stdClass();
238:             $object->image_schedule = new \stdClass();
239:             $object->image_schedule->retention = $retention;
240:             
241:             $response = $this->getService()->request($url, 'POST', array(), json_encode($object));
242:         }
243:         
244:         // @codeCoverageIgnoreStart
245:         if ($response->HttpStatus() >= 300) {
246:             throw new Exceptions\ServerImageScheduleError(sprintf(
247:                 Lang::translate('Error in Server::ImageSchedule(), status [%d], response [%s]'),
248:                 $response->HttpStatus(),
249:                 $response->HttpBody()
250:             ));
251:         }
252:         // @codeCoverageIgnoreEnd
253: 
254:         $object = json_decode($response->HttpBody());
255:         
256:         if ($object && property_exists($object, 'image_schedule'))
257:             return $object->image_schedule;
258:         else {
259:             return new \stdClass;
260:         }
261:     }
262: 
263:     /**
264:      * Initiates the resize of a server
265:      *
266:      * @api
267:      * @param Flavor $flavorRef a Flavor object indicating the new server size
268:      * @return boolean TRUE on success; FALSE on failure
269:      */
270:     public function resize(Flavor $flavorRef)
271:     {
272:         // construct a resize object for jsonization
273:         $obj = new \stdClass();
274:         $obj->resize = new \stdClass();
275:         $obj->resize->flavorRef = $flavorRef->id;
276:         return $this->Action($obj);
277:     }
278: 
279:     /**
280:      * confirms the resize of a server
281:      *
282:      * @api
283:      * @return boolean TRUE on success; FALSE on failure
284:      */
285:     public function resizeConfirm()
286:     {
287:         $obj = new \stdClass();
288:         $obj->confirmResize = null;
289:         $res = $this->Action($obj);
290:         $this->Refresh($this->id);
291:         return $res;
292:     }
293: 
294:     /**
295:      * reverts the resize of a server
296:      *
297:      * @api
298:      * @return boolean TRUE on success; FALSE on failure
299:      */
300:     public function resizeRevert()
301:     {
302:         $obj = new \stdClass();
303:         $obj->revertResize = null;
304:         return $this->Action($obj);
305:     }
306: 
307:     /**
308:      * Sets the root password on the server
309:      *
310:      * @api
311:      * @param string $newpasswd The new root password for the server
312:      * @return boolean TRUE on success; FALSE on failure
313:      */
314:     public function setPassword($newpasswd)
315:     {
316:         // construct an object to hold the password
317:         $obj = new \stdClass();
318:         $obj->changePassword = new \stdClass();
319:         $obj->changePassword->adminPass = $newpasswd;
320:         return $this->Action($obj);
321:     }
322: 
323:     /**
324:      * Puts the server into *rescue* mode
325:      *
326:      * @api
327:      * @link http://docs.rackspace.com/servers/api/v2/cs-devguide/content/rescue_mode.html
328:      * @return string the root password of the rescue server
329:      * @throws ServerActionError if the server has no ID (i.e., has not
330:      *      been created yet)
331:      */
332:     public function rescue()
333:     {
334:         $this->checkExtension('os-rescue');
335: 
336:         if (empty($this->id)) {
337:             throw new Exceptions\ServerActionError(
338:                 Lang::translate('Server has no ID; cannot Rescue()')
339:             );
340:         }
341: 
342:         $obj = new \stdClass;
343:         $obj->rescue = "none";
344: 
345:         $resp = $this->action($obj);
346:         $newobj = json_decode($resp->httpBody());
347: 
348:         $this->checkJsonError();
349:         
350:         // @codeCoverageIgnoreStart
351:         if (!isset($newobj->adminPass)) {
352:             throw new Exceptions\ServerActionError(sprintf(
353:                 Lang::translate('Rescue() method failed unexpectedly, status [%s] response [%s]'),
354:                 $resp->httpStatus(),
355:                 $resp->httpBody()
356:             ));
357:         // @codeCoverageIgnoreEnd
358:             
359:         } else {
360:             return $newobj->adminPass;
361:         }
362:     }
363: 
364:     /**
365:      * Takes the server out of *rescue* mode
366:      *
367:      * @api
368:      * @link http://docs.rackspace.com/servers/api/v2/cs-devguide/content/rescue_mode.html
369:      * @return HttpResponse
370:      * @throws ServerActionError if the server has no ID (i.e., has not
371:      *      been created yet)
372:      */
373:     public function unrescue()
374:     {
375:         $this->CheckExtension('os-rescue');
376: 
377:         if (!isset($this->id)) {
378:             throw new Exceptions\ServerActionError(Lang::translate('Server has no ID; cannot Unescue()'));
379:         }
380: 
381:         $obj = new \stdClass();
382:         $obj->unrescue = NULL;
383: 
384:         return $this->Action($obj);
385:     }
386: 
387:     /**
388:      * Retrieves the metadata associated with a Server
389:      *
390:      * If a metadata item name is supplied, then only the single item is
391:      * returned. Otherwise, the default is to return all metadata associated
392:      * with a server.
393:      *
394:      * @api
395:      * @param string $key - the (optional) name of the metadata item to return
396:      * @return OpenCloud\Compute\Metadata object
397:      * @throws MetadataError
398:      */
399:     public function metadata($key = null)
400:     {
401:         return new ServerMetadata($this, $key);
402:     }
403: 
404:     /**
405:      * Returns the IP address block for the Server or for a specific network
406:      *
407:      * @api
408:      * @param string $network - if supplied, then only the IP(s) for
409:      *      the specified network are returned. Otherwise, all IPs are returned.
410:      * @return object
411:      * @throws ServerIpsError
412:      */
413:     public function ips($network = null)
414:     {
415:         $url = Lang::noslash($this->Url('ips/'.$network));
416: 
417:         $response = $this->Service()->Request($url);
418:         
419:         // @codeCoverageIgnoreStart
420:         if ($response->HttpStatus() >= 300) {
421:             throw new Exceptions\ServerIpsError(sprintf(
422:                 Lang::translate('Error in Server::ips(), status [%d], response [%s]'),
423:                 $response->HttpStatus(),
424:                 $response->HttpBody()
425:             ));
426:         }
427:         
428:         $object = json_decode($response->httpBody());
429:         
430:         $this->checkJsonError();
431:  
432:         if (isset($object->addresses)) {
433:             return $object->addresses;
434:         } elseif (isset($object->network)) {
435:             return $object->network;
436:         } else {
437:             return new \stdClass;
438:         }
439:         // @codeCoverageIgnoreEnd
440:     }
441: 
442:     /**
443:      * Attaches a volume to a server
444:      *
445:      * Requires the os-volumes extension. This is a synonym for
446:      * `VolumeAttachment::Create()`
447:      *
448:      * @api
449:      * @param OpenCloud\VolumeService\Volume $vol the volume to attach. If
450:      *      `"auto"` is specified (the default), then the first available
451:      *      device is used to mount the volume (for example, if the primary
452:      *      disk is on `/dev/xvhda`, then the new volume would be attached
453:      *      to `/dev/xvhdb`).
454:      * @param string $device the device to which to attach it
455:      */
456:     public function attachVolume(Volume $volume, $device = 'auto')
457:     {
458:         $this->CheckExtension('os-volumes');
459: 
460:         return $this->VolumeAttachment()->Create(array(
461:             'volumeId'  => $volume->id,
462:             'device'    => ($device=='auto' ? NULL : $device)
463:         ));
464:     }
465: 
466:     /**
467:      * removes a volume attachment from a server
468:      *
469:      * Requires the os-volumes extension. This is a synonym for
470:      * `VolumeAttachment::Delete()`
471:      *
472:      * @api
473:      * @param OpenCloud\VolumeService\Volume $vol the volume to remove
474:      * @throws VolumeError
475:      */
476:     public function detachVolume(Volume $volume)
477:     {
478:         $this->CheckExtension('os-volumes');
479:         return $this->VolumeAttachment($volume->id)->Delete();
480:     }
481: 
482:     /**
483:      * returns a VolumeAttachment object
484:      *
485:      */
486:     public function volumeAttachment($id = null)
487:     {
488:         $resource = new VolumeAttachment($this->getService());
489:         $resource->setParent($this);
490:         $resource->populate($id);
491:         return $resource;
492:     }
493: 
494:     /**
495:      * returns a Collection of VolumeAttachment objects
496:      *
497:      * @api
498:      * @return Collection
499:      */
500:     public function volumeAttachmentList()
501:     {
502:         return $this->getService()->collection(
503:             '\OpenCloud\Compute\VolumeAttachment',
504:             NULL,
505:             $this
506:         );
507:     }
508: 
509:     /**
510:      * adds a "personality" file to be uploaded during Create() or Rebuild()
511:      *
512:      * The `$path` argument specifies where the file will be stored on the
513:      * target server; the `$data` is the actual data values to be stored.
514:      * To upload a local file, use `file_get_contents('name')` for the `$data`
515:      * value.
516:      *
517:      * @api
518:      * @param string $path the file path (up to 255 characters)
519:      * @param string $data the file contents (max size set by provider)
520:      * @return void
521:      * @throws PersonalityError if server already exists (has an ID)
522:      */
523:     public function addFile($path, $data)
524:     {
525:         // set the value
526:         $this->personality[$path] = base64_encode($data);
527:     }
528: 
529:     /**
530:      * Returns a console connection
531:      * Note: Where is this documented?
532:      * 
533:      * @codeCoverageIgnore
534:      */
535:     public function console($type = 'novnc') 
536:     {
537:         $info = new \stdClass;
538:         $info->type = $type;
539:         $msg = new \stdClass;
540:         $action = (strpos('spice', $type) !== false) ? 'os-getSPICEConsole' : 'os-getVNCConsole';
541:         $msg->$action = $info;
542:         return json_decode($this->action($msg)->httpBody())->console;
543:     }
544: 
545: 
546:     /**
547:      * Creates the JSON for creating a new server
548:      *
549:      * @param string $element creates {server ...} by default, but can also
550:      *      create {rebuild ...} by changing this parameter
551:      * @return json
552:      */
553:     protected function createJson()
554:     {
555:         // Convert some values
556:         $this->metadata->sdk = RAXSDK_USER_AGENT;
557:         
558:         if (!empty($this->image) && $this->image instanceof Image) {
559:             $this->imageRef = $this->image->id;
560:         }
561:         if (!empty($this->flavor) && $this->flavor instanceof Flavor) {
562:             $this->flavorRef = $this->flavor->id;
563:         }
564:         
565:         // Base object
566:         $server = (object) array(
567:             'name'        => $this->name,
568:             'imageRef'    => $this->imageRef,
569:             'flavorRef'   => $this->flavorRef,
570:             'metadata'    => $this->metadata,
571:             'networks'    => array(),
572:             'personality' => array()
573:         );
574:         
575:         // Networks
576:         if (is_array($this->networks) && count($this->networks)) {
577:             foreach ($this->networks as $network) {
578:                 if (!$network instanceof Network) {
579:                     throw new Exceptions\InvalidParameterError(sprintf(
580:                         'When creating a server, the "networks" key must be an ' .
581:                         'array of OpenCloud\Compute\Network objects with valid ' .
582:                         'IDs; variable passed in was a [%s]',
583:                         gettype($network)
584:                     ));
585:                 }
586:                 if (empty($network->id)) {
587:                     $this->getLogger()->warning('When creating a server, the ' 
588:                         . 'network objects passed in must have an ID'
589:                     );
590:                     continue;
591:                 }
592:                 // Stock networks array
593:                 $server->networks[] = (object) array('uuid' => $network->id);
594:             }
595:         }
596: 
597:         // Personality files
598:         if (!empty($this->personality)) {
599:             foreach ($this->personality as $path => $data) {
600:                 // Stock personality array
601:                 $server->personality[] = (object) array(
602:                     'path'     => $path,
603:                     'contents' => $data
604:                 );
605:             }
606:         }
607:         
608:         return (object) array('server' => $server);
609:     }
610: 
611:     /**
612:      * Creates the JSON for updating a server
613:      *
614:      * @return json
615:      */
616:     protected function updateJson($params = array())
617:     {
618:         $object = new \stdClass();
619:         $object->server = new \stdClass();
620:         foreach($params as $name => $value) {
621:             $object->server->$name = $this->$name;
622:         }
623:         return $object;
624:     }
625: 
626: }
627: 
PHP OpenCloud API API documentation generated by ApiGen 2.8.0