ClassAds

The ClassAd language consists of two parts: structured data (called “ClassAds”), and expressions.

HTCondor uses ClassAds to describe various things, primarily machines and jobs; it uses expressions as constraints for querying ClassAds, and for defining what it means for two ClassAds to match each other.

Data Syntax

A ClassAd is a list of attribute-value pairs, separated by newlines. Values may be booleans, integers, reals, strings, dictionaries, lists, or the special values UNDEFINED and ERROR. Dictionaries are marked by square brackets and lists by braces; dictionaries separate elements with semicolons, and lists separate elements with commas.

attribute_name  = "attribute-value"
pi              = 3.141
count           = 3
list            = { "red", "green", "blue" }
dictionary      = [ type = "complex"; real = 7.75; imaginary = -3 ]
structured_attr = [ hostnames = { "submit-1", "submit", "submit1" };
                    ip = "127.0.0.1"; port = "9618" ]

For the list of ClassAd attributes generated by HTCondor, see https://htcondor.readthedocs.io/en/latest/classad-attributes/index.html.

Expression Syntax

An expression consists of literals (from the data syntax) and attribute references composed with operators and functions. The value of a ClassAd attribute may be an expression.

MY.count < 10 && regexp( ".*example.*", attribute_name )

Attribute References

An attribute reference always includes an attribute name. In HTCondor, when determining if two ClassAds match, an expression may specify which ad’s value is used by prefixing it with MY. or TARGET.. Attribute references are case-insensitive.

MY.count
TARGET.machine

An element of a dictionary is referenced by using the subscript operator ([]) with an expression that evaluates to a string or with a dot (.), as follows:

MY.structured_attr.hostnames
MY.structured_attr["hostnames"]

Note that the following references the attribute named by the attribute hostnames, not the attribute named hostnames:

MY.structured_attr[hostnames]

List elements are referenced by an expression that evaluates to an integer, where the first element in the list is numbered 0. For example, if colors = { [ x = "1" ], [ x = "2", y = "3" ] }, then MY.structure_attr.colors[0] results in [ x = "1" ].

UNDEFINED and ERROR

The ClassAd language includes two special values, UNDEFINED and ERROR. An attribute may be set to either explicitly, but these values typically result from referring to an attribute that doesn’t exist, or asking for something impossible:

undefined_reference = MY.undefined_attribute
explicitly_undefined = UNDEFINED
one_error_value = "three" * 7
another_error_value = 1.3 / 0

Most expressions that refer to values that are UNDEFINED will evaluate to UNDEFINED. The same applies to ERROR.

Operators

The operators *, /, + and - operate arithmetically, on integers and reals.

The comparison operators ==, !=, <=, <, >= and > operate on booleans, integers, reals and strings. String comparison is case-insensitive. Comparing a string and a non-string value results in ERROR.

The special comparison operator =?= is like == except in the following two ways: it is case-sensitive when comparing strings; and, when comparing values to UNDEFINED, results in FALSE instead of UNDEFINED. (If comparing UNDEFINED to itself, the operator =?= results in TRUE).

The special comparison operator =!= is the negation of =?=.

The logical operators && and || operate on integers and reals; non-zero is true, and zero is false.

The ternary operator x ? y : z operates on expressions.

The default operator x ?: z returns x if x is defined and z otherwise.

The IS and ISNT operators are synonyms for =?= and =!=.

Functions

Function name are case-insensitive. Unless otherwise noted, if any of a function’s arguments are UNDEFINED or ERROR, so is the result. If an argument’s type is noted, the function will return ERROR unless the argument has that type.

integer INT( expr )

If expr is numeric, return the closest integer. If expr evaluates to a string, attempt to convert the string to an integer. Return ERROR if the string is not an integer, or if expr is neither numeric nor a string.

boolean MEMBER( expr, list l )

Returns TRUE if expr is equal, as defined by the operator ==, to any member of the list l, or FALSE if it isn’t.

boolean REGEXP( string pattern, string target[, string options] )

Return TRUE if the PCRE regular expression pattern matches target, or FALSE if it doesn’t. Return ERROR if pattern is a not a valid regular expression. If specified, options is a PCRE option string (one or more of f, i, s, m, and g). See the Specification section for details.

list SPLIT( string s[, string tokens ] )

Separate s by whitespace or comma, or instead by any of the characters in tokens, if specified, and return the result as a list of strings.

boolean STRINGLISTIMEMBER( string s, string list[, string tokens] )

Equivalent to MEMBER( *s*, SPLIT( *list*, *tokens* )).

string SUBSTR( string s, integer offset[, integer length] )

Returns the substring of s from offset to the end of the string, or instead for length characters, if specified. The first character in s is at position 0. If offset is negative, the substring begins offset characters before the end of the string. If length is negative, the substring ends that many characters before the end of the string. If the substring contains no characters, return the empty string. Thus, the following two calls both return the string “78”:

substr( "0123456789", 7, 2 )
substr( "0123456789", -3, -1 )

All ClassAd functions are defined in the references below.

Reserved Words

The words UNDEFINED, ERROR, IS, ISNT, TRUE, FALSE, MY, TARGET, and PARENT may not be used as attribute names.

Testing ClassAd Expressions

If your pool has machines in it, you can use condor_status to evaluate a ClassAd expression on the command-line. For instance, if you can’t remember which kind of regular expressions the regexp() function uses, you could check in the following way (on Linux):

condor_status -limit 1 -af 'regexp( "*tr*", "string" )'
condor_status -limit 1 -af 'regexp( ".*tr.*", "string" )'

This will print out false and then true; if you have no machines in your pool, it will print nothing. (For each ad condor_status fetches, it evaluates the expression(s) passed to -af and prints the result; the -limit 1 ensures that this is at most 1 ad.)

Examples

These examples assume a Linux shell environment.

Selecting a Slot based on Job ID

If job 288.7 is running:

condor_status -const 'JobId == "288.7"'

Only Run on a Particular Machine

If you want your job to run only on a particular machine named ‘special’, add the following to your submit file’s requirements line:

Machine == "special"

String Manipulation

In this example, an administrator has just added twelve new hosts to the pool – compute-296 to compute-307 – and wants to see if they’ve started running jobs yet.

condor_status -const '296 <= int(substr( Machine, 8 )) &&
    int(substr( Machine, 8 )) <= 307'

You could also write this as follows:

condor_status -const '296 <= int(split(Machine, "-")[1]) &&
    int(split(Machine, "-")[1]) <= 307'

Selecting Machines with a Particular File-Transfer Plugin

If you’re considering using the gdrive file-transfer plugin, and you’d like to see which machines have it, select from the slot ads based on the corresponding attribute, but only print out the machine name, and then throw away the duplicates:

condor_status -af Machine \
    -const 'StringListIMember( "gdrive", HasFileTransferPluginMethods )' \
    | uniq

You could instead use a constraint to ignore dynamic slots for a report on the resources available to run jobs which require the gdrive plugin. Note that you can also use expressions when formatting the output. In this case, it’s just to make the output prettier.

condor_status -af Machine CPUs Memory Disk \
    '(GPUs =!= undefined && GPUs >= 1) ? CUDACapability : "[no GPUs]"' \
    -const 'SlotType =!= "Dynamic" &&
        StringListIMember( "gdrive", HasFileTransferPluginMethods )'

Author

Center for High Throughput Computing, University of Wisconsin-Madison