From e59d8bf9a47d7b54c91d65cf0e0f1893c231b131 Mon Sep 17 00:00:00 2001 From: Sam Welborn Date: Tue, 5 May 2026 15:46:38 -0400 Subject: [PATCH 1/2] passthrough all custom attributes we should allow for any arbitrary custom attributes, this will raise a ValidationError. in the next commit we will catch the validation error and throw a 422 --- app/s3df/compute_adapter.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/s3df/compute_adapter.py b/app/s3df/compute_adapter.py index 28df2e55..9dc2aba2 100644 --- a/app/s3df/compute_adapter.py +++ b/app/s3df/compute_adapter.py @@ -270,6 +270,8 @@ async def submit_job( partition = partition or os.environ.get("SLURM_DEFAULT_PARTITION") account = account or os.environ.get("SLURM_DEFAULT_ACCOUNT") + custom_attributes = job_spec.attributes.custom_attributes if job_spec.attributes else {} + slurm_job = SlurmV0041PostJobSubmitRequestJob( nodes=str(node_count), time_limit=SlurmV0041PostJobSubmitRequestJobsInnerTimeLimit(set=True, number=duration_mins), @@ -281,12 +283,9 @@ async def submit_job( current_working_directory=cwd, standard_output=stdout, standard_error=stderr, + **custom_attributes ) - # Job array support: e.g. custom_attributes={"array": "0-19"} - if job_spec.attributes and "array" in job_spec.attributes.custom_attributes: - slurm_job.array = job_spec.attributes.custom_attributes["array"] - req = SlurmV0041PostJobSubmitRequest(job=slurm_job) try: From e67226c4993686d8f3f99ea1d1539c0c92cc1aa1 Mon Sep 17 00:00:00 2001 From: Sam Welborn Date: Tue, 5 May 2026 15:56:53 -0400 Subject: [PATCH 2/2] raise 422 if custom attrs don't jibe with slurm model --- app/s3df/compute_adapter.py | 47 ++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/app/s3df/compute_adapter.py b/app/s3df/compute_adapter.py index 9dc2aba2..47978cd0 100644 --- a/app/s3df/compute_adapter.py +++ b/app/s3df/compute_adapter.py @@ -35,7 +35,8 @@ from slurmrestd_client.models.slurm_v0041_post_job_submit_request_jobs_inner_time_limit import ( SlurmV0041PostJobSubmitRequestJobsInnerTimeLimit, ) -from fastapi import Response +from fastapi import HTTPException, Response +from pydantic import ConfigDict, ValidationError from ..routers.compute import models as compute_models from ..types.user import User @@ -43,6 +44,18 @@ logger = logging.getLogger(__name__) + +class SlurmV0041PostJobSubmitRequestJobStrict(SlurmV0041PostJobSubmitRequestJob): + # we reject unexpected fields to enable raising ValidationError + # TODO: we could see if the autogeneration could be configured to make + # this strict by default + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + extra="forbid", + ) + # --------------------------------------------------------------------------- # Slurm → IRI state mapping # --------------------------------------------------------------------------- @@ -272,19 +285,25 @@ async def submit_job( custom_attributes = job_spec.attributes.custom_attributes if job_spec.attributes else {} - slurm_job = SlurmV0041PostJobSubmitRequestJob( - nodes=str(node_count), - time_limit=SlurmV0041PostJobSubmitRequestJobsInnerTimeLimit(set=True, number=duration_mins), - name=name, - script=executable, - partition=partition, - account=account, - environment=environment, - current_working_directory=cwd, - standard_output=stdout, - standard_error=stderr, - **custom_attributes - ) + try: + slurm_job = SlurmV0041PostJobSubmitRequestJobStrict( + nodes=str(node_count), + time_limit=SlurmV0041PostJobSubmitRequestJobsInnerTimeLimit(set=True, number=duration_mins), + name=name, + script=executable, + partition=partition, + account=account, + environment=environment, + current_working_directory=cwd, + standard_output=stdout, + standard_error=stderr, + **custom_attributes + ) + except (ValidationError, TypeError) as exc: + raise HTTPException( + status_code=422, + detail=f"Invalid job submission parameters: {exc}", + ) from exc req = SlurmV0041PostJobSubmitRequest(job=slurm_job)