Example #1
0
def cancel(order_id: ObjectId, user: dict):
    order = Orders.get(order_id)
    if order is None:
        raise errors.NotFound()

    Orders().cancel(order_id)
    send_order_failed_email(order_id)

    return jsonify({"_id": order_id})
Example #2
0
def run_periodic_tasks():
    logger.info("running periodic tasks !!")

    # manage auto-images
    logger.info("managing auto-images")
    check_autoimages()

    # timeout orders based on status

    # orders cant stay in creation for more than 12h
    # orders in downloading/writing cant be slower than 4Mb/s
    # now = datetime.datetime.now()
    # min_bps = int(humanfriendly.parse_size("4MiB") / 8)

    # for morder in Orders().find(
    #     {"status": {"$in": [Orders().creating, Orders.downloading, Orders.writing]}},
    #     {"_id": 1},
    # ):
    #     order = Orders().get_with_tasks(morder["_id"])
    #     ls = order["statuses"][-1]

    #     # prepare expired dt based on status
    #     if ls["status"] == Orders().creating:
    #         task = CreatorTasks().get(order["tasks"]["create"])
    #     elif ls["status"] in (Orders.downloading, Orders.writing):
    #         size = humanfriendly.parse_size(order["config"]["size"])
    #         expired = now - datetime.timedelta(seconds=int(size / min_bps))
    #         if ls["status"] == Orders.downloading:
    #             task_cls, task_id = DownloaderTasks, order["tasks"]["download"]
    #         else:
    #             task_cls, task_id = WriterTasks, order["tasks"]["write"]
    #     else:
    #         # last status not in-progress
    #         continue

    #     # compare last update with expiry datetime
    #     if ls["on"] > expired:
    #         continue

    #     # timeout task
    #     task_cls().update_status(task_id=task_id, status=task_cls.timedout)

    #     # timeout order
    #     task_cls().cascade_status(task_id=task_id, status=task_cls.timedout)

    #     # notify failure
    #     send_order_failed_email(order["_id"])  # TODO: forward to task/order mgmt

    logger.info("timing out expired orders")
    for task_cls, task in Tasks.all_inprogress():
        task_id = task["_id"]
        ls = task["statuses"][-1]

        if not is_expired(ls["status"], ls["on"], task_cls.get_size(task_id)):
            logger.info("skipping non-expired task #{}".format(task_id))
            continue

        logger.info("timing out task #{}".format(task_id))

        order = Orders().get_with_tasks(task["order"])

        # timeout task
        task_cls.update_status(task_id=task_id, status=Tasks.timedout)

        # if write, cancel peers
        if ls["status"] in (Tasks.wiping_sdcard, Tasks.writing):
            for peer in order["tasks"]["write"]:
                if peer["_id"] == task_id:
                    continue
                task_cls.update_status(task_id=peer["_id"], status=Tasks.canceled)

        # cascade
        task_cls.cascade_status(task_id=task_id, task_status=task_cls.timedout)

        # notify
        send_order_failed_email(order["_id"])  # TODO: forward to task/order mgmt

    logger.info("removing expired donwload files")
    now = datetime.datetime.now()

    for order in Orders.all_pending_expiry():
        ls = order["statuses"][-1]

        if not ls["status"] == Orders.pending_expiry:
            continue  # wrong timing

        if not order["sd_card"]["expiration"] < now:
            continue  # expiration not reached

        logger.info("Order #{} has reach expiration.".format(order["_id"]))
        Orders().update_status(order["_id"], Orders.expired)
Example #3
0
def update_status(task_id: ObjectId, task_type: str, user: dict):
    task_cls = tasks_cls_for(task_type)
    task = task_cls().get(task_id)
    if task is None:
        raise errors.NotFound()

    request_json = request.get_json()
    # try:
    #     request_json = request.get_json()
    #     validate(request_json, Orders().schema)
    # except ValidationError as error:
    #     raise errors.BadRequest(error.message)

    # update task status
    status = request_json.get("status")
    task_cls.update_status(
        task_id,
        status=request_json.get("status"),
        payload=request_json.get("log"),
        extra_update=request_json.get("extra"),
    )

    # update order status based on this task
    task_cls.cascade_status(task_id, request_json.get("status"))

    # send email if appropriate
    order_id = task["order"]

    # create task uploaded image
    if status == Tasks.uploaded_public:
        order = Orders().get(order_id)
        # set expiration date
        expiration = datetime.datetime.now() + datetime.timedelta(
            days=order["sd_card"]["duration"])
        Orders().update(order_id, {"sd_card.expiration": expiration})
        send_image_uploaded_public_email(order_id)
    elif status == Tasks.uploaded:
        send_image_uploaded_email(order_id)

        # create DownloadTask
        Orders().create_downloader_task(
            order_id,
            {
                "fname": task.get("image", {}).get("fname"),
                "size": task.get("image", {}).get("size"),
                "checksum": task.get("image", {}).get("checksum"),
            },
        )

    # download task downloaded image
    elif status == Tasks.downloaded:
        # create WriterTask(s)
        Orders().create_writer_tasks(order_id)

    # write task was registered
    elif status == Tasks.waiting_for_card:
        # send email to insert card
        send_insert_card_email(order_id, task_id)

    # write task started writing
    elif status == Tasks.writing:
        send_image_writing_email(order_id, task_id)

    # write task completed
    elif status == Tasks.written:
        send_image_written_email(order_id, task_id)

        order = Orders().get_with_tasks(order_id)
        # all write tasks are marked as written
        if not [
                1 for wt in order["tasks"]["write"]
                if wt["status"] != Tasks.written
        ]:
            Orders().update_status(order_id, Orders.pending_shipment)

            send_order_pending_shipment_email(order_id)

            # find matching download task and mark it for file removal
            DownloaderTasks().update_status(
                task_id=order["tasks"]["download"]["_id"],
                status=Tasks.pending_image_removal,
            )

    elif status in Tasks.FAILED_STATUSES:
        send_order_failed_email(order_id)

    return jsonify({"_id": task_id})