Hook to put a job in a queued based on user egroup

Hello guys, how are you doing?

I’m trying to write a hook to check the user’s group parameter. If the user belongs to the “others” group, the job is moved to a specific queue (eg. test) regardless of which queue he has specified.

I’m using the Hook Book as a reference, but I don’t have much knowledge in python and I’m unsure of which instruction to use on the hook to change the job’s queue .

I wrote, this simple script:

import sys
import pbs 

try:
    e = pbs.event()
    j = e.job

   pbs.logmsg(pbs.LOG_DEBUG, "egroup is  = %s" % str(j.egroup))

   if str(j.egroup) == "others":
      j.queue.name == "test"

except SystemExit:
    pass

except:
    e.reject("Failed with %s. Please contact Admin" % (sys.exc_info()[:2]))

And in which PBS event is it best place to set this hook? queuedjob or movejob?

Can someone give some lights on it?

Thanks and best regards.

I would think that if you intend to move the job to a specific queue, then this would need to happen at the queuejob stage. movejob occurs when the job is moved, not before.

With respect to setting the new queue in the job object, I don’t think that you can set j.queue.name, as it is likely read-only (that is the name of the queue in the queue object). Per the hook guide, 5.2.4.15 Table: Reading & Setting Job Attributes in Hooks, I think that you need to retrieve a new queue object for the test queue from the server and set it as the queue in the job object:

j.queue = pbs.server().queue("test")

First, make sure your indentation is consistent (in your script above it is not and will throw an error).

Next, as Gabe says, I don’t think a move job hook would work. But then the egroup attribute is not set on a job until it’s entered an execution queue. In other words you cannot select on egroup in a queuejob hook, it’s to early in the job’s lifecycle.

I was thinking you might be able to do something with a routing queue but again, that’s pre-execution queue so egroup still isn’t set on the job.

smgoosen@linux-cvb0:~> qsub -l select=1 -q router job.script
5.linux-cvb0
smgoosen@linux-cvb0:~> qstat
Job id Name User Time Use S Queue


5.linux-cvb0 job.script smgoosen 0 Q router
smgoosen@linux-cvb0:~> qstat -f | grep group
smgoosen@linux-cvb0:~> su -
Password:
linux-cvb0:~ # qmgr
Max open servers: 49
Qmgr: s q router started=true
Qmgr: q
linux-cvb0:~ # qstat
Job id Name User Time Use S Queue


5.linux-cvb0 job.script smgoosen 00:00:00 R workq
linux-cvb0:~ # qstat -f | grep group
egroup = users
linux-cvb0:~ #

Maybe you could clear the queue attribute that a user might submit with (set it to None) in queuejob hook then:

  • filter on job owner for entry from a route queue into the test queue?

smgoosen@linux-cvb0:~> qsub -l select=1 -q router job.script
9.linux-cvb0
smgoosen@linux-cvb0:~> qstat
Job id Name User Time Use S Queue


9.linux-cvb0 job.script smgoosen 0 Q router
smgoosen@linux-cvb0:~> qstat -f | grep Owner
Job_Owner = smgoosen@linux-cvb0
smgoosen@linux-cvb0:~>

  • or require that users submit with -Wgroup_list (enforce/verify in queuejob hook), could even write a wrapper for qusub that sets it? In queuejob hook:

smgoosen@linux-cvb0:~> qsub -l select=1 -Wgroup_list=users job.script

pbs.logmsg(pbs.LOG_DEBUG, “egroup is = %s” % str(j.egroup))
pbs.logmsg(pbs.LOG_DEBUG, “group_list is = %s” % str(j.group_list))
if str(j.group_list) == “users”:
j.queue = pbs.server().queue(“test”)

03/22/2021 16:05:56;0006;Server@linux-cvb0;Hook;Server@linux-cvb0;egroup is = None
03/22/2021 16:05:56;0006;Server@linux-cvb0;Hook;Server@linux-cvb0;group_list is = users

smgoosen@linux-cvb0:~> qstat
Job id Name User Time Use S Queue


8.linux-cvb0 job.script smgoosen 0 Q test
smgoosen@linux-cvb0:~>

  • or you could let all jobs go into an execution with started=false and then use a periodic hook to move the jobs into the appropriate “real” queue based on egroup (will be available at that point)?

Hi @gabe thank you so much for ypur reply.

I’ll try this solution.

Best regards

@smgoosen You’re right, I see now in the hook guide that egroup is not available until movejob. I have been able to get around this before getting the GID of the submitting user, resolving it to a group name, then performing some throttling logic based on group name. Conceivably, one could also check to see if the user is a member of a group (e.g., look at all of user’s groups to see if there is a match).

import pwd, grp
import pbs

user_name = pbs.event().requestor
user_obj = pwd.getpwname(username)
group_obj = grp.getgrgid(user_obj.pw_gid)
group_name = group_obj.gr_name

This assumes that the user and group are defined on the PBS server as they are on the submitting host, but I think that that is a common configuration (if not required by PBS).

(Note: I haven’t tested that this works, but it’s the idea)

@gabe and @smgoosen, thanks for your reply.

With these explanations, I will try to define the script that I need.

I had mentioned the egroup because when I run qstat -f, it’s defined the user’s primary group, but the solution that @gabe showed, I believe is sufficient for my script.

Thanks

Hi!

Just for feedback. The code below works as expected:

import pwd, grp
import pbs 

user_name = pbs.event().requestor
user_obj = pwd.getpwnam(user_name)
group_obj = grp.getgrgid(user_obj.pw_gid)
group_name = group_obj.gr_name

try:
	e = pbs.event()
	j = e.job

	if "others" in str(group_name):
		j.queue = pbs.server().queue("test")

except SystemExit:
	pass

except:
	e.reject("Failed with %s. Please contact Admin" % (sys.exc_info()[:2]))

Thanks @gabe and @smgoosen

2 Likes