|
Once a pattern has triggered, its body is executed. The body consists of assignments, conditionals, loops, function calls, and termination statements. The statements in the pattern body are not guaranteed to be executed in strict sequence. The system guarantees that dependencies between statements are properly resolved, but statements with no dependencies can be executed out of order or concurrently. AssignmentsAssignments take the form: name := expression; Where the name must be a valid variable name and the expression must adhere to one of the valid expression kinds described in this section. It is an error to assign to a name that has been declared as a constant in the same pattern. Variables are dynamically typed according to the type of the expression. It is not an error to rebind a variable to a value with a different type to its previous value. ConditionalsThere is just one kind of conditional statement: the if: if expression then There may be any number of elif clauses; the else clause is optional. The expression may have any type – the values false, none, empty string, empty list, empty set, and numeric zero are considered false; all other values are considered true. LoopsThere is only one looping construct, the for loop: for variable in expression do The expression must be a list or set. It is a runtime error if it is not. The loop body executes for each item in the list or set; in each iteration the variable name is set to the corresponding list / set member. Looping can be terminated early with a break statement, or the next iteration started before the end of the loop body with the continue statement, e.g.: for item in collection do On exit from a loop, the loop variable is no longer valid. The loop variable cannot be modified in the body of the loop. Body terminationAfter triggering, it is common for a body to use some "existence criteria" to confirm that the entity modeled by the pattern does indeed exist. It can be useful to terminate the execution of the pattern body prematurely, using the stop statement, for example: if not existence_condition then If at all possible, patterns should use trigger conditions to avoid triggering when not necessary, rather than using stop in a condition. It is much more efficient to avoid triggering a pattern than to trigger and then stop. Value expressionsThere are a number of different kinds of expressions used in assignments and other declarations. Simple value expressions consist of literal values as described in the section on Common declarations and variable names. Numeric values can be involved in arithmetic expressions. Unary expressions prefix a value:
Infix arithmetic operations are the following:
The * / and % operators take binding precedence over + and -, which take precedence over << and >>, which take precedence over the other operators. Parentheses can be used to group sets of operations to override the precedence rules. String values may be concatenated using the + infix operator. Logical expressionsLogical expressions are expressions that evaluate to true or false. In boolean operations, values are considered true or false according to the same rules as for if statements, as described in section Conditionals. Logical expressions can be combined with the following operators:
Binding precedence for the operators follows the order they are given above. The operators before not are grouped together with the highest precedence, followed by not, then and, then or. Node scoped valuesVariables containing datastore nodes can be used to access the nodes' attributes, using the scoping dot character. e.g.: process := // get a DiscoveredProcess node from somewhere An attempt to access a non-existent attribute results in none. Key expressions can also be used to access values from related nodes: method := process.#Member:List:List:ProcessList.discovery_method; Since key expression traversals can find more than one target node, key expressions always return list values. As a consequence, accessing a non-existent traversal key expression results in an empty list. Attributes of nodes can also be set using the same kind of dot scoping, e.g.: host := model.host(process); Any attribute name may be set in this way, regardless of whether or not the name is defined in the taxonomy. Note that the attribute is stored with the type of the assigned value, even if the taxonomy specifies that it should have a different type. ListsLiteral lists are declared using [ and ] characters, with a comma-separated sequence of expression inside. e.g. values := [ "one", "two", "three" ]; Lists can be dereferenced using the [] operator: first := values[0]; List indexing starts from zero. Lists may be concatenated together with the + operator. The result of concatenating two lists is a new list; the original lists are left unchanged. New in TPL 1.2, items can be appended to lists with the list.append function: values := [ "one", "two" ]; FunctionsFunctions are used to interact with discovery, the data store, and external systems. Functions can be used as statements or as expressions, depending on whether there is a return value. Functions that return a value can be used as statements, in which case the return value is discarded. Functions are defined outside of the pattern language. Function names are usually scoped, using the dot character to separate the scope from the function name. The scope is used to group related functions together. The currently defined scopes are: log, text, number, regex, xpath, table, discovery, model, email, time, and inference, plus the global scope. Functions are called as follows scope.name(arguments) Function arguments are comma-separated sequences of expressions or assignments. Assignment-style arguments are used to provide named arguments. There are three different ways that functions can process their arguments.
The functions are grouped as follows:
All functions are listed on the Functions page along with a one line overview of each. String interpolationUnqualified literal strings take part in string interpolation. Values to be interpolated are surrounded by % characters. Values are accessed from the pattern's variables and constants. e.g. in: foo := "world"; The variable bar is set to the string "Hello_world!". Node scoped variables can also be interpolated. The above command and args example can be implemented with an interpolation: cmd_and_args := "%process.cmd% %process.args%"; To embed a literal percentage symbol in a string, use %% increase := 75; Values interpolated into strings must be strings or numbers. Sometimes it is useful to perform interpolation on a pre-existing string, particularly to specify patterns in constants. This can be achieved with an expand expression, e.g. template := raw "db_%instance%_1"; Note how the use of the raw string suppresses the interpolation that would normally occur in setting the template variable. The values to interpolate into the string in the expand are implicitly and explicitly named arguments as described in the section on functions above. Search expressionsSearches using the BMC Atrium Discovery search service are valid expressions in pattern bodies, with a number of minor modifications as described in Search expressions. |
