| --[[ | |
| --Example job_submit.lua file for Slurm | |
| --For more information check: | |
| -- https://slurm.schedmd.com/job_submit_plugins.html | |
| --For the list of available fields check: | |
| -- src/plugins/job_submit/lua/job_submit_lua.c | |
| --]] | |
| log_prefix = 'slurm_job_submit' | |
| function _find_in_str(str, arg) | |
| if str ~= nil then | |
| return string.find(str,arg) | |
| else | |
| return false | |
| end | |
| end | |
| function _log_user_and_debug(fmt, ...) | |
| --[[ | |
| Different messages logged to end user should be associated | |
| unique return code, to make those properly displayed in case | |
| of modification of array job. | |
| --]] | |
| --[[ Implicit definition of arg was removed in Lua 5.2 --]] | |
| local arg = {...} | |
| --[[ | |
| -- Returning a message to user from slurm_job_modify is supported | |
| -- since Slurm 23.02, using it in older versions will result in | |
| -- an error message in slurmctld logs. | |
| -- In older versions of Lua - prior to Lua 5.2 you may need to use | |
| -- unpack as a built-in instead of table.unpack | |
| ]]-- | |
| slurm.log_user(fmt, table.unpack(arg)) | |
| slurm.log_debug(fmt, table.unpack(arg)) | |
| end | |
| -- Do not allow interactive jobs longer than 4 hours except for certain users | |
| function validate_interactive_job(job_desc, uid) | |
| if job_desc['script'] ~= nil then | |
| return slurm.SUCCESS -- no limit for batch jobs | |
| end | |
| if uid == 0 --[[ or uid == SpecialUser --]] then | |
| _log_user_and_debug("Interactive job allowed for uid: %u", uid) | |
| else | |
| local time_limit = job_desc['time_limit'] | |
| if (time_limit == slurm.NO_VAL) then | |
| _log_user_and_debug("You must request a time limit within 4 hours for interactive jobs") | |
| return slurm.ESLURM_INVALID_TIME_LIMIT | |
| elseif (time_limit > (4 * 60)) then | |
| _log_user_and_debug("Interactive jobs for time longer than 4h forbidden") | |
| return slurm.ESLURM_INVALID_TIME_LIMIT | |
| end | |
| end | |
| return slurm.SUCCESS | |
| end | |
| function slurm_job_submit(job_desc, part_list, submit_uid) | |
| --[[ | |
| Don't block any activity from root. | |
| This may make reproduction of user errors difficult | |
| --]] | |
| if submit_uid == 0 then | |
| return slurm.SUCCESS | |
| end | |
| local rc = validate_interactive_job(job_desc, submit_uid) | |
| if rc ~= slurm.SUCCESS then | |
| return rc | |
| end | |
| --[[ | |
| -- Change partition to GPU if job requested any GPU | |
| -- depending on option used this may be visible in | |
| -- different job_desc field: | |
| -- --gres=gpu: -> tres_per_node | |
| -- --gpus-per-task -> tres_per_task | |
| -- --gpus-per-socket -> tres_per_socket | |
| -- --gpus -> tres_per_job | |
| --]] | |
| if _find_in_str(job_desc['tres_per_node'], "gpu") or | |
| _find_in_str(job_desc['tres_per_task'], "gpu") or | |
| _find_in_str(job_desc['tres_per_socket'], "gpu") or | |
| _find_in_str(job_desc['tres_per_job'], "gpu") then | |
| job_desc.partition = 'gpu' | |
| _log_user_and_debug("%s: Set partition to: %s", | |
| log_prefix, | |
| job_desc.partition) | |
| end | |
| --[[ Forbid unlimited --mem if memory specified --]] | |
| if job_desc['min_mem_per_node'] ~= nil then | |
| if job_desc['min_mem_per_node'] == 0 then | |
| slurm.log_user("%s: --mem=0 is not allowed", | |
| log_prefix); | |
| return slurm.ESLURM_ACCOUNTING_POLICY; | |
| end | |
| else | |
| --[[ Enforce --mem specification --]] | |
| if job_desc['min_mem_per_cpu'] == nil then | |
| _log_user_and_debug("%s: Neither --mem nor --mem-per-cpu specified", | |
| log_prefix); | |
| return slurm.ESLURM_ACCOUNTING_POLICY; | |
| else | |
| if job_desc['min_mem_per_cpu'] == 0 then | |
| _log_user_and_debug("%s: --mem-per-cpu=0 is not allowed", | |
| log_prefix); | |
| return slurm.ESLURM_ACCOUNTING_POLICY; | |
| end | |
| end | |
| end | |
| --[[ Forbid usage of MAINT job name --]] | |
| if job_desc['name'] == "MAINT" then | |
| _log_user_and_debug("%s: JobName=MAINT reserved. Please use other name.", | |
| log_prefix); | |
| return slurm.ERROR | |
| end | |
| --[[ | |
| -- If no default partition, set to the highest | |
| -- priority partition this user has access to | |
| --]] | |
| if job_desc['partition'] == nil then | |
| local new_partition = nil | |
| local top_priority = -1 | |
| local last_priority = -1 | |
| local inx = 0 | |
| for name, part in pairs(part_list) do | |
| slurm.log_debug2("%s: part name[%d]:%s", | |
| log_prefix, | |
| inx, | |
| part['name']) | |
| inx = inx + 1 | |
| --[[ | |
| -- Don't change partition if the default | |
| -- is defined in the slurm.conf | |
| --]] | |
| if part['flag_default'] ~= 0 then | |
| top_priority = -1 | |
| break | |
| end | |
| if part['priority_job_factor'] ~= nil then | |
| slurm.log_debug3("%s: last priority is %d", | |
| log_prefix, | |
| part['priority_job_factor']) | |
| last_priority = part['priority_job_factor'] | |
| if last_priority > top_priority then | |
| top_priority = last_priority | |
| new_partition = part.name | |
| end | |
| end | |
| end | |
| if top_priority >= 0 then | |
| _log_user_and_debug("%s: setting default partition value: %s", | |
| log_prefix, | |
| new_partition) | |
| job_desc.partition = new_partition | |
| end | |
| end | |
| return slurm.SUCCESS | |
| end | |
| function slurm_job_modify(job_desc, job_ptr, part_list, modify_uid) | |
| --[[ | |
| -- While working on that it's important to understand that | |
| -- modification of a job array metarecord may differs from specific | |
| -- element modification. When job is not yet split to tasks it will | |
| -- be treated as one element. | |
| --]] | |
| --[[ Don't block/modify any update from root --]] | |
| if modify_uid == 0 then | |
| return slurm.SUCCESS | |
| end | |
| local rc = validate_interactive_job(job_desc, modify_uid) | |
| if rc ~= slurm.SUCCESS then | |
| return rc | |
| end | |
| --[[ | |
| -- Forbid unlimited --mem in update | |
| -- for instance: scontrol update job=XX MinMemoryNode=0 | |
| --]] | |
| if job_desc['min_mem_per_node'] ~= nil then | |
| if job_desc['min_mem_per_node'] == 0 then | |
| _log_user_and_debug("%s: Updating MinMemPerNode=0 is not allowed", | |
| log_prefix) | |
| return slurm.ESLURM_ACCOUNTING_POLICY; | |
| end | |
| end | |
| if job_desc['min_mem_per_cpu'] ~= nil then | |
| if job_desc['min_mem_per_cpu'] == 0 then | |
| _log_user_and_debug("%s: Updating MinMemoryCPU=0 is not allowed", | |
| log_prefix) | |
| return slurm.ESLURM_ACCOUNTING_POLICY; | |
| end | |
| end | |
| --[[ Forbid usage of MAINT job name --]] | |
| if job_desc['name'] == "MAINT" then | |
| _log_user_and_debug("%s: Updating JobName to MAINT is not allowed from non-root user", | |
| log_prefix); | |
| --[[ | |
| -- This will show 'Unspecified error' but use of | |
| -- slurm.log_user is limited to job_submit | |
| --]] | |
| return slurm.ERROR | |
| end | |
| return slurm.SUCCESS | |
| end |