def process(self):
        """call transform and error if needed"""
        transformed = self._transform()
        delivered = self.ftp.unzip_and_deliver(settings.FTP_FOLDER,
                                               transformed)

        if not delivered:
            self.logger.error("Failed to deliver zip to ftp")
            raise RetryableError("Failed to deliver zip to ftp")
        return
    def process(self):
        transformed = self._transform()

        delivered = self.ftp.unzip_and_deliver(
            self._get_ftp_folder(self.survey), transformed)

        if not delivered:
            self.logger.error("Failed to deliver zip to ftp")
            raise RetryableError("Failed to deliver zip to ftp")

        return
def remote_call(url, json=None):
    service = service_name(url)

    try:
        logger.info("Calling service", request_url=url, service=service)
        response = None

        if json:
            response = session.post(url, json=json)
        else:
            response = session.get(url)

        return response

    except MaxRetryError:
        logger.error("Max retries exceeded (5)", request_url=url)
        raise RetryableError("Max retries exceeded")
    except ConnectionError:
        logger.error("Connection error", request_url=url)
        raise RetryableError("Connection error")
    def _send_for_anti_virus_check(self, filename, contents):
        url = settings.ANTI_VIRUS_BASE_URL
        headers = {
            "filename": filename,
            "rule": settings.ANTI_VIRUS_RULE,
            "user_agent": settings.ANTI_VIRUS_USER_AGENT,
        }
        self._add_api_key(headers)

        self.bound_logger.info("Sending for A/V scan", url=url)
        try:
            response = self.session.post(url=url,
                                         headers=headers,
                                         data=contents)
        except requests.RequestException:
            self.bound_logger.exception(
                "Error sending request to Anti-virus server")
            raise RetryableError()

        self._check_av_response(response)

        self.bound_logger.info("Response received", response=response.text)
        try:
            result = response.json()
        except (ValueError, TypeError):
            self.bound_logger.exception("Unable to decode A/V results")
            raise RetryableError()

        if result.get("err"):
            self.bound_logger.error("Unable to send file for anti virus scan",
                                    error=result.get("err"))
            self.bound_logger.info("Waiting before attempting again")
            time.sleep(settings.ANTI_VIRUS_WAIT_TIME)
            self.bound_logger.info("Return message to rabbit")
            raise RetryableError()

        data_id = result.get("data_id")
        self.bound_logger.info("File sent successfully for anti virus scan",
                               data_id=data_id)
        return data_id
 def _send_to_ftp(self, decoded_contents, file_path, file_name, tx_id):
     try:
         self._ftp.deliver_binary(file_path, file_name, decoded_contents)
         logger.debug("Delivered to FTP server",
                      tx_id=tx_id,
                      file_path=file_path,
                      file_name=file_name)
     except IOError as e:
         logger.error("Unable to deliver to the FTP server",
                      action="nack",
                      exception=str(e),
                      tx_id=tx_id)
         raise RetryableError()
    def send_for_av_scan(self, payload):
        """Sends the file to the anti-virus service to be scanned.
        This function is blocking as it repeatedly checks every few seconds (as defined by
        the ANTI_VIRUS_WAIT_TIME variable) to see if the scan is done, only proceeding once it's
        complete.

        Raises a QuarantinableError if the file is deemed not safe.
        """
        self.bound_logger.info("Sending for AV check",
                               filename=payload.file_name)
        data_id = self._send_for_anti_virus_check(payload.file_name,
                                                  payload.decoded_contents)
        self.bound_logger.info("Sent for A/V check", data_id=data_id)

        # this loop will block the consumer until the anti virus finishes
        # in a future iteration we should make this asynchronous so that we
        # can process multiple messages
        attempts = 0
        while attempts <= settings.ANTI_VIRUS_MAX_ATTEMPTS:
            attempts += 1
            results = self._get_anti_virus_result(data_id)
            if not results.ready:
                self.bound_logger.info("Results not ready",
                                       attempts=attempts,
                                       case_id=payload.case_id,
                                       filename=payload.file_name)
                time.sleep(settings.ANTI_VIRUS_WAIT_TIME)
            elif not results.safe:
                self._write_scan_report(results, payload.file_name)
                self.bound_logger.error("Unsafe file detected",
                                        case_id=payload.case_id,
                                        filename=payload.file_name)
                raise QuarantinableError()
            else:
                self.bound_logger.info(
                    "File has been virus checked and confirmed safe",
                    case_id=payload.case_id,
                    filename=payload.file_name)
                return True

        # out of attempts raise retryable error to force the response back to the queue.
        self.bound_logger.error("Unable to get results of Anti-virus scan",
                                attempts=attempts,
                                case_id=payload.case_id,
                                filename=payload.file_name)
        raise RetryableError()
 def _get_sequence_number():
     """return the sequence number else raise a Retryable Error"""
     sequence_no = get_sequence_no()
     if sequence_no is None:
         raise RetryableError("Failed to get sequence number")
     return sequence_no