def index(self, req): """Returns a list of snapshots, transformed through view builder.""" LOG.info(_LI("Show snapshot list")) context = req.environ['sgservice.context'] params = req.params.copy() marker, limit, offset = common.get_pagination_params(params) sort_keys, sort_dirs = common.get_sort_params(params) filters = params utils.remove_invaild_filter_options( context, filters, self._get_snapshot_filter_options()) utils.check_filters(filters) if 'name' in sort_keys: sort_keys[sort_keys.index('name')] = 'display_name' if 'name' in filters: filters['display_name'] = filters.pop('name') snapshots = self.service_api.get_all_snapshots(context, marker=marker, limit=limit, sort_keys=sort_keys, sort_dirs=sort_dirs, filters=filters, offset=offset) retval_snapshots = self._view_builder.detail_list(req, snapshots) LOG.info(_LI("Show snapshot list request issued successfully.")) return retval_snapshots
def __exit__(self, ex_type, ex_value, ex_traceback): if not ex_value: return True if isinstance(ex_value, exception.NotAuthorized): raise Fault(webob.exc.HTTPForbidden(explanation=ex_value.msg)) elif isinstance(ex_value, exception.Invalid): raise Fault( exception.ConvertedException(code=ex_value.code, explanation=ex_value.msg)) elif isinstance(ex_value, TypeError): exc_info = (ex_type, ex_value, ex_traceback) LOG.error(_LE('Exception handling resource: %s'), ex_value, exc_info=exc_info) raise Fault(webob.exc.HTTPBadRequest()) elif isinstance(ex_value, Fault): LOG.info(_LI("Fault thrown: %s"), ex_value) raise ex_value elif isinstance(ex_value, webob.exc.HTTPException): LOG.info(_LI("HTTP exception thrown: %s"), ex_value) raise Fault(ex_value) # We didn't handle the exception return False
def reset_status(self, req, id, body): """reset checkpoint status""" LOG.info(_LI("Reset checkpoint status, id: %s"), id) status = body['reset_status'].get('status', fields.CheckpointStatus.AVAILABLE) if status not in fields.CheckpointStatus.ALL: msg = _("Invalid status provided.") LOG.error(msg) raise exception.InvalidStatus(status=status) context = req.environ['sgservice.context'] checkpoint = self.service_api.get_checkpoint(context, id) checkpoint.status = status checkpoint.save() # reset master snapshot status try: master_snapshot = self.service_api.get_snapshot( context, checkpoint.master_snapshot) master_snapshot.status = status master_snapshot.save() except Exception: pass # reset slave snapshot status try: slave_snapshot = self.service_api.get_snapshot( context, checkpoint.slave_snapshot) slave_snapshot.status = status slave_snapshot.save() except Exception: pass return webob.Response(status_int=202)
def rollback(self, req, id, body): """Rollback a checkpoint""" LOG.info(_LI("Rollback checkpoint with id: %s"), id) context = req.environ['sgservice.context'] checkpoint = self.service_api.get_checkpoint(context, id) rollback = self.service_api.rollback_checkpoint(context, checkpoint) return self._view_builder.rollback_summary(req, rollback)
def delete(self, req, id): """Delete a checkpoint.""" LOG.info(_LI("Delete checkpoint with id: %s"), id) context = req.environ['sgservice.context'] checkpoint = self.service_api.get_checkpoint(context, id) self.service_api.delete_checkpoint(context, checkpoint) return webob.Response(status_int=202)
def update(self, req, id, body): """Update a snapshot.""" LOG.info(_LI("Update snapshot with id: %s"), id) context = req.environ['sgservice.context'] if not body: msg = _("Missing request body") raise webob.exc.HTTPBadRequest(explanation=msg) if 'snapshot' not in body: msg = (_("Missing required element '%s' in request body"), 'snapshot') raise webob.exc.HTTPBadRequest(explanation=msg) snapshot = body['snapshot'] update_dict = {} valid_update_keys = ( 'name', 'description', 'display_name', 'display_description', ) for key in valid_update_keys: if key in snapshot: update_dict[key] = snapshot[key] self.validate_name_and_description(update_dict) if 'name' in update_dict: update_dict['display_name'] = update_dict.pop('name') if 'description' in update_dict: update_dict['display_description'] = update_dict.pop('description') snapshot = self.service_api.get_snapshot(context, id) snapshot.update(update_dict) snapshot.save() return self._view_builder.detail(req, snapshot)
def rollback(self, req, id, body): """Rollback a snapshot to volume""" LOG.info(_LI("Rollback snapshot with id: %s"), id) context = req.environ['sgservice.context'] snapshot = self.service_api.get_snapshot(context, id) rollback = self.service_api.rollback_snapshot(context, snapshot) return self._view_builder.rollback_summary(req, rollback)
def enable(self, req, id, body): """Enable a disabled-replication""" LOG.info(_LI("Enable replication with id: %s"), id) context = req.environ['sgservice.context'] replication = self.service_api.get_replication(context, id) replication = self.service_api.enable_replication(context, replication) return self._view_builder.detail(req, replication)
def delete(self, req, id): """Delete a replication.""" LOG.info(_LI("Delete replication with id: %s"), id) context = req.environ['sgservice.context'] replication = self.service_api.get_replication(context, id) self.service_api.delete_replication(context, replication) return webob.Response(status_int=202)
def _error(self, inner, req): LOG.exception(_LE("Caught error: %(type)s %(error)s"), { 'type': type(inner), 'error': inner }) safe = getattr(inner, 'safe', False) headers = getattr(inner, 'headers', None) status = getattr(inner, 'code', 500) if status is None: status = 500 msg_dict = dict(url=req.url, status=status) LOG.info(_LI("%(url)s returned with HTTP %(status)d"), msg_dict) outer = self.status_to_type(status) if headers: outer.headers = headers # NOTE(johannes): We leave the explanation empty here on # purpose. It could possibly have sensitive information # that should not be returned back to the user. See # bugs 868360 and 874472 # NOTE(eglynn): However, it would be over-conservative and # inconsistent with the EC2 API to hide every exception, # including those that are safe to expose, see bug 1021373 if safe: msg = (inner.msg if isinstance(inner, exception.SGServiceException) else six.text_type(inner)) params = { 'exception': inner.__class__.__name__, 'explanation': msg } outer.explanation = _('%(exception)s: %(explanation)s') % params return wsgi.Fault(outer)
def update(self, req, id, body): """Update a backup.""" LOG.info(_LI("Update backup, backup_id: %s"), id) context = req.environ['sgservice.context'] if not body: msg = _("Missing request body") raise webob.exc.HTTPBadRequest(explanation=msg) if 'backup' not in body: msg = (_("Missing required element '%s' in request body"), 'backup') raise webob.exc.HTTPBadRequest(explanation=msg) backup = body['backup'] update_dict = {} valid_update_keys = ( 'name', 'description', 'display_name', 'display_description', ) for key in valid_update_keys: if key in backup: update_dict[key] = backup[key] self.validate_name_and_description(update_dict) if 'name' in update_dict: update_dict['display_name'] = update_dict.pop('name') if 'description' in update_dict: update_dict['display_description'] = update_dict.pop('description') backup = self.service_api.get_backup(context, id) backup.update(update_dict) backup.save() return self._view_builder.detail(req, backup)
def delete(self, req, id): """Delete a backup.""" LOG.info(_LI("Delete backup, backup_id: %s"), id) context = req.environ['sgservice.context'] backup = self.service_api.get_backup(context, id) self.service_api.delete_backup(context, backup) return webob.Response(status_int=202)
def delete(self, req, id): """Delete a snapshot.""" LOG.info(_LI("Delete snapshot with id: %s"), id) context = req.environ['sgservice.context'] snapshot = self.service_api.get_snapshot(context, id) self.service_api.delete_snapshot(context, snapshot) return webob.Response(status_int=202)
def disable(self, req, id, body): """Disable a enabled-volume.""" LOG.info(_LI("Disable volume SG, volume_id: %s"), id) context = req.environ['sgservice.context'] volume = self.service_api.get(context, id) volume = self.service_api.disable_sg(context, volume) return self._view_builder.detail(req, volume)
def delete(self, req, id): """Delete a sg volume.""" LOG.info(_LI("Delete sg volume, volume_id: %s"), id) context = req.environ['sgservice.context'] volume = self.service_api.get(context, id) self.service_api.delete(context, volume) return webob.Response(status_int=202)
def reset_status(self, req, id, body): """reset replication status""" LOG.info(_LI("Reset replication status, id: %s"), id) status = body['reset_status'].get('status', fields.ReplicationStatus.ENABLED) if status not in fields.ReplicationStatus.ALL: msg = _("Invalid status provided.") LOG.error(msg) raise exception.InvalidStatus(status=status) context = req.environ['sgservice.context'] replication = self.service_api.get_replication(context, id) replication.status = status replication.save() # reset master volume replicate status master_volume = self.service_api.get(context, replication.master_volume) if master_volume.replicate_status not in [ None, fields.ReplicateStatus.DELETED ]: master_volume.replicate_status = status master_volume.save() # reset slave volume replicate status slave_volume = self.service_api.get(context, replication.slave_volume) if slave_volume.replicate_status not in [ None, fields.ReplicateStatus.DELETED ]: slave_volume.replicate_status = status slave_volume.save() return webob.Response(status_int=202)
def export_record(self, req, id, body): """Export backup record""" LOG.info(_LI("Export backup record, backup_id: %s"), id) context = req.environ['sgservice.context'] backup = self.service_api.get_backup(context, id) record = self.service_api.export_record(context, backup) return self._view_builder.export_summary(req, record)
def detach(self, req, id, body): """Clear attachment metadata.""" LOG.info(_LI("Clear SG-volume attachment with volume_id: %s"), id) context = req.environ['sgservice.context'] volume = self.service_api.get(context, id) params = body['detach'] params = {} if params is None else params instance_uuid = params.get('instance_uuid', None) self.service_api.detach(context, volume, instance_uuid) return webob.Response(status_int=202)
def failover(self, req, id, body): """Failover a enabled replication""" LOG.info(_LI("Failover replication with id: %s"), id) context = req.environ['sgservice.context'] params = body['failover'] force = params.get('force', False) replication = self.service_api.get_replication(context, id) replication = self.service_api.failover_replication( context, replication, force) return self._view_builder.detail(req, replication)
def restore(self, req, id, body): """Restore backup to an SG-enabled volume""" LOG.info(_LI("Restore backup to sg-enabled volume, backup_id: %s"), id) context = req.environ['sgservice.context'] backup = self.service_api.get_backup(context, id) restore = body['restore'] volume_id = restore.get('volume_id', None) if volume_id is None: msg = _('restored volume should be specified.') raise webob.exc.HTTPBadRequest(explanation=msg) restore = self.service_api.restore_backup(context, backup, volume_id) return self._view_builder.restore_summary(req, restore)
def wait(self): """Block, until the server has stopped. Waits on the server's eventlet to finish, then returns. :returns: None """ try: if self._server is not None: self._pool.waitall() self._server.wait() except greenlet.GreenletExit: LOG.info(_LI("WSGI server has stopped."))
def stop(self): """Stop this server. This is not a very nice action, as currently the method by which a server is stopped is by killing its eventlet. :returns: None """ LOG.info(_LI("Stopping WSGI server.")) if self._server is not None: # Resize pool to stop new requests from being processed self._pool.resize(0) self._server.kill()
def reset_status(self, req, id, body): """reset snapshot status""" LOG.info(_LI("Reset snapshot status, id: %s"), id) status = body['reset_status'].get('status', fields.SnapshotStatus.AVAILABLE) if status not in fields.SnapshotStatus.ALL: msg = _("Invalid status provided.") LOG.error(msg) raise exception.InvalidStatus(status=status) context = req.environ['sgservice.context'] snapshot = self.service_api.get_snapshot(context, id) snapshot.status = status snapshot.save() return webob.Response(status_int=202)
def reset_status(self, req, id, body): """reset volume status""" LOG.info(_LI("Reset volume status, id: %s"), id) status = body['reset_status'].get('status', fields.VolumeStatus.ENABLED) if status not in fields.VolumeStatus.ALL: msg = _("Invalid status provided.") LOG.error(msg) raise exception.InvalidStatus(status=status) context = req.environ['sgservice.context'] volume = self.service_api.get(context, id) volume.status = status volume.save() return webob.Response(status_int=202)
def start(self): version_string = version.version_string() LOG.info(_LI('Starting %(topic)s node (version %(version_string)s)'), {'topic': self.topic, 'version_string': version_string}) self.model_disconnected = False ctxt = context.get_admin_context() try: service_ref = db.service_get_by_args(ctxt, self.host, self.binary) self.service_id = service_ref['id'] except exception.NotFound: self._create_service_ref(ctxt) self.manager.init_host(service_id=self.service_id) LOG.debug("Creating RPC server for service %s", self.topic) target = messaging.Target(topic=self.topic, server=self.host) endpoints = [self.manager] endpoints.extend(self.manager.additional_endpoints) serializer = objects_base.SGServiceObjectSerializer() self.rpcserver = rpc.get_server(target, endpoints, serializer) self.rpcserver.start() self.manager.init_host_with_rpc() if self.report_interval: pulse = loopingcall.FixedIntervalLoopingCall( self.report_state) pulse.start(interval=self.report_interval, initial_delay=self.report_interval) self.timers.append(pulse) if self.periodic_interval: if self.periodic_fuzzy_delay: initial_delay = random.randint(0, self.periodic_fuzzy_delay) else: initial_delay = None periodic = loopingcall.FixedIntervalLoopingCall( self.periodic_tasks) periodic.start(interval=self.periodic_interval, initial_delay=initial_delay) self.timers.append(periodic)
def __call__(self, request): """WSGI method that controls (de)serialization and method dispatch.""" LOG.info(_LI("%(method)s %(url)s"), { "method": request.method, "url": request.url }) # Identify the action, its arguments, and the requested # content type action_args = self.get_action_args(request.environ) action = action_args.pop('action', None) content_type, body = self.get_body(request) accept = request.best_match_content_type() # NOTE(Vek): Splitting the function up this way allows for # auditing by external tools that wrap the existing # function. If we try to audit __call__(), we can # run into troubles due to the @webob.dec.wsgify() # decorator. return self._process_stack(request, action, action_args, content_type, body, accept)
def import_record(self, req, body): """Import a backup""" LOG.info(_LI("Importing record from body: %s"), body) self.assert_valid_body(body, 'backup_record') context = req.environ['sgservice.context'] backup_record = body['backup_record'] # Verify that body elements are provided try: driver_data = backup_record['driver_data'] except KeyError: msg = _("Incorrect request body format.") raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug('Importing backup using driver_data %s.', driver_data) try: new_backup = self.service_api.import_record(context, backup_record) except exception.InvalidBackup as error: raise webob.exc.HTTPBadRequest(explanation=error.msg) # Other Not found exceptions will be handled at the wsgi level except exception.ServiceNotFound as error: raise webob.exc.HTTPInternalServerError(explanation=error.msg) retval = self._view_builder.detail(req, new_backup) return retval
def attach(self, req, id, body): """Add sg-volume attachment metadata.""" LOG.info(_LI("Add SG-volume attachment, volume_id: %s"), id) context = req.environ['sgservice.context'] volume = self.service_api.get(context, id) params = body['attach'] params = {} if params is None else params instance_uuid = params.get('instance_uuid', None) mode = params.get('mode', None) if mode is None: mode = 'rw' if instance_uuid is None: msg = _("Invalid request to attach volume to an invalid target") raise webob.exc.HTTPBadRequest(explanation=msg) if mode not in ('rw', 'ro'): msg = _("Invalid request to attach volume to an invalid mode. " "Attaching mode should be 'rw' or 'ro'.") raise webob.exc.HTTPBadRequest(explanation=msg) attach_result = self.service_api.attach(context, volume, instance_uuid, mode) return self._view_builder.attach_summary(req, attach_result)
def index(self, req): """Returns a list of snapshots, transformed through view builder.""" LOG.info(_LI("Show snapshot list")) return {"snapshots": {}}
def delete(self, req, id): """Delete a snapshot.""" LOG.info(_LI("Delete snapshot with id: %s"), id) pass return webob.Response(status_int=202)