Ejemplo n.º 1
0
def acquire_get_status_and_save(acquisition_request, capability_name, action_name, group_name,
                                data_acq_client, data_store_client, verbose):
    """Helper function which issues an acquisition request and checks that its data is saved to the data store, and the
    GetStatus RPC eventually respond with a status "complete".

    Args:
        acquisition_request (AcquisitionRequestList): The acquisition request proto message to send to the AcquireData RPC.
        capability_name (string): The name of the data capability being acquired.
        action_name (string): The action name for the acquisition request's CaptureActionId.
        group_name (string): The group name for the acquisition request's CaptureActionId.
        data_acq_client (DataAcquisitionClient): The client for the data acquisition service running on robot.
        data_store_client (DataAcquisitionStoreClient): The client for the data acquisition store service running on robot.
        verbose (boolean): Print additional logging information on failure.

    Returns:
        A boolean indicating that the acquisition request received a "complete" status for the GetStatus RPC and
        an action id for the acquisition can be found in the data store.
    """
    # Make a request for this data capability and check that it completes successfully.
    acquire_success, acquired_request_id = acquire_data_and_check_errors(
        acquisition_request, data_acq_client, capability_name, action_name, group_name, verbose)
    if not acquire_success:
        # Exit early if the AcquireData RPC did not succeed and did not return a request_id.
        return False
    success = monitor_status_until_complete_or_failed(acquired_request_id, data_acq_client,
                                                      capability_name, action_name, verbose)

    if success:
        # If the GetStatus responds with "Complete", then check the data store for the action id.
        action_id = data_acquisition_pb2.CaptureActionId(action_name=action_name,
                                                         group_name=group_name)
        query_params = data_acquisition_store_pb2.DataQueryParams(
            action_ids=data_acquisition_store_pb2.ActionIdQuery(action_ids=[action_id]))
        try:
            saved_capture_actions = data_store_client.list_capture_actions(query_params)
            if len(saved_capture_actions) == 0:
                # Nothing saved with a matching action and group name!
                _LOGGER.error(
                    "The request %s for data '%s' with action_name '%s' did NOT save to the data "
                    "acquisition store or returned prematurely with a STATUS_COMPLETE in the GetStatus RPC.",
                    acquired_request_id, capability_name, action_name)
                if verbose:
                    _LOGGER.info("ListCaptureAction RPC's query parameters: ", query_params)
                return False
        except ResponseError as err:
            _LOGGER.error(
                "Exception raised when checking if request %s for data '%s' with action_name '%s' was "
                "saved in the data acquisition store.", request_id, capability_name, action_name)
            if verbose:
                log_debug_information(err)
            return False
    else:
        # The GetStatus checks failed in some way.
        return False

    # The acquisition request went through, the GetStatus RPC responded with "status complete" and the data was
    # successfully found in the data store service.
    return True
Ejemplo n.º 2
0
def monitor_status_until_complete_or_failed(request_id, client, capability_name, action_name,
                                            verbose):
    """Helper status that monitors the status (using the GetStatus RPC) for the acquisition request until it
    completes, fails, or times out.

    Args:
        request_id (int): The request_id for the acquisition request (returned by the AcquireData RPC).
        client (DataAcquisitionClient): The client for the data acquisition service running on robot.
        capability_name (string): The data source name being acquired.
        action_name (string): The action name from the AcquireData RPC being monitored.
        verbose (boolean): Print additional logging information on failure.

    Returns:
        A boolean indicating that the GetStatus RPC eventually received a "complete" status.
    """
    start_time = time.time()
    should_continue = time.time() - start_time < kMonitorStatusTimeoutSecs
    while should_continue:
        get_status_response = None
        try:
            get_status_response = client.get_status(request_id)
        except ResponseError as err:
            _LOGGER.error(
                "Exception raised when monitoring the status of request %s for data '%s' with action_name '%s'.",
                request_id, capability_name, action_name)
            if verbose:
                log_debug_information(err)
            return False

        if get_status_response.status in kAcquisitionSucceededStatuses:
            return True
        elif get_status_response.status in kAcquisitionFailedStatuses:
            _LOGGER.error(
                "Request %s for data '%s' with action_name '%s' failed the GetStatus RPC with status %s.",
                request_id, capability_name, action_name,
                data_acquisition_pb2.GetStatusResponse.Status.Name(get_status_response.status))
            if verbose:
                _LOGGER.info("The full GetStatus response: %s", get_status_response)
            return False
        elif get_status_response.status in kAcquisitionContinuesStatuses:
            # Sleep briefly, then re-attempt to make a GetStatus RPC to see if the acquisition has completed.
            time.sleep(0.2)
            should_continue = time.time() - start_time < kMonitorStatusTimeoutSecs
            continue
        else:
            _LOGGER.error(
                "Unexpected status %s when monitoring request %s for data '%s' with action_name '%s'.",
                data_acquisition_pb2.GetStatusResponse.Status.Name(get_status_response.status),
                request_id, capability_name, action_name)
            if verbose:
                _LOGGER.info("The full GetStatus response: %s", get_status_response)
            return False

    _LOGGER.warning(
        "No result to the GetStatus RPC within %s seconds for request %s of data '%s' with action_name '%s'.",
        kMonitorStatusTimeoutSecs, request_id, capability_name, action_name)
    return True
Ejemplo n.º 3
0
def acquire_data_and_check_errors(acquisition_request, data_acq_client,
                                  capability_name, action_name, group_name,
                                  verbose):
    """Helper function which makes the acquisition request for this data source and checks for errors.

    Args:
        acquisition_request (AcquisitionRequestList): The acquisition request for the capability_name.
        data_acq_client (DataAcquisitionClient): The client for the on-robot data acquisition service.
        capability_name (string): The data source name being acquired.
        action_name (string): The action name for saving in the CaptureActionId of the AcquireData request.
        group_name (string): The group name for saving in the CaptureActionId of the AcquireData request.
        verbose (boolean): Print additional logging information on failure.

    Returns:
        A tuple consisting of 1) a boolean indicating that the AcquireData RPC completed without any errors,
        and 2) an integer representing the request_id for the acquisition request. The request_id will be None
        if the AcquireData RPC fails.
    """
    acquire_data_request_id = None
    try:
        # Issue the AcquireData RPC to the on-robot data acquisition service.
        acquire_data_request_id = data_acq_client.acquire_data(
            acquisition_request, action_name, group_name)
    except InvalidRequestError as err:
        _LOGGER.error(
            "The AcquireData RPC to the data-acquisition service for %s was invalid: %s",
            capability_name, err.error_message)
        if verbose:
            _LOGGER.info(
                "The capture action ID associated with the request: %s",
                data_acquisition_pb2.CaptureActionId(action_name=action_name,
                                                     group_name=group_name))
            log_debug_information(err, acquisition_request)
        return False, acquire_data_request_id
    except ResponseError as err:
        _LOGGER.error(
            "Exception raised when testing the AcquireData RPC to the data-acquisition service for %s: %s",
            capability_name, err)
        if verbose:
            _LOGGER.info(
                "The capture action ID associated with the request: %s",
                data_acquisition_pb2.CaptureActionId(action_name=action_name,
                                                     group_name=group_name))
            log_debug_information(err, acquisition_request)
        return False, acquire_data_request_id
    return True, acquire_data_request_id
Ejemplo n.º 4
0
def cancel_request_and_monitor_status(request_id, client, capability_name,
                                      action_name, verbose):
    """Helper status that monitors the status (using the GetStatus RPC) for the acquisition request after it
    is cancelled until it recieves a "cancellation complete" status, or fails and times out.

    Args:
        request_id (int): The request_id for the acquisition request (returned by the AcquireData RPC).
        client (DataAcquisitionClient): The client for the data acquisition service running on robot.
        capability_name (string): The data source name being acquired.
        action_name (string): The action name from the AcquireData RPC being monitored.
        verbose (boolean): Print additional logging information on failure.

    Returns:
        A boolean indicating that the GetStatus RPC eventually recieved a "cancellation complete" status.
    """
    try:
        cancel_res = client.cancel_acquisition(request_id)
    except CancellationFailedError as err:
        _LOGGER.error(
            "The CancelAcquisition RPC for request %s of data '%s' with action_name '%s' failed. "
            "Check that the CancelAcquisition RPC is implemented and working in the plugin service.",
            request_id, capability_name, action_name)
        if verbose:
            log_debug_information(err)
        return False
    except RequestIdDoesNotExistError as err:
        _LOGGER.error(
            "The request ID %s for data '%s' with action_name '%s' does not exist. Something may have "
            "gone wrong with the AcquireData request or the id was not saved/deleted by the plugin service.",
            request_id, capability_name, action_name)
        if verbose:
            log_debug_information(err)
        return False
    except ResponseError as err:
        _LOGGER.error(
            "Exception raised when cancelling request %s for data '%s' with action_name '%s'.",
            request_id, capability_name, action_name)
        if verbose:
            log_debug_information(err)
        return False

    start_time = time.time()
    should_continue = time.time() - start_time < kMonitorStatusTimeoutSecs
    first_time_warning = True
    while should_continue:
        get_status_response = None
        try:
            get_status_response = client.get_status(request_id)
        except ResponseError as err:
            _LOGGER.error(
                "Exception raised when monitoring the cancellation status of request %s for data '%s'"
                " with action_name '%s'.", request_id, capability_name,
                action_name)
            if verbose:
                log_debug_information(err)
            return False

        if get_status_response.status in kAcquisitionCancellationSucceededStatuses:
            return True
        elif get_status_response.status in kAcquisitionCancellationContinuesStatuses:
            # Sleep breifly, then re-attempt to make a GetStatus RPC to see if the acquisition has cancelled.
            time.sleep(0.2)
        elif get_status_response.status in kAcquisitionContinuesStatuses:
            # Warning that plugin did not update status to reflect that cancel rpc was recieved.
            if first_time_warning:
                _LOGGER.warning(
                    "The plugin did not update the status to reflect that a CancelAcquisition RPC was recieved. Try "
                    "setting the status as STATUS_CANCEL_IN_PROGRESS after responding to the RPC."
                )
                _LOGGER.info("Request %s for data '%s' with action_name '%s",
                             request_id, capability_name, action_name)
                if verbose:
                    _LOGGER.info(
                        "Request %s for data '%s' with action_name '%s",
                        request_id, capability_name, action_name)
                    _LOGGER.info("The full GetStatus response: %s",
                                 get_status_response)
                first_time_warning = False
            # Sleep breifly, then re-attempt to make a GetStatus RPC to see if the acquisition has cancelled.
            time.sleep(0.2)
        elif get_status_response.status in kAcquisitionCancellationFailedStatuses:
            # Cancellation-specific failure.
            _LOGGER.error(
                "The cancellation request %s for data '%s' with action_name '%s' failed the GetStatus "
                "RPC with status %s.", request_id, capability_name,
                action_name,
                data_acquisition_pb2.GetStatusResponse.Status.Name(
                    get_status_response.status))
            if verbose:
                _LOGGER.info("The full GetStatus response: %s",
                             get_status_response)
            return False
        elif get_status_response.status in kAcquisitionFailedStatuses:
            # Failed for reason other than cancellation failed statuses.
            _LOGGER.error(
                "The cancellation request %s for data '%s' with action_name '%s' failed the GetStatus RPC with status %s."
                "This is not an expected failure status after a CancelAcquisition RPC.",
                request_id, capability_name, action_name,
                data_acquisition_pb2.GetStatusResponse.Status.Name(
                    get_status_response.status))
            if verbose:
                _LOGGER.info("The full GetStatus response: %s",
                             get_status_response)
            return False
        else:
            _LOGGER.error(
                "Unexpected status %s when monitoring cancellation request %s for data '%s' with action_name '%s'.",
                data_acquisition_pb2.GetStatusResponse.Status.Name(
                    get_status_response.status), request_id, capability_name,
                action_name)
            if verbose:
                _LOGGER.info("The full GetStatus response: %s",
                             get_status_response)
            return False

        should_continue = time.time() - start_time < kMonitorStatusTimeoutSecs

    _LOGGER.warning(
        "Did not get a result for the GetStatus RPC within %s seconds for request %s of data '%s' with "
        "action_name '%s'.", kMonitorStatusTimeoutSecs, request_id,
        capability_name, action_name)
    return True
Ejemplo n.º 5
0
def request_image_and_save(image_sources, image_client, filepath, verbose=False):
    """Request the image sources in all possible formats and save the data.

    This makes GetImage RPCs for the image sources for each type of image format. The requests which
    respond without errors are then checked for completeness in the proto response, and saved.

    A warning message is printed if an image source cannot respond in a format that the tablet will
    be able to understand.

    Args:
        image_sources (List[string]): The image source names from the image service.
        image_client (ImageClient): The client for the image service being tested.
        filepath (string): A destination folder to save the images at.
        verbose (boolean): Print additional logging information on failure.

    Returns:
        Boolean indicating if the image sources could be successfully requested in one of the possible image
        formats and the image response is validated.
    """
    successful_request_found = False
    successful_tablet_request_found = False
    # Check that one of the formats requested by the tablet will work.
    for img_format in ALL_FORMATS:
        img_req = [
            build_image_request(source_name, image_format=img_format)
            for source_name in image_sources
        ]
        img_resps = None
        try:
            img_resps = image_client.get_image(img_req)
        except UnsupportedImageFormatRequestedError as err:
            _LOGGER.error("The image format %s is unsupported for image sources %s.",
                          image_pb2.Image.Format.Name(img_format), image_sources)
            if verbose:
                log_debug_information(err, img_req, strip_response=True)
            continue
        except ImageDataError as err:
            _LOGGER.error(
                "The image sources (%s) were unable to be captured and decoded in format %s.",
                image_sources, image_pb2.Image.Format.Name(img_format))
            if verbose:
                log_debug_information(err, img_req, strip_response=True)
            continue
        except UnknownImageSourceError as err:
            unknown_sources = []
            for img_resp in err.response.image_responses:
                if img_resp.status == image_pb2.ImageResponse.STATUS_UNKNOWN_CAMERA:
                    unknown_sources.append(img_resp.source.name)
            _LOGGER.error("The image sources %s are unknown by the image service.", unknown_sources)
            if verbose:
                log_debug_information(err, img_req, strip_response=True)
            continue
        except SourceDataError as err:
            _LOGGER.error("The image sources (%s) do not have image source information.",
                          image_sources)
            if verbose:
                log_debug_information(err, img_req, strip_response=True)
            continue
        except ResponseTooLargeError as err:
            _LOGGER.warning(
                "Note: the response for requesting image sources %s in format %s is too large and they cannot "
                "all be requested at once unless the ImageClient's grpc message limit is increased.",
                image_sources, image_pb2.Image.Format.Name(img_format))
            if verbose:
                log_debug_information(err, img_req, strip_response=True)
            # Exit out when the request is too large.
            return True

        # Check that the bare minimum required fields of the image response are populated.
        if len(img_resps) != len(img_req):
            # Found too many or too few image responses in a request for only one image.
            _LOGGER.warning(
                "The GetImageResponse RPC contains %d image responses, when %d images were requested.",
                len(img_resps), len(img_req))
            if verbose:
                _LOGGER.info("GetImage requests: %s", img_req)
                _LOGGER.info("GetImage response: %s",
                             [copy_image_response_and_strip_bytes(img) for img in img_resp])
            continue

        _LOGGER.info("Successfully saved image sources %s in format %s", image_sources,
                     image_pb2.Image.Format.Name(img_format))

        for img_data in img_resps:
            if not validate_image_response(img_data, img_req, img_format, verbose):
                # The image response did not succeed in the validation checks, therefore the format
                # requested does not completely work. Continue to the next potential image format
                # and attempt to request it.
                continue

        # All checks for the image response have succeeded for this image format!
        successful_request_found = True
        if img_format in TABLET_REQUIRED_IMAGE_FORMATS:
            successful_tablet_request_found = True

        # Save all the collect images.
        save_images_as_files(img_resps, filepath=filepath)

    if not successful_tablet_request_found:
        _LOGGER.warning(
            "The image sources %s did not respond successfully to a GetImage RPC with one of the "
            "known image formats (%s) used by the tablet. This means the images will NOT appear successfully "
            "on the tablet.", image_sources,
            [image_pb2.Image.Format.Name(f) for f in TABLET_REQUIRED_IMAGE_FORMATS])

    return successful_request_found