def _wf_module_delete_secret_and_build_delta(
        workflow: Workflow, wf_module: WfModule,
        param: str) -> Optional[clientside.Update]:
    """
    Write a new secret (or `None`) to `wf_module`, or raise.

    Return a `clientside.Update`, or `None` if the database is not modified.

    Raise Workflow.DoesNotExist if the Workflow was deleted.
    """
    with workflow.cooperative_lock():  # raises Workflow.DoesNotExist
        try:
            wf_module.refresh_from_db()
        except WfModule.DoesNotExist:
            return None  # no-op

        if wf_module.secrets.get(param) is None:
            return None  # no-op

        wf_module.secrets = dict(wf_module.secrets)  # shallow copy
        del wf_module.secrets[param]
        wf_module.save(update_fields=["secrets"])

        return clientside.Update(steps={
            wf_module.id:
            clientside.StepUpdate(secrets=wf_module.secret_metadata)
        })
Exemple #2
0
def _wf_module_delete_secret_and_build_delta(
    workflow: Workflow, wf_module: WfModule, param: str
) -> Optional[Dict[str, Any]]:
    """
    Write a new secret (or `None`) to `wf_module`, or raise.

    Return a "delta" for websockets.ws_client_send_delta_async(), or `None` if
    the database has not been modified.

    Raise Workflow.DoesNotExist if the Workflow was deleted.
    """
    with workflow.cooperative_lock():  # raises Workflow.DoesNotExist
        try:
            wf_module.refresh_from_db()
        except WfModule.DoesNotExist:
            return None  # no-op

        if wf_module.secrets.get(param) is None:
            return None  # no-op

        wf_module.secrets = dict(wf_module.secrets)  # shallow copy
        del wf_module.secrets[param]
        wf_module.save(update_fields=["secrets"])

        return {
            "updateWfModules": {
                str(wf_module.id): {"secrets": wf_module.secret_metadata}
            }
        }
Exemple #3
0
def wfmodule_render(request: HttpRequest, wf_module: WfModule, format=None):
    # Get first and last row from query parameters, or default to all if not
    # specified
    try:
        startrow = int_or_none(request.GET.get("startrow"))
        endrow = int_or_none(request.GET.get("endrow"))
    except ValueError:
        return Response(
            {"message": "bad row number", "status_code": 400},
            status=status.HTTP_400_BAD_REQUEST,
        )

    with wf_module.workflow.cooperative_lock():
        wf_module.refresh_from_db()
        cached_result = wf_module.cached_render_result
        if cached_result is None:
            # assume we'll get another request after execute finishes
            return JsonResponse({"start_row": 0, "end_row": 0, "rows": []})

        try:
            startrow, endrow, records = _make_render_tuple(
                cached_result, startrow, endrow
            )
        except CorruptCacheError:
            # assume we'll get another request after execute finishes
            return JsonResponse({"start_row": 0, "end_row": 0, "rows": []})

        return JsonResponse({"start_row": startrow, "end_row": endrow, "rows": records})
def _do_finish_upload(
    workflow: Workflow, wf_module: WfModule, uuid: uuidgen.UUID, filename: str
) -> clientside.Update:
    with workflow.cooperative_lock():
        wf_module.refresh_from_db()
        try:
            in_progress_upload = wf_module.in_progress_uploads.get(
                id=uuid, is_completed=False
            )
        except InProgressUpload.DoesNotExist:
            raise HandlerError(
                "BadRequest: key is not being uploaded for this WfModule right now. "
                "(Even a valid key becomes invalid after you create, finish or abort "
                "an upload on its WfModule.)"
            )
        try:
            in_progress_upload.convert_to_uploaded_file(filename)
        except FileNotFoundError:
            raise HandlerError(
                "BadRequest: file not found. "
                "You must upload the file before calling finish_upload."
            )
        return clientside.Update(
            steps={
                wf_module.id: clientside.StepUpdate(
                    files=wf_module.to_clientside().files
                )
            }
        )
def _wf_module_set_secret_and_build_delta(
        workflow: Workflow, wf_module: WfModule, param: str,
        secret: str) -> Optional[clientside.Update]:
    """
    Write a new secret to `wf_module`, or raise.

    Return a `clientside.Update`, or `None` if the database is not modified.

    Raise Workflow.DoesNotExist if the Workflow was deleted.
    """
    with workflow.cooperative_lock():  # raises Workflow.DoesNotExist
        try:
            wf_module.refresh_from_db()
        except WfModule.DoesNotExist:
            return None  # no-op

        if wf_module.secrets.get(param, {}).get("secret") == secret:
            return None  # no-op

        try:
            module_zipfile = MODULE_REGISTRY.latest(wf_module.module_id_name)
        except KeyError:
            raise HandlerError(
                f"BadRequest: ModuleZipfile {wf_module.module_id_name} does not exist"
            )
        module_spec = module_zipfile.get_spec()
        if not any(p.type == "secret" and p.secret_logic.provider == "string"
                   for p in module_spec.param_fields):
            raise HandlerError(
                f"BadRequest: param is not a secret string parameter")

        created_at = timezone.now()
        created_at_str = (
            created_at.strftime("%Y-%m-%dT%H:%M:%S") + "." +
            created_at.strftime("%f")[0:3]  # milliseconds
            + "Z")

        wf_module.secrets = {
            **wf_module.secrets,
            param: {
                "name": created_at_str,
                "secret": secret
            },
        }
        wf_module.save(update_fields=["secrets"])

        return clientside.Update(steps={
            wf_module.id:
            clientside.StepUpdate(secrets=wf_module.secret_metadata)
        })
Exemple #6
0
def _wf_module_set_secret_and_build_delta(
    workflow: Workflow, wf_module: WfModule, param: str, secret: str
) -> Optional[Dict[str, Any]]:
    """
    Write a new secret to `wf_module`, or raise.

    Return a "delta" for websockets.ws_client_send_delta_async(), or `None` if
    the database is not modified.

    Raise Workflow.DoesNotExist if the Workflow was deleted.
    """
    with workflow.cooperative_lock():  # raises Workflow.DoesNotExist
        try:
            wf_module.refresh_from_db()
        except WfModule.DoesNotExist:
            return None  # no-op

        if wf_module.secrets.get(param, {}).get("secret") == secret:
            return None  # no-op

        module_version = wf_module.module_version
        if module_version is None:
            raise HandlerError(f"BadRequest: ModuleVersion does not exist")
        if not any(
            p.type == "secret" and p.secret_logic.provider == "string"
            for p in module_version.param_fields
        ):
            raise HandlerError(f"BadRequest: param is not a secret string parameter")

        created_at = timezone.now()
        created_at_str = (
            created_at.strftime("%Y-%m-%dT%H:%M:%S")
            + "."
            + created_at.strftime("%f")[0:3]  # milliseconds
            + "Z"
        )

        wf_module.secrets = {
            **wf_module.secrets,
            param: {"name": created_at_str, "secret": secret},
        }
        wf_module.save(update_fields=["secrets"])

        return {
            "updateWfModules": {
                str(wf_module.id): {"secrets": wf_module.secret_metadata}
            }
        }
Exemple #7
0
def _locked_wf_module(workflow_id: int, wf_module: WfModule):
    """
    Refresh wf_module from database and yield with workflow lock.

    Raise Workflow.DoesNotExist or WfModule.DoesNotExist in the event of a
    race. (Even soft-deleted WfModule or Tab raises WfModule.DoesNotExist,
    to simulate hard deletion -- because sooner or later soft-delete won't be
    a thing any more.)
    """
    # raise Workflow.DoesNotExist
    with Workflow.lookup_and_cooperative_lock(id=workflow_id):
        # raise WfModule.DoesNotExist
        wf_module.refresh_from_db()
        if wf_module.is_deleted or wf_module.tab.is_deleted:
            raise WfModule.DoesNotExist("soft-deleted")
        yield
def wfmodule_render(request: HttpRequest, wf_module: WfModule, format=None):
    # Get first and last row from query parameters, or default to all if not
    # specified
    try:
        startrow = int_or_none(request.GET.get("startrow"))
        endrow = int_or_none(request.GET.get("endrow"))
    except ValueError:
        return Response(
            {
                "message": "bad row number",
                "status_code": 400
            },
            status=status.HTTP_400_BAD_REQUEST,
        )

    with wf_module.workflow.cooperative_lock():
        wf_module.refresh_from_db()
        cached_result = wf_module.cached_render_result
        if cached_result is None:
            # assume we'll get another request after execute finishes
            return JsonResponse({"start_row": 0, "end_row": 0, "rows": []})

        try:
            startrow, endrow, record_json = _make_render_tuple(
                cached_result, startrow, endrow)
        except CorruptCacheError:
            # assume we'll get another request after execute finishes
            return JsonResponse({"start_row": 0, "end_row": 0, "rows": []})

    data = '{"start_row":%d,"end_row":%d,"rows":%s}' % (startrow, endrow,
                                                        record_json)
    response = HttpResponse(data.encode("utf-8"),
                            content_type="application/json",
                            charset="utf-8")
    add_never_cache_headers(response)
    return response
def _do_create_upload(workflow: Workflow, wf_module: WfModule) -> Dict[str, Any]:
    with workflow.cooperative_lock():
        wf_module.refresh_from_db()
        in_progress_upload = wf_module.in_progress_uploads.create()
        return in_progress_upload.generate_upload_parameters()