feat: update apispec for polymorphic resource class definition - #1388
feat: update apispec for polymorphic resource class definition#1388SalimKayal wants to merge 49 commits into
Conversation
7dbc2f8 to
d76ebb5
Compare
225f912 to
0646568
Compare
Coverage Report for CI Build 31506944335Coverage at 85.878% (no base build to compare)Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
df18a6a to
964aeaf
Compare
| $ref: "#/components/schemas/NodeAffinityList" | ||
| quota_enforced: | ||
| $ref: "#/components/schemas/QuotaEnforced" | ||
| kind: |
There was a problem hiding this comment.
I don't understand why we repeat kind in the resource class when it cannot be different from the parent resource pool.
There was a problem hiding this comment.
it allows the conditional in the api spec. I hesitated a lot with this because datamodel code generator does not support this. I can change that if you think it's more trouble than otherwise
| then: | ||
| properties: | ||
| cpu: | ||
| $ref: "#/components/schemas/CpuInteger" |
There was a problem hiding this comment.
Why do we add this complexity in the API spec? I would rather have this handled by a math.floor() inside the remote session controller on the amalthea side than make a complex API spec.
There was a problem hiding this comment.
because floor of 0.5 is not what we want ? but again this can be validated elsewhere (i.e. in core.py)
There was a problem hiding this comment.
I mean, we can have:
cpu_int = max(math.floor(cpu), 1)There was a problem hiding this comment.
to have a minimum of 1 and then truncating if set to a non-whole value
SalimKayal
left a comment
There was a problem hiding this comment.
So basically all your remarks are linked to the kind in resource class. should I remove this and manage this aspect differently ?
| $ref: "#/components/schemas/NodeAffinityList" | ||
| quota_enforced: | ||
| $ref: "#/components/schemas/QuotaEnforced" | ||
| kind: |
There was a problem hiding this comment.
it allows the conditional in the api spec. I hesitated a lot with this because datamodel code generator does not support this. I can change that if you think it's more trouble than otherwise
| then: | ||
| properties: | ||
| cpu: | ||
| $ref: "#/components/schemas/CpuInteger" |
There was a problem hiding this comment.
because floor of 0.5 is not what we want ? but again this can be validated elsewhere (i.e. in core.py)
| $ref: "#/components/schemas/RemoteConfigurationFirecrestSystemName" | ||
| partition: | ||
| $ref: "#/components/schemas/RemoteConfigurationFirecrestPartition" | ||
| ignore_resource_class_values: |
There was a problem hiding this comment.
Would it make more sense to move this field to the resource class? It seems that all the classes in a remote HPC pool would set this to the same value.
There was a problem hiding this comment.
I wondered a bit about this. Here's why I went this way.
If we keep the resource pools/classes as is it works because the resource pool's values are used.
if we change the values in the resource class, it overrides the pool's defaults
this means that if we do not change anything in the configs it should still work, if we do we can have a single resource pool per firecrest api endpoint. i.e. CSCS Alps with Daint/Eiger/Bristen/Clariden Systems and debug/normal partitions. I can change that if you think it's poor design.
There was a problem hiding this comment.
I think it would be more likely that an admin forgets about this field when updating some classes. If we have forward_resource_values at the resource pool level, then it is less likely to be mis-configured (only needs to be set once per pool).
There was a problem hiding this comment.
the default for the forward_resource_values is false. we may want to have some classes with defaults and some with config. Also we could have a default in the pool and an override in the class ? Or do we disregard this feature for admins and simplify it at the pool level ?
There was a problem hiding this comment.
Is there a case where a resource pool would have a mix bag of forward: true and forward: false for classes? It seems to me that the setting could be left at the pool level.
There was a problem hiding this comment.
At CSCS they were talking about allowing partial node allocation because some people were complaining that 4xGB200 is a bit much for some tasks.
leafty
left a comment
There was a problem hiding this comment.
Comment: without a platform override (amd64 | arm64), it is not possible to merge clusters in a single resource pool.
Should I add it while I'm at it ? |
Sure. |
this is a bigger redesign as we need to use it to validate the image builds. do I simply wire it in for now then add the ui/image-building stuff in a follow up PR or is all of this a follow up pr ? |
We should leave it out then. |
|
Info: |
* feat: remove redundant kind field from resource-class API spec * refactor: derive resource class local/remote from parent pool * fix: components/renku_data_services/crc/apispec.py * test: update resource pool API tests for removed kind field * refactor: reset QuotaEnforced defaults at apispec level
…RD_RESOURCE_VALUES
…n model + validators
b5fcd65 to
0464e41
Compare
leafty
left a comment
There was a problem hiding this comment.
Looks good now, we should deploy and test.
| $ref: "#/components/schemas/RemoteConfigurationFirecrestSystemName" | ||
| partition: | ||
| $ref: "#/components/schemas/RemoteConfigurationFirecrestPartition" | ||
| forward_resource_value: |
There was a problem hiding this comment.
| forward_resource_value: | |
| forward_resource_values: |
| # FirecREST requires integer CPU. | ||
| cpu = rc.cpu if rc.cpu is not None else (existing.cpu if existing is not None else None) | ||
| if new_pool_kind == models.RemoteConfigurationKind.firecrest and cpu is not None and not cpu.is_integer(): | ||
| raise errors.ValidationError(message="FirecREST resource classes require an integer value for cpu.") |
There was a problem hiding this comment.
Can we not do ceil() instead? This could be annoying to deal with. (Or the admin would have to delete and re-create).
There was a problem hiding this comment.
The check only fires on writes (PUT/PATCH of the pool, POST of a class). GETs don't validate, so existing fractional-cpu classes still read back fine and don't need migrating.
Failing at write time is actually the right moment to be explicit: the admin is already making a change, so a clear error tells them to set an integer cpu in the same request rather than silently coercing a value they typed.
For the case where fractional data does slip through (legacy rows, etc.), I've switched the launch-time coercion in core_sessions.py from int() (truncated down) to ceil() (rounds up). That achieves the "never under-provision" result without hiding the write-time mismatch behind a silent fix.
Co-authored-by: Flora Thiebaut <flora@leafty.dev>
Summary
Adds a
kindand optional FirecRESTremoteoverride to resource classes so that FirecREST-backedclasses can target specific Slurm systems/partitions and optionally let the HPC grid choose CPU,
memory, and GPU. A single resource pool can now contain classes with different Slurm target
configurations.
Motivation and context
We originally targeted only CSCS, where the smallest allocation is a full node, so it was enough to
to let Slurm set the defaults for
CPUS_PER_TASK,GPUS,RAM. As we expand to other grids(Idiap) we need to tell Amalthea exactly how much of a node to request. We also want a single
resource pool to support multiple class-level target configurations and optionally which
system_name/partitionto use, rather than forcing one pool per Slurm target.Behavior
kind(local,firecrest,runai). The kind must match the parentpool's remote kind;
firecrestclasses require integer CPU and may only carryremoteoverrideswhen the pool is FirecREST.
remoteoverrides forsystem_nameandpartition, fallingback to the pool defaults when omitted. This lets a single pool hold multiple classes targeting
different Slurm systems or partitions.
ignore_resource_class_valuesto tell Amalthea to ignore the CRD CPU,memory, and GPU values and let the HPC grid choose them. The class still stores and reports the
values for display and quota matching.
RSC_FIRECREST_SYSTEM_NAME,RSC_FIRECREST_PARTITION(when set), and
RSC_FIRECREST_IGNORE_RESOURCE_CLASS_VALUES(when true). CPU, memory, and GPUcontinue to be passed through the session CRD resources as before.
rejected if any class still has FirecREST remote overrides when moving away from FirecREST, or if
any class has non-integer CPU when moving to FirecREST.
kindtolocal, so existingclients and legacy classes keep working.
Changes
Updated
crc/api.spec.yamland regeneratedcrc/apispec.py:ResourceClass/ResourceClassWithIdnow includekind: RemoteKind(defaultlocal) and anoptional
remote: RemoteClassConfigurationFirecrest.RemoteClassConfigurationFirecrestgainsignore_resource_class_values(defaultfalse).if/then/elseschema rules soremoteis forbidden whenkind != firecrestandcpumust be an integer when
kind == firecrest.Extended
crc/models.pywithFirecrestClassRemoteand addedkind/remotetoUnsavedResourceClass,ResourceClass, andResourceClassPatch.Extended
crc/orm.pywith aremote_jsoncolumn for class-level FirecREST overrides. Classkindis derived at read time from the parent pool'sremote_json.kind.Added an Alembic migration that adds
resource_classes.remote_json.Updated
crc/core.pyvalidators to:remoteoverrides on non-FirecREST classes.kindcorrectly on PUT/PATCH when omitted.Updated
crc/db.pyto persistremote_json, rejectkindchanges, and apply pool remote changesbefore class updates so class conversion sees the new pool kind.
Updated
crc/blueprints.pyto pass the existing class kind into standalone class PUT/PATCHvalidators.
Updated
notebooks/core_sessions.pyto compute effective FirecREST env vars from class overridesand emit
RSC_FIRECREST_IGNORE_RESOURCE_CLASS_VALUESwhen requested.Added unit tests for the new validators and updated FirecREST resource-pool and session-launch
tests.
Notes
kindis not stored on theresource_classestable; it is derived at read timefrom the parent pool's
remote_json.kind(defaulting tolocal). This keeps the migrationminimal (only
remote_jsonis added) while still making existing FirecREST/Run:AI classes appearwith the correct kind.
system_name/partitionfor now; they serve as thedefaults for classes without per-class overrides.