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) })
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} } }
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) })
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} } }
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()