Ejemplo n.º 1
0
    def protect(self, context, plan):
        """create protection for the given plan

        :param plan: Define that protection plan should be done
        """

        LOG.info(_LI("Starting protection service:protect action"))
        LOG.debug('protecting  :%s tpye:%s', plan, type(plan))

        if not plan:
            raise exception.InvalidPlan(reason='the protection plan is None')
        provider_id = plan.get('provider_id', None)
        plan_id = plan.get('id', None)
        provider = self.provider_registry.show_provider(provider_id)
        if not provider:
            raise exception.ProviderNotFound(provider_id=provider_id)
        try:
            protection_flow = self.worker.get_flow(context,
                                                   constants.OPERATION_PROTECT,
                                                   plan=plan,
                                                   provider=provider)
        except Exception:
            LOG.exception(_LE("Failed to create protection flow,plan:%s"),
                          plan_id)
            raise exception.SmaugException(
                _("Failed to create protection flow"))
        try:
            self.worker.run_flow(protection_flow)
        except Exception:
            LOG.exception(_LE("Failed to run protection flow"))
            raise
        finally:
            checkpoint = self.worker.flow_outputs(protection_flow,
                                                  target='checkpoint')
            return {'checkpoint_id': checkpoint.id}
    def _run_operation(self, operation_id, param):

        self._update_operation_state(
            operation_id,
            {'state': constants.OPERATION_STATE_RUNNING})

        try:
            check_item = [self._CHECK_ITEMS['is_canceled']]
            if self._check_operation(operation_id, check_item):
                return

            try:
                operation = objects.ScheduledOperation.get_by_id(
                    context.get_admin_context(), operation_id)
            except Exception:
                LOG.exception(_LE("Run operation(%s), get operation failed"),
                              operation_id)
                return

            try:
                self._operation_manager.run_operation(
                    operation.operation_type, operation.project_id,
                    operation.operation_definition,
                    param=param)
            except Exception:
                LOG.exception(_LE("Run operation(%s) failed"), operation_id)

        finally:
            self._update_operation_state(
                operation_id,
                {'state': constants.OPERATION_STATE_REGISTERED})
Ejemplo n.º 3
0
    def _run_operation(self, operation_id, param):

        self._update_operation_state(
            operation_id, {'state': constants.OPERATION_STATE_RUNNING})

        try:
            check_item = [self._CHECK_ITEMS['is_canceled']]
            if self._check_operation(operation_id, check_item):
                return

            try:
                operation = objects.ScheduledOperation.get_by_id(
                    context.get_admin_context(), operation_id)
            except Exception:
                LOG.exception(_LE("Run operation(%s), get operation failed"),
                              operation_id)
                return

            try:
                self._operation_manager.run_operation(
                    operation.operation_type,
                    operation.project_id,
                    operation.operation_definition,
                    param=param)
            except Exception:
                LOG.exception(_LE("Run operation(%s) failed"), operation_id)

        finally:
            self._update_operation_state(
                operation_id, {'state': constants.OPERATION_STATE_REGISTERED})
Ejemplo n.º 4
0
def load_plugin(namespace, plugin_name, *args, **kwargs):
    try:
        # Try to resolve plugin by name
        mgr = driver.DriverManager(namespace, plugin_name)
        plugin_class = mgr.driver
    except RuntimeError as e1:
        # fallback to class name
        try:
            plugin_class = importutils.import_class(plugin_name)
        except ImportError as e2:
            LOG.exception(_LE("Error loading plugin by name, %s"), e1)
            LOG.exception(_LE("Error loading plugin by class, %s"), e2)
            raise ImportError(_("Class not found."))
    return plugin_class(*args, **kwargs)
Ejemplo n.º 5
0
    def report_state(self):
        """Update the state of this service in the datastore."""
        if not self.manager.is_working():
            # NOTE(dulek): If manager reports a problem we're not sending
            # heartbeats - to indicate that service is actually down.
            LOG.error(_LE('Manager for service %(binary)s %(host)s is '
                          'reporting problems, not sending heartbeat. '
                          'Service will appear "down".'),
                      {'binary': self.binary,
                       'host': self.host})
            return

        ctxt = context.get_admin_context()
        state_catalog = {}
        try:
            try:
                service_ref = db.service_get(ctxt, self.service_id)
            except exception.NotFound:
                LOG.debug('The service database object disappeared, '
                          'recreating it.')
                self._create_service_ref(ctxt)
                service_ref = db.service_get(ctxt, self.service_id)

            state_catalog['report_count'] = service_ref['report_count'] + 1

            db.service_update(ctxt,
                              self.service_id, state_catalog)

            # TODO(termie): make this pattern be more elegant.
            if getattr(self, 'model_disconnected', False):
                self.model_disconnected = False
                LOG.error(_LE('Recovered model server connection!'))

        except db_exc.DBConnectionError:
            if not getattr(self, 'model_disconnected', False):
                self.model_disconnected = True
                LOG.exception(_LE('model server went away'))

        # NOTE(jsbryant) Other DB errors can happen in HA configurations.
        # such errors shouldn't kill this thread, so we handle them here.
        except db_exc.DBError:
            if not getattr(self, 'model_disconnected', False):
                self.model_disconnected = True
                LOG.exception(_LE('DBError encountered: '))

        except Exception:
            if not getattr(self, 'model_disconnected', False):
                self.model_disconnected = True
                LOG.exception(_LE('Exception encountered: '))
Ejemplo n.º 6
0
def load_plugin(namespace, plugin_name, *args, **kwargs):
    try:
        LOG.debug('Start load plugin %s. ', plugin_name)
        # Try to resolve plugin by name
        mgr = driver.DriverManager(namespace, plugin_name)
        plugin_class = mgr.driver
    except RuntimeError as e1:
        # fallback to class name
        try:
            plugin_class = importutils.import_class(plugin_name)
        except ImportError as e2:
            LOG.exception(_LE("Error loading plugin by name, %s"), e1)
            LOG.exception(_LE("Error loading plugin by class, %s"), e2)
            raise ImportError(_("Class not found."))
    return plugin_class(*args, **kwargs)
Ejemplo n.º 7
0
def create(context, conf):
    conf.register_opts(nova_client_opts, group=SERVICE + '_client')
    try:
        url = utils.get_url(SERVICE,
                            context,
                            conf,
                            append_project_fmt='%(url)s/%(project)s')
    except Exception:
        LOG.error(_LE("Get nova service endpoint url failed."))
        raise

    LOG.info(_LI('Creating nova client with url %s.'), url)

    extensions = nc.discover_extensions(NOVACLIENT_VERSION)

    args = {
        'project_id': context.project_id,
        'auth_token': context.auth_token,
        'extensions': extensions,
    }

    client = nc.Client(NOVACLIENT_VERSION, **args)
    client.client.set_management_url(url)

    return client
Ejemplo n.º 8
0
    def create_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        image_id = resource_node.value.id
        bank_section = checkpoint.get_resource_bank_section(image_id)

        resource_definition = {"resource_id": image_id}
        glance_client = self._glance_client(cntxt)

        LOG.info(_("creating image backup, image_id: %s."), image_id)
        try:
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)
            image_info = glance_client.images.get(image_id)
            image_metadata = {
                "disk_format": image_info.disk_format,
                "container_format": image_info.container_format
            }
            resource_definition["image_metadata"] = image_metadata
            resource_definition["backup_id"] = image_id

            bank_section.create_object("metadata", resource_definition)
        except Exception as err:
            LOG.error(_LE("create image backup failed, image_id: %s."),
                      image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)

        self._add_to_threadpool(self._create_backup, glance_client,
                                bank_section, image_id)
Ejemplo n.º 9
0
    def __init__(self, provider_config):
        super(PluggableProtectionProvider, self).__init__()
        self._config = provider_config
        self._id = self._config.provider.id
        self._name = self._config.provider.name
        self._description = self._config.provider.description
        self._extended_info_schema = {'options_schema': {},
                                      'restore_schema': {},
                                      'saved_info_schema': {}}
        self.checkpoint_collection = None
        self._bank_plugin = None
        self._plugin_map = {}

        if hasattr(self._config.provider, 'bank') \
                and not self._config.provider.bank:
            raise ImportError("Empty bank")
        self._load_bank(self._config.provider.bank)
        if hasattr(self._config.provider, 'plugin'):
            for plugin_name in self._config.provider.plugin:
                if not plugin_name:
                    raise ImportError("Empty protection plugin")
                self._load_plugin(plugin_name)

        if self._bank_plugin:
            self.checkpoint_collection = checkpoint.CheckpointCollection(
                self._bank_plugin)
        else:
            LOG.error(_LE('Bank plugin not exist, check your configuration'))
Ejemplo n.º 10
0
    def get_method(self, request, action, content_type, body):
        """Look up the action-specific method and its extensions."""

        # Look up the method
        try:
            if not self.controller:
                meth = getattr(self, action)
            else:
                meth = getattr(self.controller, action)
        except AttributeError as e:
            with excutils.save_and_reraise_exception(e) as ctxt:
                if (not self.wsgi_actions or action
                        not in ['action', 'create', 'delete', 'update']):
                    LOG.exception(_LE('Get method error.'))
                else:
                    ctxt.reraise = False
        else:
            return meth, self.wsgi_extensions.get(action, [])

        if action == 'action':
            # OK, it's an action; figure out which action...
            mtype = _MEDIA_TYPE_MAP.get(content_type)
            action_name = self.action_peek[mtype](body)
            LOG.debug("Action body: %s", body)
        else:
            action_name = action

        # Look up the action method
        return (self.wsgi_actions[action_name],
                self.wsgi_action_extensions.get(action_name, []))
Ejemplo n.º 11
0
    def create_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        image_id = resource_node.value.id
        bank_section = checkpoint.get_resource_bank_section(image_id)

        resource_definition = {"resource_id": image_id}
        glance_client = self._glance_client(cntxt)

        LOG.info(_("creating image backup, image_id: %s."), image_id)
        try:
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)
            image_info = glance_client.images.get(image_id)
            image_metadata = {
                "disk_format": image_info.disk_format,
                "container_format": image_info.container_format
            }
            resource_definition["image_metadata"] = image_metadata
            resource_definition["backup_id"] = image_id

            bank_section.create_object("metadata", resource_definition)
        except Exception as err:
            LOG.error(_LE("create image backup failed, image_id: %s."),
                      image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)

        self._add_to_threadpool(self._create_backup, glance_client,
                                bank_section, image_id)
Ejemplo n.º 12
0
def create(context, conf, **kwargs):
    auth_url = kwargs["auth_url"]
    username = kwargs["username"]
    password = kwargs["password"]
    tenant_name = context.project_name
    LOG.info(_LI('Creating heat client with url %s.'), auth_url)
    try:
        keystone = kc.Client(version=KEYSTONECLIENT_VERSION,
                             username=username,
                             tenant_name=tenant_name,
                             password=password,
                             auth_url=auth_url)

        auth_token = keystone.auth_ref['token']['id']
        heat_endpoint = ''
        services = keystone.auth_ref['serviceCatalog']
        for service in services:
            if service['name'] == 'heat':
                heat_endpoint = service['endpoints'][0]['publicURL']
        heat = hc.Client(HEATCLIENT_VERSION, endpoint=heat_endpoint,
                         token=auth_token)
        return heat
    except Exception:
        LOG.error(_LE('Creating heat client with url %s.'), auth_url)
        raise
Ejemplo n.º 13
0
    def restore_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        resource_id = resource_node.value.id
        heat_template = kwargs.get("heat_template")

        name = kwargs.get("restore_name",
                          "%s@%s" % (checkpoint.id, resource_id))
        description = kwargs.get("restore_description")

        heat_resource_id = str(uuid4())
        heat_resource = HeatResource(heat_resource_id,
                                     constants.VOLUME_RESOURCE_TYPE)

        bank_section = checkpoint.get_resource_bank_section(resource_id)
        try:
            resource_definition = bank_section.get_object("metadata")
            backup_id = resource_definition["backup_id"]
            properties = {"backup_id": backup_id,
                          "name": name}

            if description is not None:
                properties["description"] = description

            for key, value in properties.items():
                heat_resource.set_property(key, value)

            heat_template.put_resource(resource_id, heat_resource)
        except Exception as e:
            LOG.error(_LE("restore volume backup failed, volume_id: %s."),
                      resource_id)
            raise exception.RestoreBackupFailed(
                reason=six.text_type(e),
                resource_id=resource_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE
            )
Ejemplo n.º 14
0
    def list_protectable_dependents(self, context, protectable_id,
                                    protectable_type):
        LOG.info(
            _LI("Start to list dependents of resource "
                "(type:%(type)s, id:%(id)s)"), {
                    'type': protectable_type,
                    'id': protectable_id
                })

        parent_resource = Resource(type=protectable_type,
                                   id=protectable_id,
                                   name="")

        try:
            dependent_resources = \
                self.protectable_registry.fetch_dependent_resources(
                    context, parent_resource)
        except exception.ListProtectableResourceFailed as err:
            LOG.error(
                _LE("List dependent resources of (%(res)s) "
                    "failed: %(err)s"), {
                        'res': parent_resource,
                        'err': six.text_type(err)
                    })
            raise

        result = []
        for resource in dependent_resources:
            result.append(
                dict(type=resource.type, id=resource.id, name=resource.name))

        return result
Ejemplo n.º 15
0
    def delete_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        resource_id = resource_node.value.id

        bank_section = checkpoint.get_resource_bank_section(resource_id)
        cinder_client = self._cinder_client(cntxt)

        LOG.info(_("deleting volume backup, volume_id: %s."), resource_id)
        try:
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_DELETING)
            resource_definition = bank_section.get_object("metadata")
            backup_id = resource_definition["backup_id"]
            cinder_client.backups.delete(backup_id)
            bank_section.delete_object("metadata", resource_definition)
            self.protection_resource_map[resource_id] = {
                "bank_section": bank_section,
                "backup_id": backup_id,
                "cinder_client": cinder_client,
                "operation": "delete"
            }
        except Exception as e:
            LOG.error(_LE("delete volume backup failed, volume_id: %s."),
                      resource_id)
            bank_section.update_object("status",
                                       constants.CHECKPOINT_STATUS_ERROR)

            raise exception.DeleteBackupFailed(
                reason=six.text_type(e),
                resource_id=resource_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE
            )
Ejemplo n.º 16
0
    def list_protectable_dependents(self, context,
                                    protectable_id,
                                    protectable_type):
        LOG.info(_LI("Start to list dependents of resource "
                     "(type:%(type)s, id:%(id)s)"),
                 {'type': protectable_type,
                  'id': protectable_id})

        parent_resource = Resource(type=protectable_type, id=protectable_id,
                                   name="")

        try:
            dependent_resources = \
                self.protectable_registry.fetch_dependent_resources(
                    context, parent_resource)
        except exception.ListProtectableResourceFailed as err:
            LOG.error(_LE("List dependent resources of (%(res)s) "
                          "failed: %(err)s"),
                      {'res': parent_resource,
                       'err': six.text_type(err)})
            raise

        result = []
        for resource in dependent_resources:
            result.append(dict(type=resource.type, id=resource.id,
                               name=resource.name))

        return result
Ejemplo n.º 17
0
    def get_dependent_resources(self, context, parent_resource):
        def _is_attached_to(vol):
            if parent_resource.type == constants.SERVER_RESOURCE_TYPE:
                return any([
                    s.get('server_id') == parent_resource.id
                    for s in vol.attachments
                ])
            if parent_resource.type == constants.PROJECT_RESOURCE_TYPE:
                return getattr(vol, 'os-vol-tenant-attr:tenant_id') == \
                    parent_resource.id

        try:
            volumes = self._client(context).volumes.list(detailed=True)
        except Exception as e:
            LOG.exception(
                _LE("List all detailed volumes "
                    "from cinder failed."))
            raise exception.ListProtectableResourceFailed(
                type=self._SUPPORT_RESOURCE_TYPE, reason=six.text_type(e))
        else:
            return [
                resource.Resource(type=self._SUPPORT_RESOURCE_TYPE,
                                  id=vol.id,
                                  name=vol.name) for vol in volumes
                if _is_attached_to(vol)
            ]
Ejemplo n.º 18
0
 def sync_status(self):
     for resource_id, resource_info in self.protection_resource_map.items():
         backup_id = resource_info["backup_id"]
         bank_section = resource_info["bank_section"]
         cinder_client = resource_info["cinder_client"]
         operation = resource_info["operation"]
         try:
             backup = cinder_client.backups.get(backup_id)
             if backup.status == "available":
                 bank_section.update_object(
                     "status", constants.RESOURCE_STATUS_AVAILABLE)
                 self.protection_resource_map.pop(resource_id)
             elif backup.status in ["error", "error-deleting"]:
                 bank_section.update_object(
                     "status", constants.RESOURCE_STATUS_ERROR)
                 self.protection_resource_map.pop(resource_id)
             else:
                 continue
         except Exception as exc:
             if operation == "delete" and type(exc) == NotFound:
                 bank_section.update_object(
                     "status",
                     constants.RESOURCE_STATUS_DELETED)
                 LOG.info(_("deleting volume backup finished."
                            "backup id: %s"), backup_id)
             else:
                 LOG.error(_LE("deleting volume backup error.exc:%s."),
                           six.text_type(exc))
             self.protection_resource_map.pop(resource_id)
Ejemplo n.º 19
0
    def delete_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        resource_id = resource_node.value.id

        bank_section = checkpoint.get_resource_bank_section(resource_id)
        cinder_client = self._cinder_client(cntxt)

        LOG.info(_("deleting volume backup, volume_id: %s."), resource_id)
        try:
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_DELETING)
            resource_definition = bank_section.get_object("metadata")
            backup_id = resource_definition["backup_id"]
            cinder_client.backups.delete(backup_id)
            bank_section.delete_object("metadata", resource_definition)
            self.protection_resource_map[resource_id] = {
                "bank_section": bank_section,
                "backup_id": backup_id,
                "cinder_client": cinder_client,
                "operation": "delete"
            }
        except Exception as e:
            LOG.error(_LE("delete volume backup failed, volume_id: %s."),
                      resource_id)
            bank_section.update_object("status",
                                       constants.CHECKPOINT_STATUS_ERROR)

            raise exception.DeleteBackupFailed(
                reason=six.text_type(e),
                resource_id=resource_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE)
Ejemplo n.º 20
0
    def restore_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        resource_id = resource_node.value.id
        heat_template = kwargs.get("heat_template")

        name = kwargs.get("restore_name",
                          "%s@%s" % (checkpoint.id, resource_id))
        description = kwargs.get("restore_description")

        heat_resource_id = str(uuid4())
        heat_resource = HeatResource(heat_resource_id,
                                     constants.VOLUME_RESOURCE_TYPE)

        bank_section = checkpoint.get_resource_bank_section(resource_id)
        try:
            resource_definition = bank_section.get_object("metadata")
            backup_id = resource_definition["backup_id"]
            properties = {"backup_id": backup_id, "name": name}

            if description is not None:
                properties["description"] = description

            for key, value in properties.items():
                heat_resource.set_property(key, value)

            heat_template.put_resource(resource_id, heat_resource)
        except Exception as e:
            LOG.error(_LE("restore volume backup failed, volume_id: %s."),
                      resource_id)
            raise exception.RestoreBackupFailed(
                reason=six.text_type(e),
                resource_id=resource_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE)
Ejemplo n.º 21
0
 def get_object(self, key):
     try:
         return self._get_object(container=self.bank_object_container,
                                 obj=key)
     except SwiftConnectionFailed as err:
         LOG.error(_LE("get object failed, err: %s."), err)
         raise exception.BankGetObjectFailed(reason=err, key=key)
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
 def build_flow(self, flow_name, flow_type='graph'):
     if flow_type == 'linear':
         return linear_flow.Flow(flow_name)
     elif flow_type == 'graph':
         return graph_flow.Flow(flow_name)
     else:
         raise ValueError(_LE("unsupported flow type:%s") % flow_type)
Ejemplo n.º 24
0
 def output(self, flow_engine, target=None):
     if flow_engine is None:
         LOG.error(_LE("Flow engine is None,return nothing"))
         return
     if target:
         return flow_engine.storage.fetch(target)
     return flow_engine.storage.fetch_all()
Ejemplo n.º 25
0
def create(context, conf):
    register_opts(conf)

    if hasattr(conf.swift_client, 'swift_auth_url') and \
            conf.swift_client.swift_auth_url:
        connection = swift.Connection(
            authurl=conf.swift_client.swift_auth_url,
            auth_version=conf.swift_client.swift_auth_version,
            tenant_name=conf.swift_client.swift_tenant_name,
            user=conf.swift_client.swift_user,
            key=conf.swift_client.swift_key,
            retries=conf.swift_client.swift_retry_attempts,
            starting_backoff=conf.swift_client.swift_retry_backoff,
            insecure=conf.swift_client.swift_auth_insecure,
            cacert=conf.swift_client.swift_ca_cert_file)
    else:
        try:
            url = utils.get_url(SERVICE, context, conf,
                                append_project_fmt='%(url)s/AUTH_%(project)s')
        except Exception:
            LOG.error(_LE("Get swift service endpoint url failed"))
            raise
        LOG.info(_LI("Creating swift client with url %s."), url)
        connection = swift.Connection(
            preauthurl=url,
            preauthtoken=context.auth_token,
            retries=conf.swift_client.swift_retry_attempts,
            starting_backoff=conf.swift_client.swift_retry_backoff,
            insecure=conf.swift_client.swift_auth_insecure,
            cacert=conf.swift_client.swift_ca_cert_file)
    return connection
Ejemplo n.º 26
0
    def get_method(self, request, action, content_type, body):
        """Look up the action-specific method and its extensions."""

        # Look up the method
        try:
            if not self.controller:
                meth = getattr(self, action)
            else:
                meth = getattr(self.controller, action)
        except AttributeError as e:
            with excutils.save_and_reraise_exception(e) as ctxt:
                if (not self.wsgi_actions or action not in ['action',
                                                            'create',
                                                            'delete',
                                                            'update']):
                    LOG.exception(_LE('Get method error.'))
                else:
                    ctxt.reraise = False
        else:
            return meth, self.wsgi_extensions.get(action, [])

        if action == 'action':
            # OK, it's an action; figure out which action...
            mtype = _MEDIA_TYPE_MAP.get(content_type)
            action_name = self.action_peek[mtype](body)
            LOG.debug("Action body: %s", body)
        else:
            action_name = action

        # Look up the action method
        return (self.wsgi_actions[action_name],
                self.wsgi_action_extensions.get(action_name, []))
Ejemplo n.º 27
0
    def list_protectable_instances(self, context,
                                   protectable_type=None,
                                   marker=None,
                                   limit=None,
                                   sort_keys=None,
                                   sort_dirs=None,
                                   filters=None):

        LOG.info(_LI("Start to list protectable instances of type: %s"),
                 protectable_type)

        try:
            resource_instances = self.protectable_registry.list_resources(
                context, protectable_type)
        except exception.ListProtectableResourceFailed as err:
            LOG.error(_LE("List resources of type %(type)s failed: %(err)s"),
                      {'type': protectable_type,
                       'err': six.text_type(err)})
            raise

        result = []
        for resource in resource_instances:
            result.append(dict(id=resource.id, name=resource.name))

        return result
Ejemplo n.º 28
0
 def build_flow(self, flow_name, flow_type='graph'):
     if flow_type == 'linear':
         return linear_flow.Flow(flow_name)
     elif flow_type == 'graph':
         return graph_flow.Flow(flow_name)
     else:
         raise ValueError(_LE("unsupported flow type:%s") % flow_type)
Ejemplo n.º 29
0
 def output(self, flow_engine, target=None):
     if flow_engine is None:
         LOG.error(_LE("Flow engine is None,return nothing"))
         return
     if target:
         return flow_engine.storage.fetch(target)
     return flow_engine.storage.fetch_all()
Ejemplo n.º 30
0
    def __init__(self, message=None, **kwargs):
        """Initiate the instance of SmaugException

        There are two ways to initiate the instance.
        1. Specify the value of 'message' and leave the 'kwargs' None.
        2. Leave 'message' None, and specify the keyword arguments matched
           with the format of SmaugException.message. Especially, can't
           use the 'message' as the key in the 'kwargs', otherwise, the
           first argument('message') will be set.

        Note: This class doesn't support to create instance of SmaugException
            with another instance.
        """
        self.kwargs = kwargs

        if 'code' not in self.kwargs:
            try:
                self.kwargs['code'] = self.code
            except AttributeError:
                pass

        if not message:
            try:
                message = self.message % kwargs

            except Exception:
                exc_info = sys.exc_info()
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_LE('Exception in string format operation'))
                for name, value in kwargs.items():
                    LOG.error(_LE("%(name)s: %(value)s"), {
                        'name': name,
                        'value': value
                    })
                if CONF.fatal_exception_format_errors:
                    six.reraise(*exc_info)
                # at least get the core message out if something happened
                message = self.message
        elif isinstance(message, Exception):
            message = six.text_type(message)

        # NOTE(luisg): We put the actual message in 'msg' so that we can access
        # it, because if we try to access the message via 'message' it will be
        # overshadowed by the class' message attribute
        self.msg = message
        super(SmaugException, self).__init__(message)
Ejemplo n.º 31
0
    def _trigger_operations(self):
        """Trigger operations once

        returns: wait time for next run
        """
        now = datetime.utcnow()
        expect_run_time = self._next_run_time
        # Just for robustness, actually expect_run_time always <= now
        # but, if the scheduling of eventlet is not accurate, then we
        # can do some adjustments.
        if expect_run_time > now:
            return int(timeutils.delta_seconds(now, expect_run_time))

        window = self._window
        if now > (expect_run_time + timedelta(seconds=window)):
            LOG.exception(
                _LE("TimeTrigger didn't trigger operation "
                    "on time, now=%(now)s, expect_run_time="
                    "%(expect_run_time)s, window=%(window)d"), {
                        'now': now,
                        'expect_run_time': expect_run_time,
                        'window': window
                    })
        else:
            # The self._executor.execute_operation may have I/O operation.
            # If it is, this green thread will be switched out during looping
            # operation_ids. In order to avoid changing self._operation_ids
            # during the green thread is switched out, copy self._operation_ids
            # as the iterative object.
            operation_ids = self._operation_ids.copy()
            for operation_id in operation_ids:
                try:
                    self._executor.execute_operation(operation_id, now,
                                                     expect_run_time, window)
                except Exception:
                    LOG.exception(
                        _LE("Submit operation to executor "
                            "failed, id=%(op_id)s"), operation_id)
                    pass

        self._next_run_time = self._compute_next_run_time(
            datetime.utcnow(), self._trigger_property['end_time'],
            self._trigger_property['format'],
            self._trigger_property['pattern'])

        return None if not self._next_run_time else (int(
            timeutils.delta_seconds(now, self._next_run_time)))
Ejemplo n.º 32
0
 def output(self, flow_engine, target=None):
     if flow_engine is None:
         LOG.error(_LE("Flow engine is None,return nothing"))
         raise exception.InvalidTaskFlowObject(reason="The flow_engine"
                                               " is None")
     if target:
         return flow_engine.storage.fetch(target)
     return flow_engine.storage.fetch_all()
Ejemplo n.º 33
0
 def _get_protection_plugin(self, resource_type):
     for plugin in self.plugin_map.values():
         if hasattr(plugin, "get_supported_resources_types"):
             if resource_type in plugin.get_supported_resources_types():
                 return plugin
     LOG.error(_LE("no plugin support this resource_type:%s"),
               resource_type)
     raise Exception("no plugin support this resource_type")
Ejemplo n.º 34
0
 def delete_object(self, key):
     try:
         self._delete_object(container=self.bank_object_container,
                             obj=key)
     except SwiftConnectionFailed as err:
         LOG.error(_LE("delete object failed, err: %s."), err)
         raise exception.BankDeleteObjectFailed(reasone=err,
                                                key=key)
Ejemplo n.º 35
0
 def get_object(self, key):
     try:
         return self._get_object(container=self.bank_object_container,
                                 obj=key)
     except SwiftConnectionFailed as err:
         LOG.error(_LE("get object failed, err: %s."), err)
         raise exception.BankGetObjectFailed(reasone=err,
                                             key=key)
Ejemplo n.º 36
0
    def __init__(self, config, context, object_container):
        super(SwiftBankPlugin, self).__init__(config)
        self.context = context
        self._config.register_opts(swift_client_opts, "swift_client")
        self.swift_retry_attempts = \
            self._config.swift_client.bank_swift_retry_attempts
        self.swift_retry_backoff = \
            self._config.swift_client.bank_swift_retry_backoff
        self.swift_auth_insecure = \
            self._config.swift_client.bank_swift_auth_insecure
        self.swift_ca_cert_file = \
            self._config.swift_client.bank_swift_ca_cert_file
        self.lease_expire_window = self._config.lease_expire_window
        self.lease_renew_window = self._config.lease_renew_window
        # TODO(luobin):
        # init lease_validity_window
        # according to lease_renew_window if not configured
        self.lease_validity_window = self._config.lease_validity_window

        # TODO(luobin): create a uuid of this bank_plugin
        self.owner_id = str(uuid.uuid4())
        self.lease_expire_time = 0
        self.bank_leases_container = "leases"
        self.bank_object_container = object_container
        self.connection = self._setup_connection()

        # create container
        try:
            self._put_container(self.bank_object_container)
            self._put_container(self.bank_leases_container)
        except SwiftConnectionFailed as err:
            LOG.error(_LE("bank plugin create container failed."))
            raise exception.CreateContainerFailed(reason=err)

        # acquire lease
        try:
            self.acquire_lease()
        except exception.AcquireLeaseFailed as err:
            LOG.error(_LE("bank plugin acquire lease failed."))
            raise err

        # start renew lease
        renew_lease_loop = loopingcall.FixedIntervalLoopingCall(
            self.renew_lease)
        renew_lease_loop.start(interval=self.lease_renew_window,
                               initial_delay=self.lease_renew_window)
Ejemplo n.º 37
0
 def output(self, flow_engine, target=None):
     if flow_engine is None:
         LOG.error(_LE("Flow engine is None,return nothing"))
         raise exception.InvalidTaskFlowObject(reason="The flow_engine"
                                                      " is None")
     if target:
         return flow_engine.storage.fetch(target)
     return flow_engine.storage.fetch_all()
Ejemplo n.º 38
0
 def _get_protection_plugin(self, resource_type):
     for plugin in self.plugin_map.values():
         if hasattr(plugin, "get_supported_resources_types"):
             if resource_type in plugin.get_supported_resources_types():
                 return plugin
     LOG.error(_LE("no plugin support this resource_type:%s"),
               resource_type)
     raise Exception("no plugin support this resource_type")
Ejemplo n.º 39
0
    def start(self):
        """Start serving a WSGI application.

        :returns: None
        :raises: smaug.exception.InvalidInput

        """
        # The server socket object will be closed after server exits,
        # but the underlying file descriptor will remain open, and will
        # give bad file descriptor error. So duplicating the socket object,
        # to keep file descriptor usable.

        dup_socket = self._socket.dup()
        dup_socket.setsockopt(socket.SOL_SOCKET,
                              socket.SO_REUSEADDR, 1)

        # NOTE(praneshp): Call set_tcp_keepalive in oslo to set
        # tcp keepalive parameters. Sockets can hang around forever
        # without keepalive
        netutils.set_tcp_keepalive(dup_socket,
                                   CONF.tcp_keepalive,
                                   CONF.tcp_keepidle,
                                   CONF.tcp_keepalive_count,
                                   CONF.tcp_keepalive_interval)

        if self._use_ssl:
            try:
                ssl_kwargs = {
                    'server_side': True,
                    'certfile': CONF.ssl_cert_file,
                    'keyfile': CONF.ssl_key_file,
                    'cert_reqs': ssl.CERT_NONE,
                }

                if CONF.ssl_ca_file:
                    ssl_kwargs['ca_certs'] = CONF.ssl_ca_file
                    ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED

                dup_socket = ssl.wrap_socket(dup_socket,
                                             **ssl_kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(_LE("Failed to start %(name)s on %(_host)s: "
                                  "%(_port)s with SSL "
                                  "support."), self.__dict__)

        wsgi_kwargs = {
            'func': eventlet.wsgi.server,
            'sock': dup_socket,
            'site': self.app,
            'protocol': self._protocol,
            'custom_pool': self._pool,
            'log': self._logger,
            'socket_timeout': self.client_socket_timeout,
            'keepalive': CONF.wsgi_keep_alive
        }

        self._server = eventlet.spawn(**wsgi_kwargs)
Ejemplo n.º 40
0
    def _trigger_operations(self):
        """Trigger operations once

        returns: wait time for next run
        """
        now = datetime.utcnow()
        expect_run_time = self._next_run_time
        # Just for robustness, actually expect_run_time always <= now
        # but, if the scheduling of eventlet is not accurate, then we
        # can do some adjustments.
        if expect_run_time > now:
            return int(timeutils.delta_seconds(now, expect_run_time))

        window = self._window
        if now > (expect_run_time + timedelta(seconds=window)):
            LOG.exception(_LE("TimeTrigger didn't trigger operation "
                              "on time, now=%(now)s, expect_run_time="
                              "%(expect_run_time)s, window=%(window)d"),
                          {'now': now,
                           'expect_run_time': expect_run_time,
                           'window': window})
        else:
            # The self._executor.execute_operation may have I/O operation.
            # If it is, this green thread will be switched out during looping
            # operation_ids. In order to avoid changing self._operation_ids
            # during the green thread is switched out, copy self._operation_ids
            # as the iterative object.
            operation_ids = self._operation_ids.copy()
            for operation_id in operation_ids:
                try:
                    self._executor.execute_operation(
                        operation_id, now, expect_run_time, window)
                except Exception:
                    LOG.exception(_LE("Submit operation to executor "
                                      "failed, id=%(op_id)s"),
                                  operation_id)
                    pass

        self._next_run_time = self._compute_next_run_time(
            datetime.utcnow(), self._trigger_property['end_time'],
            self._trigger_property['format'],
            self._trigger_property['pattern'])

        return None if not self._next_run_time else (int(
            timeutils.delta_seconds(now, self._next_run_time)))
Ejemplo n.º 41
0
    def __init__(self, message=None, **kwargs):
        """Initiate the instance of SmaugException

        There are two ways to initiate the instance.
        1. Specify the value of 'message' and leave the 'kwargs' None.
        2. Leave 'message' None, and specify the keyword arguments matched
           with the format of SmaugException.message. Especially, can't
           use the 'message' as the key in the 'kwargs', otherwise, the
           first argument('message') will be set.

        Note: This class doesn't support to create instance of SmaugException
            with another instance.
        """
        self.kwargs = kwargs

        if 'code' not in self.kwargs:
            try:
                self.kwargs['code'] = self.code
            except AttributeError:
                pass

        if not message:
            try:
                message = self.message % kwargs

            except Exception:
                exc_info = sys.exc_info()
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_LE('Exception in string format operation'))
                for name, value in kwargs.items():
                    LOG.error(_LE("%(name)s: %(value)s"),
                              {'name': name, 'value': value})
                if CONF.fatal_exception_format_errors:
                    six.reraise(*exc_info)
                # at least get the core message out if something happened
                message = self.message
        elif isinstance(message, Exception):
            message = six.text_type(message)

        # NOTE(luisg): We put the actual message in 'msg' so that we can access
        # it, because if we try to access the message via 'message' it will be
        # overshadowed by the class' message attribute
        self.msg = message
        super(SmaugException, self).__init__(message)
Ejemplo n.º 42
0
 def search_task(self, flow, task_id):
     if not isinstance(flow, graph_flow.Flow):
         LOG.error(_LE("this is not a graph flow,flow name:%s"), flow.name)
         return
     for node, meta in flow.iter_nodes():
         if not isinstance(node, task.FunctorTask):
             continue
         if task_id == getattr(node, 'name'):
             return node
Ejemplo n.º 43
0
 def _load_bank(self, bank_name):
     try:
         plugin = utils.load_plugin(PROTECTION_NAMESPACE, bank_name,
                                    self._config)
     except Exception:
         LOG.error(_LE("Load bank plugin: '%s' failed."), bank_name)
         raise
     else:
         self._bank_plugin = plugin
Ejemplo n.º 44
0
 def _load_bank(self, bank_name):
     try:
         plugin = utils.load_plugin(PROTECTION_NAMESPACE, bank_name,
                                    self._config)
     except Exception:
         LOG.error(_LE("Load bank plugin: '%s' failed."), bank_name)
         raise
     else:
         self._bank_plugin = plugin
Ejemplo n.º 45
0
 def search_task(self, flow, task_id):
     if not isinstance(flow, graph_flow.Flow):
         LOG.error(_LE("this is not a graph flow,flow name:%s"), flow.name)
         return
     for node, meta in flow.iter_nodes():
         if not isinstance(node, task.FunctorTask):
             continue
         if task_id == getattr(node, 'name'):
             return node
Ejemplo n.º 46
0
 def execute(self):
     stack_name = "restore_%s" % str(uuid4())
     LOG.info(_("creating stack, stack_name:%s"), stack_name)
     try:
         body = self._heat_client.stacks.create(
             stack_name=stack_name, template=self._template.to_dict())
         return body['stack']['id']
     except Exception:
         LOG.error(_LE("use heat to create stack failed"))
         raise
Ejemplo n.º 47
0
    def __init__(self, config, context=None):
        super(SwiftBankPlugin, self).__init__(config)
        self._config.register_opts(swift_bank_plugin_opts, "swift_bank_plugin")
        self._config.register_opts(lease_opt, "swift_bank_plugin")
        self.bank_object_container = \
            self._config.swift_bank_plugin.bank_swift_object_container
        self.lease_expire_window = \
            self._config.swift_bank_plugin.lease_expire_window
        self.lease_renew_window = \
            self._config.swift_bank_plugin.lease_renew_window
        self.context = context
        # TODO(luobin):
        # init lease_validity_window
        # according to lease_renew_window if not configured
        self.lease_validity_window = \
            self._config.swift_bank_plugin.lease_validity_window

        # TODO(luobin): create a uuid of this bank_plugin
        self.owner_id = str(uuid.uuid4())
        self.lease_expire_time = 0
        self.bank_leases_container = "leases"
        self.connection = self._setup_connection()

        # create container
        try:
            self._put_container(self.bank_object_container)
            self._put_container(self.bank_leases_container)
        except SwiftConnectionFailed as err:
            LOG.error(_LE("bank plugin create container failed."))
            raise exception.CreateContainerFailed(reason=err)

        # acquire lease
        try:
            self.acquire_lease()
        except exception.AcquireLeaseFailed as err:
            LOG.error(_LE("bank plugin acquire lease failed."))
            raise err

        # start renew lease
        renew_lease_loop = loopingcall.FixedIntervalLoopingCall(
            self.renew_lease)
        renew_lease_loop.start(interval=self.lease_renew_window,
                               initial_delay=self.lease_renew_window)
Ejemplo n.º 48
0
 def renew_lease(self):
     container = self.bank_leases_container
     obj = self.owner_id
     headers = {'X-Delete-After': self.lease_expire_window}
     try:
         self._post_object(container=container, obj=obj, headers=headers)
         self.lease_expire_time = math.floor(
             time.time()) + self.lease_expire_window
     except SwiftConnectionFailed as err:
         LOG.error(_LE("acquire lease failed, err:%s."), err)
Ejemplo n.º 49
0
    def restore(self, context, restore=None):
        LOG.info(_LI("Starting restore service:restore action"))

        checkpoint_id = restore["checkpoint_id"]
        provider_id = restore["provider_id"]
        provider = self.provider_registry.show_provider(provider_id)
        try:
            checkpoint_collection = provider.get_checkpoint_collection()
            checkpoint = checkpoint_collection.get(checkpoint_id)
        except Exception:
            LOG.error(_LE("Invalid checkpoint id: %s"), checkpoint_id)
            raise exception.InvalidInput(
                reason=_("Invalid checkpoint id"))

        if checkpoint.status in [constants.CHECKPOINT_STATUS_ERROR,
                                 constants.CHECKPOINT_STATUS_PROTECTING]:
            raise exception.CheckpointNotAvailable(
                checkpoint_id=checkpoint_id)

        try:
            restoration_flow = self.worker.get_restoration_flow(
                context,
                constants.OPERATION_RESTORE,
                checkpoint,
                provider,
                restore)
        except Exception:
            LOG.exception(
                _LE("Failed to create restoration flow checkpoint: %s"),
                checkpoint_id)
            raise exception.FlowError(
                flow="restore",
                error=_("Failed to create flow"))
        try:
            self.worker.run_flow(restoration_flow)
            return True
        except Exception:
            LOG.exception(
                _LE("Failed to run restoration flow checkpoint: %s"),
                checkpoint_id)
            raise exception.FlowError(
                flow="restore",
                error=_("Failed to run flow"))
Ejemplo n.º 50
0
    def start(self):
        """Start serving a WSGI application.

        :returns: None
        :raises: smaug.exception.InvalidInput

        """
        # The server socket object will be closed after server exits,
        # but the underlying file descriptor will remain open, and will
        # give bad file descriptor error. So duplicating the socket object,
        # to keep file descriptor usable.

        dup_socket = self._socket.dup()
        dup_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # NOTE(praneshp): Call set_tcp_keepalive in oslo to set
        # tcp keepalive parameters. Sockets can hang around forever
        # without keepalive
        netutils.set_tcp_keepalive(dup_socket, CONF.tcp_keepalive,
                                   CONF.tcp_keepidle, CONF.tcp_keepalive_count,
                                   CONF.tcp_keepalive_interval)

        if self._use_ssl:
            try:
                ssl_kwargs = {
                    'server_side': True,
                    'certfile': CONF.ssl_cert_file,
                    'keyfile': CONF.ssl_key_file,
                    'cert_reqs': ssl.CERT_NONE,
                }

                if CONF.ssl_ca_file:
                    ssl_kwargs['ca_certs'] = CONF.ssl_ca_file
                    ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED

                dup_socket = ssl.wrap_socket(dup_socket, **ssl_kwargs)
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _LE("Failed to start %(name)s on %(_host)s: "
                            "%(_port)s with SSL "
                            "support."), self.__dict__)

        wsgi_kwargs = {
            'func': eventlet.wsgi.server,
            'sock': dup_socket,
            'site': self.app,
            'protocol': self._protocol,
            'custom_pool': self._pool,
            'log': self._logger,
            'socket_timeout': self.client_socket_timeout,
            'keepalive': CONF.wsgi_keep_alive
        }

        self._server = eventlet.spawn(**wsgi_kwargs)
Ejemplo n.º 51
0
    def delete(self, context, provider_id, checkpoint_id):
        LOG.info(_LI("Starting protection service:delete action"))
        LOG.debug('provider_id :%s checkpoint_id:%s', provider_id,
                  checkpoint_id)
        provider = self.provider_registry.show_provider(provider_id)
        try:
            checkpoint_collection = provider.get_checkpoint_collection()
            checkpoint = checkpoint_collection.get(checkpoint_id)
        except Exception:
            LOG.error(_LE("get checkpoint failed, checkpoint_id:%s"),
                      checkpoint_id)
            raise exception.InvalidInput(
                reason="Invalid checkpoint_id or provider_id")

        if checkpoint.status in [
            constants.CHECKPOINT_STATUS_ERROR,
            constants.CHECKPOINT_STATUS_PROTECTING
        ]:
            raise exception.CheckpointNotBeDeleted(
                checkpoint_id=checkpoint_id)
        checkpoint.status = constants.CHECKPOINT_STATUS_DELETING
        checkpoint.commit()

        try:
            delete_checkpoint_flow = self.worker.get_delete_checkpoint_flow(
                context,
                constants.OPERATION_DELETE,
                checkpoint,
                provider)
        except Exception:
            LOG.exception(
                _LE("Failed to create delete checkpoint flow, checkpoint:%s."),
                checkpoint_id)
            raise exception.SmaugException(_(
                "Failed to create delete checkpoint flow."
            ))
        try:
            self.worker.run_flow(delete_checkpoint_flow)
            return True
        except Exception:
            LOG.exception(_LE("Failed to run delete checkpoint flow"))
            raise
Ejemplo n.º 52
0
 def show_resource(self, resource_id):
     try:
         image = self._glance_client.images.get(resource_id)
     except Exception as e:
         LOG.exception(_LE("Show a image from glance failed."))
         raise exception.ListProtectableResourceFailed(
             type=self._SUPPORT_RESOURCE_TYPE,
             reason=six.text_type(e))
     else:
         return resource.Resource(type=self._SUPPORT_RESOURCE_TYPE,
                                  id=image.id, name=image.name)
Ejemplo n.º 53
0
    def _list_clients():
        clients_dir = os.path.join(os.path.dirname(__file__), 'clients')
        if not os.path.isdir(clients_dir):
            LOG.error(_LE('clients directory "%s" not found'), clients_dir)
            return

        for file in os.listdir(clients_dir):
            name, ext = os.path.splitext(file)
            if name != '__init__' and ext == '.py':
                LOG.debug('Found client "%s"', name)
                yield '%s.clients.%s' % (__package__, name)
Ejemplo n.º 54
0
 def execute(self):
     stack_name = "restore_%s" % str(uuid4())
     LOG.info(_("creating stack, stack_name:%s"), stack_name)
     try:
         body = self._heat_client.stacks.create(
             stack_name=stack_name,
             template=self._template.to_dict())
         return body['stack']['id']
     except Exception:
         LOG.error(_LE("use heat to create stack failed"))
         raise
Ejemplo n.º 55
0
 def get_resource_reference(self, original_id):
     if original_id in self._original_id_resource_map:
         return {
             "get_resource": (self._original_id_resource_map[original_id])
         }
     elif original_id in self._original_id_parameter_map:
         return self._original_id_parameter_map[original_id]
     else:
         LOG.error(_LE("The reference is not found, original_id:%s"),
                   original_id)
         raise InvalidOriginalId
Ejemplo n.º 56
0
 def show_resource(self, context, resource_id):
     try:
         image = self._glance_client(context).images.get(resource_id)
     except Exception as e:
         LOG.exception(_LE("Show a image from glance failed."))
         raise exception.ListProtectableResourceFailed(
             type=self._SUPPORT_RESOURCE_TYPE, reason=six.text_type(e))
     else:
         return resource.Resource(type=self._SUPPORT_RESOURCE_TYPE,
                                  id=image.id,
                                  name=image.name)