def show(self, req, server_id, id): """Return data about the given volume attachment.""" context = req.environ['nova.context'] authorize(context) authorize_attach(context, action='show') volume_id = id instance = common.get_instance(self.compute_api, context, server_id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) if not bdms: msg = _("Instance %s is not attached.") % server_id raise exc.HTTPNotFound(explanation=msg) assigned_mountpoint = None for bdm in bdms: if bdm.volume_id == volume_id: assigned_mountpoint = bdm.device_name break if assigned_mountpoint is None: msg = _("volume_id not found: %s") % volume_id raise exc.HTTPNotFound(explanation=msg) return {'volumeAttachment': _translate_attachment_detail_view( volume_id, instance.uuid, assigned_mountpoint)}
def update(self, req, server_id, id, body): if (not self.ext_mgr or not self.ext_mgr.is_loaded('os-volume-attachment-update')): raise exc.HTTPBadRequest() context = req.environ['nova.context'] authorize(context) authorize_attach(context, action='update') if not self.is_valid_body(body, 'volumeAttachment'): msg = _("volumeAttachment not specified") raise exc.HTTPBadRequest(explanation=msg) old_volume_id = id old_volume = self.volume_api.get(context, old_volume_id) try: new_volume_id = body['volumeAttachment']['volumeId'] except KeyError: msg = _("volumeId must be specified.") raise exc.HTTPBadRequest(explanation=msg) self._validate_volume_id(new_volume_id) new_volume = self.volume_api.get(context, new_volume_id) instance = common.get_instance(self.compute_api, context, server_id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) found = False try: for bdm in bdms: if bdm.volume_id != old_volume_id: continue try: self.compute_api.swap_volume(context, instance, old_volume, new_volume) found = True break except exception.VolumeUnattached: # The volume is not attached. Treat it as NotFound # by falling through. pass except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'swap_volume', server_id) if not found: msg = _("volume_id not found: %s") % old_volume_id raise exc.HTTPNotFound(explanation=msg) else: return webob.Response(status_int=202)
def delete(self, req, server_id, id): """Detach a volume from an instance.""" context = req.environ['nova.context'] authorize(context) authorize_attach(context, action='delete') volume_id = id LOG.info(_LI("Detach volume %s"), volume_id, context=context) instance = common.get_instance(self.compute_api, context, server_id) volume = self.volume_api.get(context, volume_id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) if not bdms: msg = _("Instance %s is not attached.") % server_id raise exc.HTTPNotFound(explanation=msg) found = False try: for bdm in bdms: if bdm.volume_id != volume_id: continue if bdm.is_root: msg = _("Can't detach root device volume") raise exc.HTTPForbidden(explanation=msg) try: self.compute_api.detach_volume(context, instance, volume) found = True break except exception.VolumeUnattached: # The volume is not attached. Treat it as NotFound # by falling through. pass except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'detach_volume', server_id) if not found: msg = _("volume_id not found: %s") % volume_id raise exc.HTTPNotFound(explanation=msg) else: return webob.Response(status_int=202)
def _items(self, req, server_id, entity_maker): """Returns a list of attachments, transformed through entity_maker.""" context = req.environ['nova.context'] authorize(context) instance = common.get_instance(self.compute_api, context, server_id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) limited_list = common.limited(bdms, req) results = [] for bdm in limited_list: if bdm.volume_id: results.append(entity_maker(bdm.volume_id, bdm.instance_uuid, bdm.device_name)) return {'volumeAttachments': results}