Beispiel #1
0
    def _schedule(self, context, topic, request_spec, **kwargs):
        """Picks a host that is up at random."""

        elevated = context.elevated()
        hosts = self.hosts_up(elevated, topic)
        if not hosts:
            msg = _("Is the appropriate service running?")
            raise exception.NoValidHost(reason=msg)

        hosts = self._filter_hosts(request_spec, hosts, **kwargs)
        if not hosts:
            msg = _("Could not find another host")
            raise exception.NoValidHost(reason=msg)

        return hosts[int(random.random() * len(hosts))]
Beispiel #2
0
    def schedule_create_share(self, context, request_spec, filter_properties):
        """Picks a host that is up and has the fewest shares."""
        # TODO(rushiagr) - pick only hosts that run shares
        elevated = context.elevated()

        share_id = request_spec.get('share_id')
        snapshot_id = request_spec.get('snapshot_id')
        share_properties = request_spec.get('share_properties')
        share_size = share_properties.get('size')
        availability_zone = share_properties.get('availability_zone')

        zone, host = None, None
        if availability_zone:
            zone, _x, host = availability_zone.partition(':')
        if host and context.is_admin:
            service = db.service_get_by_args(elevated, host, CONF.share_topic)
            if not utils.service_is_up(service):
                raise exception.WillNotSchedule(host=host)
            updated_share = driver.share_update_db(context, share_id, host)
            self.share_rpcapi.create_share(context,
                                           updated_share,
                                           host,
                                           request_spec,
                                           None,
                                           snapshot_id=snapshot_id)
            return None

        results = db.service_get_all_share_sorted(elevated)
        if zone:
            results = [(service, gigs) for (service, gigs) in results
                       if service['availability_zone'] == zone]
        for result in results:
            (service, share_gigabytes) = result
            if share_gigabytes + share_size > CONF.max_gigabytes:
                msg = _("Not enough allocatable share gigabytes remaining")
                raise exception.NoValidHost(reason=msg)
            if utils.service_is_up(service) and not service['disabled']:
                updated_share = driver.share_update_db(context, share_id,
                                                       service['host'])
                self.share_rpcapi.create_share(context,
                                               updated_share,
                                               service['host'],
                                               request_spec,
                                               None,
                                               snapshot_id=snapshot_id)
                return None
        msg = _("Is the appropriate service running?")
        raise exception.NoValidHost(reason=msg)
    def _populate_retry_share(self, filter_properties, properties):
        """Populate filter properties with retry history.

        Populate filter properties with history of retries for this
        request. If maximum retries is exceeded, raise NoValidHost.
        """
        max_attempts = self.max_attempts
        retry = filter_properties.pop('retry', {})

        if max_attempts == 1:
            # re-scheduling is disabled.
            return

        # retry is enabled, update attempt count:
        if retry:
            retry['num_attempts'] += 1
        else:
            retry = {
                'num_attempts': 1,
                'hosts': []  # list of share service hosts tried
            }
        filter_properties['retry'] = retry

        share_id = properties.get('share_id')
        self._log_share_error(share_id, retry)

        if retry['num_attempts'] > max_attempts:
            msg = _("Exceeded max scheduling attempts %(max_attempts)d for "
                    "share %(share_id)s") % {
                        "max_attempts": max_attempts,
                        "share_id": share_id
                    }
            raise exception.NoValidHost(reason=msg)
    def schedule_create_share(self, context, request_spec, filter_properties):
        weighed_host = self._schedule_share(context, request_spec,
                                            filter_properties)

        if not weighed_host:
            raise exception.NoValidHost(reason="")

        host = weighed_host.obj.host
        share_id = request_spec['share_id']
        snapshot_id = request_spec['snapshot_id']

        updated_share = driver.share_update_db(context, share_id, host)
        self._post_select_populate_filter_properties(filter_properties,
                                                     weighed_host.obj)

        # context is not serializable
        filter_properties.pop('context', None)

        self.share_rpcapi.create_share_instance(
            context,
            updated_share.instance,
            host,
            request_spec=request_spec,
            filter_properties=filter_properties,
            snapshot_id=snapshot_id)
Beispiel #5
0
    def test_create_share_exception_puts_share_in_error_state(
            self, _mock_message_create):
        """Test NoValidHost exception for create_share.

        Puts the share in 'error' state and eats the exception.
        """
        fake_share_id = 1

        request_spec = {'share_id': fake_share_id}
        ex = exception.NoValidHost(reason='')
        with mock.patch.object(
                self.manager.driver, 'schedule_create_share',
                mock.Mock(side_effect=ex)):
            self.mock_object(manager.LOG, 'error')

            self.manager.create_share_instance(
                self.context, request_spec=request_spec, filter_properties={})

            db.share_update.assert_called_once_with(
                self.context, fake_share_id, {'status': 'error'})
            (self.manager.driver.schedule_create_share.
                assert_called_once_with(self.context, request_spec, {}))
            manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)

            _mock_message_create.assert_called_once_with(
                self.context,
                message_field.Action.ALLOCATE_HOST,
                self.context.project_id, resource_type='SHARE',
                exception=ex, resource_id=fake_share_id)
Beispiel #6
0
    def schedule_create_replica(self, context, request_spec,
                                filter_properties):
        share_replica_id = request_spec['share_instance_properties'].get('id')

        weighed_host = self._schedule_share(context, request_spec,
                                            filter_properties)

        if not weighed_host:
            msg = _('Failed to find a weighted host for scheduling share '
                    'replica %s.')
            raise exception.NoValidHost(reason=msg % share_replica_id)

        host = weighed_host.obj.host

        updated_share_replica = base.share_replica_update_db(
            context, share_replica_id, host)
        self._post_select_populate_filter_properties(filter_properties,
                                                     weighed_host.obj)

        # context is not serializable
        filter_properties.pop('context', None)

        self.share_rpcapi.create_share_replica(
            context,
            updated_share_replica,
            host,
            request_spec=request_spec,
            filter_properties=filter_properties)
Beispiel #7
0
    def test_manage_share_exception(self):

        share = db_utils.create_share()

        self.mock_object(base.Scheduler, 'host_passes_filters',
                         mock.Mock(side_effect=exception.NoValidHost('fake')))

        self.assertRaises(exception.NoValidHost, self.manager.manage_share,
                          self.context, share['id'], 'driver_options', {},
                          None)
Beispiel #8
0
    def test_migrate_share_to_host_no_valid_host(self):

        share = db_utils.create_share()
        host = 'fake@backend#pool'

        self.mock_object(
            base.Scheduler, 'host_passes_filters',
            mock.Mock(side_effect=[exception.NoValidHost('fake')]))

        self.manager.migrate_share_to_host(self.context, share['id'], host,
                                           False, {}, None)
Beispiel #9
0
    def schedule_create_share(self, context, request_spec, filter_properties):
        """Picks a host that is up and has the fewest shares."""
        # TODO(rushiagr) - pick only hosts that run shares
        elevated = context.elevated()

        share_id = request_spec.get('share_id')
        snapshot_id = request_spec.get('snapshot_id')
        share_properties = request_spec.get('share_properties')
        share_size = share_properties.get('size')

        instance_properties = request_spec.get('share_instance_properties', {})
        availability_zone_id = instance_properties.get('availability_zone_id')

        results = db.service_get_all_share_sorted(elevated)
        if availability_zone_id:
            results = [
                (service_g, gigs) for (service_g, gigs) in results
                if (service_g['availability_zone_id'] == availability_zone_id)
            ]
        for result in results:
            (service, share_gigabytes) = result
            if share_gigabytes + share_size > CONF.max_gigabytes:
                msg = _("Not enough allocatable share gigabytes remaining")
                raise exception.NoValidHost(reason=msg)
            if utils.service_is_up(service) and not service['disabled']:
                updated_share = base.share_update_db(context, share_id,
                                                     service['host'])
                self.share_rpcapi.create_share_instance(
                    context,
                    updated_share.instance,
                    service['host'],
                    request_spec,
                    None,
                    snapshot_id=snapshot_id)
                return None
        msg = _("Is the appropriate service running?")
        raise exception.NoValidHost(reason=msg)
Beispiel #10
0
    def test_manage_share_exception(self):

        share = db_utils.create_share()

        db_update = self.mock_object(db, 'share_update', mock.Mock())
        self.mock_object(base.Scheduler, 'host_passes_filters',
                         mock.Mock(side_effect=exception.NoValidHost('fake')))

        share_id = share['id']

        self.assertRaises(exception.NoValidHost, self.manager.manage_share,
                          self.context, share['id'], 'driver_options',
                          {'share_id': share_id}, None)
        db_update.assert_called_once_with(self.context, share_id, {
            'status': constants.STATUS_MANAGE_ERROR,
            'size': 1
        })
Beispiel #11
0
    def schedule_create_share_group(self, context, share_group_id,
                                    request_spec, filter_properties):

        LOG.info("Scheduling share group %s.", share_group_id)
        host = self._get_best_host_for_share_group(context, request_spec)

        if not host:
            msg = _("No hosts available for share group %s.") % share_group_id
            raise exception.NoValidHost(reason=msg)

        msg = "Chose host %(host)s for create_share_group %(group)s."
        LOG.info(msg, {'host': host, 'group': share_group_id})

        updated_share_group = base.share_group_update_db(
            context, share_group_id, host)

        self.share_rpcapi.create_share_group(
            context, updated_share_group, host)
    def schedule_create_consistency_group(self, context, group_id,
                                          request_spec, filter_properties):

        LOG.info(_LI("Scheduling consistency group %s") % group_id)

        host = self._get_best_host_for_consistency_group(context, request_spec)

        if not host:
            msg = _("No hosts available for consistency group %s") % group_id
            raise exception.NoValidHost(reason=msg)

        msg = _LI("Chose host %(host)s for create_consistency_group %(cg_id)s")
        LOG.info(msg % {'host': host, 'cg_id': group_id})

        updated_group = driver.cg_update_db(context, group_id, host)

        self.share_rpcapi.create_consistency_group(context, updated_group,
                                                   host)
Beispiel #13
0
    def host_passes_filters(self, context, host, request_spec,
                            filter_properties):

        elevated = context.elevated()

        filter_properties, share_properties = self._format_filter_properties(
            context, filter_properties, request_spec)

        hosts = self.host_manager.get_all_host_states_share(elevated)
        hosts = self.host_manager.get_filtered_hosts(hosts, filter_properties)
        hosts = self.host_manager.get_weighed_hosts(hosts, filter_properties)

        for tgt_host in hosts:
            if tgt_host.obj.host == host:
                return tgt_host.obj

        msg = (_('Cannot place share %(id)s on %(host)s')
               % {'id': request_spec['share_id'], 'host': host})
        raise exception.NoValidHost(reason=msg)
Beispiel #14
0
    def _schedule_share(self, context, request_spec, filter_properties=None):
        """Returns a list of hosts that meet the required specs.

        The list is ordered by their fitness.
        """
        elevated = context.elevated()

        filter_properties, share_properties = self._format_filter_properties(
            context, filter_properties, request_spec)

        # Find our local list of acceptable hosts by filtering and
        # weighing our options. we virtually consume resources on
        # it so subsequent selections can adjust accordingly.

        # Note: remember, we are using an iterator here. So only
        # traverse this list once.
        hosts = self.host_manager.get_all_host_states_share(elevated)

        # Filter local hosts based on requirements ...
        hosts, last_filter = self.host_manager.get_filtered_hosts(
            hosts, filter_properties)

        if not hosts:
            msg = _('Failed to find a weighted host, the last executed filter'
                    ' was %s.')
            raise exception.NoValidHost(
                reason=msg % last_filter,
                detail_data={'last_filter': last_filter})

        LOG.debug("Filtered share %(hosts)s", {"hosts": hosts})
        # weighted_host = WeightedHost() ... the best
        # host for the job.
        weighed_hosts = self.host_manager.get_weighed_hosts(hosts,
                                                            filter_properties)
        best_host = weighed_hosts[0]
        LOG.debug("Choosing for share: %(best_host)s",
                  {"best_host": best_host})
        # NOTE(rushiagr): updating the available space parameters at same place
        best_host.obj.consume_from_share(share_properties)
        return best_host
Beispiel #15
0
 def raise_no_valid_host(*args, **kwargs):
     raise exception.NoValidHost(reason="")
Beispiel #16
0
class SchedulerManagerTestCase(test.TestCase):
    """Test case for scheduler manager."""

    manager_cls = manager.SchedulerManager
    driver_cls = base.Scheduler
    driver_cls_name = 'manila.scheduler.drivers.base.Scheduler'

    def setUp(self):
        super(SchedulerManagerTestCase, self).setUp()
        self.flags(scheduler_driver=self.driver_cls_name)
        self.manager = self.manager_cls()
        self.context = context.RequestContext('fake_user', 'fake_project')
        self.topic = 'fake_topic'
        self.fake_args = (1, 2, 3)
        self.fake_kwargs = {'cat': 'meow', 'dog': 'woof'}

    def raise_no_valid_host(*args, **kwargs):
        raise exception.NoValidHost(reason="")

    def test_1_correct_init(self):
        # Correct scheduler driver
        manager = self.manager
        self.assertIsInstance(manager.driver, self.driver_cls)

    @ddt.data('manila.scheduler.filter_scheduler.FilterScheduler',
              'manila.scheduler.drivers.filter.FilterScheduler')
    def test_scheduler_driver_mapper(self, driver_class):

        test_manager = manager.SchedulerManager(scheduler_driver=driver_class)

        self.assertIsInstance(test_manager.driver, filter.FilterScheduler)

    def test_init_host(self):

        self.mock_object(context, 'get_admin_context',
                         mock.Mock(return_value='fake_admin_context'))
        self.mock_object(self.manager, 'request_service_capabilities')

        self.manager.init_host()

        self.manager.request_service_capabilities.assert_called_once_with(
            'fake_admin_context')

    def test_get_host_list(self):

        self.mock_object(self.manager.driver, 'get_host_list')

        self.manager.get_host_list(context)

        self.manager.driver.get_host_list.assert_called_once_with()

    def test_get_service_capabilities(self):

        self.mock_object(self.manager.driver, 'get_service_capabilities')

        self.manager.get_service_capabilities(context)

        self.manager.driver.get_service_capabilities.assert_called_once_with()

    def test_update_service_capabilities(self):
        service_name = 'fake_service'
        host = 'fake_host'
        with mock.patch.object(self.manager.driver,
                               'update_service_capabilities', mock.Mock()):
            self.manager.update_service_capabilities(self.context,
                                                     service_name=service_name,
                                                     host=host)
            (self.manager.driver.update_service_capabilities.
             assert_called_once_with(service_name, host, {}))
        with mock.patch.object(self.manager.driver,
                               'update_service_capabilities', mock.Mock()):
            capabilities = {'fake_capability': 'fake_value'}
            self.manager.update_service_capabilities(self.context,
                                                     service_name=service_name,
                                                     host=host,
                                                     capabilities=capabilities)
            (self.manager.driver.update_service_capabilities.
             assert_called_once_with(service_name, host, capabilities))

    @mock.patch.object(db, 'share_update', mock.Mock())
    def test_create_share_exception_puts_share_in_error_state(self):
        """Test NoValidHost exception for create_share.

        Puts the share in 'error' state and eats the exception.
        """
        fake_share_id = 1

        request_spec = {'share_id': fake_share_id}
        with mock.patch.object(
                self.manager.driver, 'schedule_create_share',
                mock.Mock(side_effect=self.raise_no_valid_host)):
            self.mock_object(manager.LOG, 'error')

            self.manager.create_share_instance(self.context,
                                               request_spec=request_spec,
                                               filter_properties={})

            db.share_update.assert_called_once_with(self.context,
                                                    fake_share_id,
                                                    {'status': 'error'})
            (self.manager.driver.schedule_create_share.assert_called_once_with(
                self.context, request_spec, {}))
            manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)

    @mock.patch.object(db, 'share_update', mock.Mock())
    def test_create_share_other_exception_puts_share_in_error_state(self):
        """Test any exception except NoValidHost for create_share.

        Puts the share in 'error' state and re-raises the exception.
        """
        fake_share_id = 1

        request_spec = {'share_id': fake_share_id}
        with mock.patch.object(self.manager.driver, 'schedule_create_share',
                               mock.Mock(side_effect=exception.QuotaError)):
            self.mock_object(manager.LOG, 'error')

            self.assertRaises(exception.QuotaError,
                              self.manager.create_share_instance,
                              self.context,
                              request_spec=request_spec,
                              filter_properties={})

            db.share_update.assert_called_once_with(self.context,
                                                    fake_share_id,
                                                    {'status': 'error'})
            (self.manager.driver.schedule_create_share.assert_called_once_with(
                self.context, request_spec, {}))
            manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)

    def test_get_pools(self):
        """Ensure get_pools exists and calls base_scheduler.get_pools."""
        mock_get_pools = self.mock_object(self.manager.driver, 'get_pools',
                                          mock.Mock(return_value='fake_pools'))

        result = self.manager.get_pools(self.context, filters='fake_filters')

        mock_get_pools.assert_called_once_with(self.context, 'fake_filters')
        self.assertEqual('fake_pools', result)

    @mock.patch.object(db, 'share_group_update', mock.Mock())
    def test_create_group_no_valid_host_puts_group_in_error_state(self):
        """Test that NoValidHost is raised for create_share_group.

        Puts the share in 'error' state and eats the exception.
        """

        fake_group_id = 1
        group_id = fake_group_id
        request_spec = {"share_group_id": group_id}
        with mock.patch.object(
                self.manager.driver, 'schedule_create_share_group',
                mock.Mock(side_effect=self.raise_no_valid_host)):
            self.manager.create_share_group(self.context,
                                            fake_group_id,
                                            request_spec=request_spec,
                                            filter_properties={})
            db.share_group_update.assert_called_once_with(
                self.context, fake_group_id, {'status': 'error'})
            (self.manager.driver.schedule_create_share_group.
             assert_called_once_with(self.context, group_id, request_spec, {}))

    @mock.patch.object(db, 'share_group_update', mock.Mock())
    def test_create_group_exception_puts_group_in_error_state(self):
        """Test that exceptions for create_share_group.

        Puts the share in 'error' state and raises the exception.
        """

        fake_group_id = 1
        group_id = fake_group_id
        request_spec = {"share_group_id": group_id}
        with mock.patch.object(self.manager.driver,
                               'schedule_create_share_group',
                               mock.Mock(side_effect=exception.NotFound)):
            self.assertRaises(exception.NotFound,
                              self.manager.create_share_group,
                              self.context,
                              fake_group_id,
                              request_spec=request_spec,
                              filter_properties={})

    def test_migrate_share_to_host(self):
        class fake_host(object):
            host = 'fake@backend#pool'

        share = db_utils.create_share()
        host = fake_host()

        self.mock_object(db, 'share_get', mock.Mock(return_value=share))
        self.mock_object(share_rpcapi.ShareAPI, 'migration_start',
                         mock.Mock(side_effect=TypeError))
        self.mock_object(base.Scheduler, 'host_passes_filters',
                         mock.Mock(return_value=host))

        self.assertRaises(TypeError, self.manager.migrate_share_to_host,
                          self.context, share['id'], 'fake@backend#pool',
                          False, True, True, False, True, 'fake_net_id',
                          'fake_type_id', {}, None)

        db.share_get.assert_called_once_with(self.context, share['id'])
        base.Scheduler.host_passes_filters.assert_called_once_with(
            self.context, 'fake@backend#pool', {}, None)
        share_rpcapi.ShareAPI.migration_start.assert_called_once_with(
            self.context, share, host.host, False, True, True, False, True,
            'fake_net_id', 'fake_type_id')

    @ddt.data(exception.NoValidHost(reason='fake'), TypeError)
    def test_migrate_share_to_host_exception(self, exc):

        share = db_utils.create_share(status=constants.STATUS_MIGRATING)
        host = 'fake@backend#pool'
        request_spec = {'share_id': share['id']}

        self.mock_object(db, 'share_get', mock.Mock(return_value=share))
        self.mock_object(base.Scheduler, 'host_passes_filters',
                         mock.Mock(side_effect=exc))
        self.mock_object(db, 'share_update')
        self.mock_object(db, 'share_instance_update')

        capture = (exception.NoValidHost
                   if isinstance(exc, exception.NoValidHost) else TypeError)

        self.assertRaises(capture, self.manager.migrate_share_to_host,
                          self.context, share['id'], host, False, True, True,
                          False, True, 'fake_net_id', 'fake_type_id',
                          request_spec, None)

        base.Scheduler.host_passes_filters.assert_called_once_with(
            self.context, host, request_spec, None)
        db.share_get.assert_called_once_with(self.context, share['id'])
        db.share_update.assert_called_once_with(
            self.context, share['id'],
            {'task_state': constants.TASK_STATE_MIGRATION_ERROR})
        db.share_instance_update.assert_called_once_with(
            self.context, share.instance['id'],
            {'status': constants.STATUS_AVAILABLE})

    def test_manage_share(self):

        share = db_utils.create_share()

        self.mock_object(db, 'share_get', mock.Mock(return_value=share))
        self.mock_object(share_rpcapi.ShareAPI, 'manage_share')
        self.mock_object(base.Scheduler, 'host_passes_filters')

        self.manager.manage_share(self.context, share['id'], 'driver_options',
                                  {}, None)

    def test_manage_share_exception(self):

        share = db_utils.create_share()

        db_update = self.mock_object(db, 'share_update', mock.Mock())
        self.mock_object(base.Scheduler, 'host_passes_filters',
                         mock.Mock(side_effect=exception.NoValidHost('fake')))

        share_id = share['id']

        self.assertRaises(exception.NoValidHost, self.manager.manage_share,
                          self.context, share['id'], 'driver_options',
                          {'share_id': share_id}, None)
        db_update.assert_called_once_with(self.context, share_id, {
            'status': constants.STATUS_MANAGE_ERROR,
            'size': 1
        })

    def test_create_share_replica_exception_path(self):
        """Test 'raisable' exceptions for create_share_replica."""
        db_update = self.mock_object(db, 'share_replica_update')
        self.mock_object(db, 'share_snapshot_instance_get_all_with_filters',
                         mock.Mock(return_value=[{
                             'id': '123'
                         }]))
        snap_update = self.mock_object(db, 'share_snapshot_instance_update')
        request_spec = fakes.fake_replica_request_spec()
        replica_id = request_spec.get('share_instance_properties').get('id')
        expected_updates = {
            'status': constants.STATUS_ERROR,
            'replica_state': constants.STATUS_ERROR,
        }
        with mock.patch.object(self.manager.driver, 'schedule_create_replica',
                               mock.Mock(side_effect=exception.NotFound)):

            self.assertRaises(exception.NotFound,
                              self.manager.create_share_replica,
                              self.context,
                              request_spec=request_spec,
                              filter_properties={})
            db_update.assert_called_once_with(self.context, replica_id,
                                              expected_updates)
            snap_update.assert_called_once_with(
                self.context, '123', {'status': constants.STATUS_ERROR})

    def test_create_share_replica_no_valid_host(self):
        """Test the NoValidHost exception for create_share_replica."""
        db_update = self.mock_object(db, 'share_replica_update')
        request_spec = fakes.fake_replica_request_spec()
        replica_id = request_spec.get('share_instance_properties').get('id')
        expected_updates = {
            'status': constants.STATUS_ERROR,
            'replica_state': constants.STATUS_ERROR,
        }
        with mock.patch.object(
                self.manager.driver, 'schedule_create_replica',
                mock.Mock(side_effect=self.raise_no_valid_host)):

            retval = self.manager.create_share_replica(
                self.context, request_spec=request_spec, filter_properties={})

            self.assertIsNone(retval)
            db_update.assert_called_once_with(self.context, replica_id,
                                              expected_updates)

    def test_create_share_replica(self):
        """Test happy path for create_share_replica."""
        db_update = self.mock_object(db, 'share_replica_update')
        mock_scheduler_driver_call = self.mock_object(
            self.manager.driver, 'schedule_create_replica')
        request_spec = fakes.fake_replica_request_spec()

        retval = self.manager.create_share_replica(self.context,
                                                   request_spec=request_spec,
                                                   filter_properties={})

        mock_scheduler_driver_call.assert_called_once_with(
            self.context, request_spec, {})
        self.assertFalse(db_update.called)
        self.assertIsNone(retval)
Beispiel #17
0
class MessageFieldTest(test.TestCase):
    @ddt.data(message_field.Action, message_field.Detail)
    def test_unique_ids(self, cls):
        """Assert that no action or detail id is duplicated."""
        ids = [name[0] for name in cls.ALL]
        self.assertEqual(len(ids), len(set(ids)))

    @ddt.data({
        'id': '001',
        'content': 'allocate host'
    }, {
        'id': 'invalid',
        'content': None
    })
    @ddt.unpack
    def test_translate_action(self, id, content):
        result = message_field.translate_action(id)
        if content is None:
            content = 'unknown action'
        self.assertEqual(content, result)

    @ddt.data({
        'id': '001',
        'content': 'An unknown error occurred.'
    }, {
        'id':
        '002',
        'content':
        'No storage could be allocated for this share '
        'request. Trying again with a different size or '
        'share type may succeed.'
    }, {
        'id': 'invalid',
        'content': None
    })
    @ddt.unpack
    def test_translate_detail(self, id, content):
        result = message_field.translate_detail(id)
        if content is None:
            content = 'An unknown error occurred.'
        self.assertEqual(content, result)

    @ddt.data(
        {
            'exception': exception.NoValidHost(reason='fake reason'),
            'detail': '',
            'expected': '002'
        }, {
            'exception':
            exception.NoValidHost(
                detail_data={'last_filter': 'CapacityFilter'},
                reason='fake reason'),
            'detail':
            '',
            'expected':
            '009'
        }, {
            'exception':
            exception.NoValidHost(detail_data={'last_filter': 'FakeFilter'},
                                  reason='fake reason'),
            'detail':
            '',
            'expected':
            '002'
        }, {
            'exception': None,
            'detail': message_field.Detail.NO_VALID_HOST,
            'expected': '002'
        })
    @ddt.unpack
    def test_translate_detail_id(self, exception, detail, expected):
        result = message_field.translate_detail_id(exception, detail)
        self.assertEqual(expected, result)