condor_transform_ads language
Transform rules files consist of lines containing key=value pairs or
transform commands such as
SET
,
RENAME
, etc. Transform commands execute
as they are read and can make use of values set up until that point
using the
$(key)
macro substitution commands that HTCondor configuration files
and condor_submit files use.
Most constructs that work in these files will also work in rules files such as if/else. Macro substitution will fetch attributes of the
ClassAd
to be transformed when
$(MY.attr)
is used.
The transform commands are:
SET <attr> <expr>
|
Set
<attr>
to
<expr>
|
EVALSET <attr> <expr>
|
Evaluate
<expr>
and then set
<attr>
to the result
|
DEFAULT <attr> <expr>
|
Set
<attr>
to
<expr>
if
<attr>
is undefined or missing
|
COPY <attr> <newattr>
|
Copy the value of
<attr>
to
<newattr>
|
COPY /<regex>/ <newattrs>
|
Copy the values of attributes whose names match
<regex>
to
<newattrs>
|
RENAME <attr> <newattr>
|
Rename
<attr>
to
<newattr>
|
RENAME /<regex>/ <newattrs>
|
Rename attributes matching
<regex>
to
<newattrs>
|
DELETE <attr> <newattr>
|
Delete
<attr>
|
DELETE /<regex>/
|
Delete attributes matching
<regex>
|
EVALMACRO <key> <expr>
|
Evaluate
<expr>
and then insert it as a transform macro value
|
In the above commands
<attr>
must be a valid attribute name and
<expr>
a valid
ClassAd
expression or literal. The various $() macros will be expanded in
<expr>
,
<newattr>
or
<newattrs>
before they are parsed as
ClassAd
expressions or attribute names.
When a
COPY
,
RENAME
, or
DELETE
with
<regex>
is used, regex capture groups are substituted in
<newattrs>
after $() expansion. \0 will expand to the entire match, \1 to the first capture, etc.
Optionally, a transform rule set can end with an iteration command
TRANSFORM [<N>] [<vars>] [in <list>
|
from <file>
|
matching <pattern>]
A
TRANSFORM
command must be the last command in the rules file. It takes the same options as the
QUEUE
statement from a HTCONDOR submit file. There is an implicit
TRANSFORM 1
at the end of a rules file
that has no explicit
TRANSFORM
command.
OSGs default route expressed in the TJ's proposed new transform language.
lines starting with the keywords set , delete , copy , rename , name are commands to the transform engine and are executed as they are read. lines that are of the form key = value set temporary variables that can be referenced in transform commmands using the various $() and $function() macro expansions that are common to config and submit files.
new transform language
NAME OSG CE Default route MaxIdleJobs = 2000 MaxJobs = 10000 # by default, accept all jobs Requirements = True # these triggers control IF statements later in the transform tmp.ExpireJob = False tmp.RemoveIfIdle = False # modify routed job attributes # DELETE CondorCE SET RoutedJob True # remove routed job if the client disappears for 48 hours or it is idle for 6 # IF $(tmp.RemoveIfIdle) SET PeriodicRemove (LastClientContact - time() > 48*60*60) || (JobStatus == 1 && (time() - QDate) > 6*60) ELSE DELETE PeriodicRemove ENDIF # insert HOME and OSG_* into environment # tmp.osg_env = OSG_GRID='/etc/osg/wn-client/' OSG_SQUID_LOCATION='fermicloud133.fnal.gov:3128' OSG_SITE_READ='None' OSG_APP='/share/osg/app' OSG_GLEXEC_LOCATION='None' OSG_DATA='UNAVAILABLE' tmp.osg_env = $(tmp.osg_env) OSG_HOSTNAME='fermicloud136.fnal.gov' OSG_STORAGE_ELEMENT='False' OSG_SITE_NAME='herp' GLOBUS_LOCATION='/usr' OSG_WN_TMP='None' OSG_DEFAULT_SE='None' OSG_SITE_WRITE='None' SET osg_environment "$(tmp.osg_env)" tmp.user_home_expr = userHome(Owner, "/") tmp.user_home = HOME=$EVAL(tmp.user_home_expr) COPY Environment orig_environment SET Environment "$(tmp.user_home) $(MY.orig_environment) $(MY.osg_environment)" # pick up GlobusRSL settings, we will use those later in the transform # NOTE: is it a bug to leave this attribute behind? # # set InputRSL = ifThenElse(GlobusRSL is null, [], eval_rsl(GlobusRSL)); # or possibly this IF DEFINED MY.GlobusRSL SET InputRSL eval_rsl(GlobusRSL) ELSE SET InputRSL [] ENDIF # Set new requirements IF $(tmp.ExpireJob) SET Requirements (LastClientContact - time()) < 30*60 ELSE SET Requirements True ENDIF # pass attributes (maxMemory,xcount,jobtype,queue) # via gWMS Factory described within ClassAd if undefined via RSL # Note default memory request of 2GB # IF DEFINED MY.InputRSL.MaxMemory SET RequestMemory $(MY.InputRSL.MaxMemory) ELIF $(MY.MaxMemory) SET RequestMemory MaxMemory ELSE SET RequestMemory $(MY.default_maxMemory:2000) ENDIF IF DEFINED MY.InputRSL.Queue SET remote_queue "$(MY.InputRSL.Queue)" ELIF DEFINED MY.Queue SET remote_queue Queue ELSE SET remote_queue "$(MY.default_queue)" ENDIF # Figure out the number of cores. HTCondor uses RequestCpus # blahp uses SMPGranularity and NodeNumber. Default is 1 core. # IF DEFINED MY.InputRSL.xcount tmp.cpus = $(MY.InputRSL.xcount) ELIF $(MY.xcount) tmp.cpus = $(MY.xcount) ELSE tmp.cpus = $(MY.default_xcount:1) ENDIF SET RequestCpus $(tmp.cpus) SET SMPGranularity $(tmp.cpus) SET NodeNumber $(tmp.cpus) # If remote_cerequirements is a string, BLAH will parse it as an expression before examining it # SET remote_cerequirements "CONDOR_CE == 1" # add a walltime to the remote_cerequirements expression if one is given. tmp.MaxWalltime_expr = 60 * (InputRSL.MaxWalltime ?: MaxWalltime ?: default_MaxWalltime ?: 0) IF $INT(tmp.MaxWalltime_expr) SET remote_cerequirements "Walltime == $INT(tmp.MaxWalltime_expr) && CondorCE == 1" ENDIF
For reference here is the same route expressed in the current new classad syntax
current job router language
[ MaxIdleJobs = 2000; MaxJobs = 10000; /* by default, accept all jobs */ Requirements = True; /* now modify routed job attributes */ /* remove routed job if the client disappears for 48 hours or it is idle for 6 */ /*set_PeriodicRemove = (LastClientContact - time() > 48*60*60) || (JobStatus == 1 && (time() - QDate) > 6*60); */ delete_PeriodicRemove = true; delete_CondorCE = true; set_RoutedJob = true; copy_environment = "orig_environment"; set_osg_environment = "OSG_GRID='/etc/osg/wn-client/' OSG_SQUID_LOCATION='fermicloud133.fnal.gov:3128' OSG_SITE_READ='None' OSG_APP='/share/osg/app' OSG_GLEXEC_LOCATION='None' OSG_DATA='UNAVAILABLE' OSG_HOSTNAME='fermicloud136.fnal.gov' OSG_STORAGE_ELEMENT='False' OSG_SITE_NAME='herp' GLOBUS_LOCATION='/usr' OSG_WN_TMP='None' OSG_DEFAULT_SE='None' OSG_SITE_WRITE='None'"; eval_set_environment = debug(strcat("HOME=", userHome(Owner, "/"), " ", ifThenElse(orig_environment is undefined, osg_environment, strcat(osg_environment, " ", orig_environment) ))); /* Set new requirements */ /* set_requirements = LastClientContact - time() < 30*60;*/ set_requirements = True; set_InputRSL = ifThenElse(GlobusRSL is null, [], eval_rsl(GlobusRSL)); /* Note default memory request of 2GB */ /* Note yet another nested condition allow pass attributes (maxMemory,xcount,jobtype,queue) via gWMS Factory described within ClassAd if undefined via RSL */ eval_set_RequestMemory = ifThenElse(InputRSL.maxMemory isnt null, InputRSL.maxMemory, ifThenElse(maxMemory isnt null, maxMemory, ifThenElse(default_maxMemory isnt null, default_maxMemory, 2000))); eval_set_remote_queue = ifThenElse(InputRSL.queue isnt null, InputRSL.queue, ifThenElse(queue isnt null, queue, ifThenElse(default_queue isnt null, default_queue, ""))); /* HTCondor uses RequestCpus; blahp uses SMPGranularity and NodeNumber. Default is 1 core. */ eval_set_RequestCpus = ifThenElse(InputRSL.xcount isnt null, InputRSL.xcount, ifThenElse(xcount isnt null, xcount, ifThenElse(default_xcount isnt null, default_xcount, 1))); eval_set_remote_SMPGranularity = ifThenElse(InputRSL.xcount isnt null, InputRSL.xcount, ifThenElse(xcount isnt null, xcount, ifThenElse(default_xcount isnt null, default_xcount, 1))); eval_set_remote_NodeNumber = ifThenElse(InputRSL.xcount isnt null, InputRSL.xcount, ifThenElse(xcount isnt null, xcount, ifThenElse(default_xcount isnt null, default_xcount, 1))); /* If remote_cerequirements is a string, BLAH will parse it as an expression before examining it */ eval_set_remote_cerequirements = ifThenElse(InputRSL.maxWalTlime isnt null, strcat("Walltime == ",string(60*InputRSL.maxWallTime)," && CondorCE == 1"), ifThenElse(maxWallTime isnt null, strcat("Walltime == ",string(60*maxWallTime)," && CondorCE == 1"), ifThenElse(default_maxWallTime isnt null, strcat("Walltime == ", string(60*default_maxWallTime), " && CondorCE == 1"), "CondorCE == 1"))); ]