{section: 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 =|Set == to ==| |=EVALSET =|Evaluate == and then set == to the result| |=DEFAULT =|Set == to == if == is undefined or missing| |=COPY =|Copy the value of == to ==| |=COPY // =|Copy the values of attributes whose names match == to ==| |=RENAME =|Rename == to ==| |=RENAME // =|Rename attributes matching == to ==| |=DELETE =|Delete ==| |=DELETE //=|Delete attributes matching ==| |=EVALMACRO =|Evaluate == and then insert it as a transform macro value| In the above commands == must be a valid attribute name and == a valid {quote: ClassAd} expression or literal. The various $() macros will be expanded in ==, == or == before they are parsed as {quote: ClassAd} expressions or attribute names. When a =COPY=, =RENAME=, or =DELETE= with == is used, regex capture groups are substituted in == 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 [] [] [in {quote:|} from {quote:|} matching ]= 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. {subsection: 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. {snip: 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 {endsnip} For reference here is the same route expressed in the current new classad syntax {snip: 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"))); ] {endsnip}