'Permit admins to evacuate a server from a failed host
to a new one.'

@extensions.expected_errors((400, 404, 409))
@wsgi.action('evacuate')
@validation.schema(evacuate.evacuate, '2.0', '2.13')
@validation.schema(evacuate.evacuate_v214, '2.14', '2.28')
@validation.schema(evacuate.evacuate_v2_29, '2.29')
def _evacuate(self, req, id, body):

    context = req.environ['nova.context']
    instance = common.get_instance(self.compute_api, context, id)
    context.can(evac_policies.BASE_POLICY_NAME, target={'user_id': instance.user_id, 'project_id': instance.project_id})
    evacuate_body = body['evacuate']
    host = evacuate_body.get('host')
    force = None
    on_shared_storage = self._get_on_shared_storage(req, evacuate_body)
    if api_version_request.is_supported(req, min_version='2.29'):
        force = body['evacuate'].get('force', False)
        force = strutils.bool_from_string(force, strict=True)
        if ((force is True) and (not host)):
            message = _("Can't    force    to    a    non-provided    destination")
            raise exc.HTTPBadRequest(explanation=message)
    if api_version_request.is_supported(req, min_version='2.14'):
        password = self._get_password_v214(req, evacuate_body)
    else:
        password = self._get_password(req, evacuate_body, on_shared_storage)
    if (host is not None):
        try:
            self.host_api.service_get_by_compute_host(context, host)
        except (exception.ComputeHostNotFound, exception.HostMappingNotFound):
            msg = (_('Compute    host    %s    not    found.') % host)
            raise exc.HTTPNotFound(explanation=msg)
    if (instance.host == host):
        msg = _("The    target    host    can't    be    the    same    one.")
        raise exc.HTTPBadRequest(explanation=msg)
    try:
        self.compute_api.evacuate(context, instance, host, on_shared_storage, password, force)
    except exception.InstanceUnknownCell as e:
        raise exc.HTTPNotFound(explanation=e.format_message())
    except exception.InstanceInvalidState as state_error:
        common.raise_http_conflict_for_instance_invalid_state(state_error, 'evacuate', id)
    except exception.ComputeServiceInUse as e:
        raise exc.HTTPBadRequest(explanation=e.format_message())
    if ((not api_version_request.is_supported(req, min_version='2.14')) and CONF.api.enable_instance_password):
        return {'adminPass': password}
    else:
        return None
