This topic describes the various child tags allowed within the <deviceCommand> tag, within a given <deviceType> tag that defines a device type adapter. It describes the most commonly used features of those tags and presents examples to help you code your own adapters. For a complete description of all the available elements and attributes, see Device-type-CLI-interaction-XML-element-reference.
- Interactions
- Bounded interactions
- Unbounded interactions
- Optional interactions
- Property capture–XML reference
- Property capture—simple
- Property capture—complex
- Property capture—xpath
- Property capture—multiple values
- Property capture—multiple passes
- Property capture warnings
- Property assignment
- Conditions
- Response properties
- Error properties
- Retry
- Disconnect
- Loops - Types
- Loops - Multiple Arrays
- Assertions
- Regular expression support
- Jitter time
- Stutter time
- Sensitive commands
- Finally Block
- Sleep
- Auto discovery
- Reusable responses and errors
Interactions
An <interaction> is a block that defines one terminal command to be executed on a target device. An <interaction> element can include the following sub-elements:
- <prompt>: Defines the prompt required to be emitted by the device before the command is sent to it.
- <command>: Defines the command to be executed on the device.
- <response>: Defines a response that the device is going to exhibit after the command execution that indicates the command succeeded.
- <error>: Defines a response that the device is going to exhibit after the command execution that indicates the command failed.
- <capture>: Enables you to capture parts of the command's output into properties, for later use in other interactions.
- <pauseSeconds>: Defines the time in seconds for which you want to explicitly wait between sending the command and reading in the response.
Back to top
Bounded interactions
Interactions which have both prompt and response elements are called bounded. That is, there is a specific expected string to be read from the device before sending it a command, and there is a specific expected string to be read from the device after sending it a command.
The following example shows a device command with bounded interaction:
Example of a bounded interaction
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_C</response>
<error>text_D</error>
</interaction>
<interaction>
<prompt>text_C</prompt>
<command>text_E</command>
<response>text_F</response>
<error>text_G</error>
<error>text_H</error>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C or text_D found in the read buffer if the read buffer contains text_D then throw exception to trigger error handling endif |
<prompt> | read device output until text_C found in the read buffer; in this case, text_C is already in the read buffer |
<command> | clear read buffer, send text_D to the device |
<response> | read device output until text_F or text_G or text_H found in the read buffer if read buffer contains text_G then throw exceptionto trigger error handling else if read buffer contains text_H then throw exceptionto trigger error handling endif |
An interaction always monitors the execution of a command to receive an expected response within a timeout period. The interaction generates a timeout exception if none of the response or error tags is matched within the timeout period. You can control the default timeout period via the deviceDefaultResponseTimeoutSeconds global property, but you can also specify it on a per interaction basis by using the timeoutSeconds attribute.
Back to top
Unbounded interactions
Interactions that are missing a prompt or a response or both tags are called unbounded. That is, no specific input is expected prior to issuing the command or after issuing the command.
The following example shows a device command with unbounded interaction:
Example of an unbounded interaction
<deviceCommand>
<interaction>
<command>text_A</command>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<command> | clear the read buffer, send text_A to the device |
When the <response> element is omitted, any<error> tags present might or might not be matched. This is because the receive action performed after a command is sent in a non-blocking interaction a single non-blocking read, as opposed to a blocking read in a bounded interaction. If the device responds slowly, no text is present in the read buffer yet, so you would not detect the error. Similarly, if the device responds with a lot of jitter (more than 10 milliseconds in between characters sent), you would also miss the error.
You can specify a<pauseSeconds> tag for unbounded interactions, when you want to explicitly wait for one or more seconds between sending the command and starting to read the response. This can be helpful for unbounded cases with <error> elements, but introduces fixed pauses that make the overall action take longer to complete, and take longer every single time. For this reason, it is generally advisable to specify adequate <prompt> and<response> tag boundaries for your interactions.
Back to top
Optional interactions
An<interaction> tag can include an optional attribute to reflect the unpredictable device behavior. That is, you can match one of a series of possible expected prompts.
The following example shows a device command containing an interaction with the optional attribute:
Example of the optional attribute
<deviceCommand>
<interaction optional="true">
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_C</response>
</interaction>
<interaction>
<prompt>text_C</prompt>
<command>text_D</command>
<response>text_E</response>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A or text_C found in the read buffer (the prompt from the optional interaction or the prompt from the required interaction) |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C found in the read buffer endif |
<prompt> | read device output until text_C found in the read buffer |
<command> | clear read buffer, send text_D to the device |
<response> | read device output until text_E found in read buffer |
Be careful when using optional interactions because they are not permitted in all circumstances. You cannot use an optional interaction as the last interaction prior to or within a complex block of interactions being evaluated. That is, a non-optional interaction is required to terminate the list of candidate interactions. This means the last interaction in the<deviceCommand> tag cannot be optional. It also means that the last interaction prior to or within a loop cannot be optional either. In case of a condition, if it is not a simple block (for example, it contains nested conditions or loops), then the last interaction prior to or within such a condition cannot be optional either. Loopsand conditions are described in subsequent sections. It is best to avoid optional interactions inside these complex logic blocks.
If you violate these rules, you are blocked until you receive the optional<prompt> within the receive buffer. If the device does not send the optional<prompt>, the command times out and fails erroneously.
Back to top
Property capture–XML reference
It is often useful to capture some part of the output of a command, and use that part in a subsequent command or use it for conditional logic. SeeCommon concepts and XML elementsfor an overview.
The <capture> element allows you to parse command output and create and populate one or more properties. For example, you can use this element to capture a device's dynamic<prompt> in a property, or to capture the entire contents of its configuration file dumped over the terminal session.
The <capture> element is complex and has many available attributes, all of which are optional. Inside, at least one child <property> element is required to specify the name of the property to which the value is assigned and what the value is.
<capture> attribute reference
<capture append="false"
buffer=""
defValue=""
eagerPrefix="false"
eagerSuffix="true"
failsafe="false"
ignoreFailure="false"
ignorePrefix="false"
ignoreSuffix="false"
includePrefix="false"
includeSuffix="false"
index=""
iterArrays=""
iterVariables=""
multipleValues="false"
omitEOL="false"
optionalPrefix="true"
optionalSuffix="false"
prefix=""
suffix=""
xpath="">
<property name="">propertyValue</property>
</capture>
The following table describes all of the attributes:
Attribute | Description |
---|---|
append | true or false to indicate if the new value should be appended to any existing property value. When false, any existing value is removed Default value is false. |
buffer | String containing a regular expression to match only a part of the command's output Include parentheses around parts to define a capture group, which you can then refer to by number on the value. Default value is null, meaning to capture from all of the command's output between prefix and suffix. |
defValue | String containing the default value to assign to the property Used only when ignoreFailures is true, to assign a value to the property when the input is not matched to the other capture criteria. |
eagerPrefix | true or false to indicate if the last match of the prefix in the received text is the starting delimiter, as opposed to the first match Default value is false. |
eagerSuffix | true or false to indicate if the last match of the suffix in the received text is the ending delimiter, as opposed to the first match Default value is true. |
failsafe | true or false to indicate if a capture should only be attempted if the preceding capture failed This is useful for instance if a given interaction has two capture tags, but you only want the second one to be used if the first one fails. Default value is false. |
ignoreFailure | true or false to indicate if it is considered an error if the capture criteria is not matched. When true, if nothing is captured, then the XML logic continues; when false, the XML logic throws an exception (IOException), causing the action to fail. Default value is false. |
ignorePrefix | true or false to indicate if the prefix is to be ignored, making the capture unbounded at the beginning (no start delimiter) Default value is false. |
ignoreSuffix | true or false to indicate if the suffix is to be ignored, making the capture unbounded at the end (no ending delimiter) Default value is false. |
includePrefix | true or false to indicate if the string specified by the prefix is to be included in the text to be examined Default value is false. |
includeSuffix | true or false to indicate if the string specified by the suffix is to be included in the text to be examined Default value is false. |
index | String containing information about how to construct an associative index name for a property array in a multi-value capture. |
iterArrays | Used in multi-pass style capture. Holds a comma-delimited list of property-array names to use as inputs to assign values to iterVariables, in order to make multiple passes over the text received from the device to capture property values. If populated, it must contain the same number of names as iterVariables. See the example below. |
iterVariables | Used in multi-pass style capture. Can hold a comma-delimited list of variable names which appear as "%capture.variableName%" keywords within the capture buffer. Used in conjunction with the iterArrays attribute to support multiple pass capture logic. If populated, it must contain the same number of names as iterArrays. |
multipleValues | true or false to indicate if the buffer is to be matched multiple times, producing multiple properties whose names are augmented with a counter value starting at zero. See the example below. Default value is false. |
omitEOL | true or false to indicate if append is true, an end-of-line sequence is to separate the values appended to the property. When false, there is no separator (not even a space), unless you include it yourself as part of the value. Default value is false. |
optionalPrefix | true or false to indicate if the absence of the prefix is to be treated as an error. When true and the prefix is not matched in the command's output, then the capture becomes unbounded at the beginning (no start delimiter). Default value is true. |
optionalSuffix | true or false to indicate if the absence of the suffix is to be treated as an error. When true and the suffix is not matched in the command's output, then the capture becomes unbounded at the end (no ending delimiter). Default value is false. |
prefix | String or regular expression containing the delimiter that starts the text to be examined for storage into property values. If the regex attribute of the containing <interaction> or <httpInteraction> element is set to false, value can be a string to search for an exact match. If regex is set to true, value can be a regular expression to search for an inexact match. Default is to examine the command output from the echoed command string (but not including that string). |
suffix | String or regular expression containing the delimiter that ends the text to be examined for storage into property values. If the regex attribute of the containing <interaction> or <httpInteraction> element is set to false, value can be a string to search for an exact match. If regex is set to true, value can be a regular expression to search for an inexact match. Default is to examine the command output up to but not including the matched <response>. |
xpath | String containing an xpath to use to narrow down the input from which to capture. If specified, then the normal input which is captured from (after being trimmed using prefix and suffix specifications) is interpreted as an XML document, then it will have this xpath expression applied to it to select a desired piece (or pieces) from it, then the desired piece will be translated back into an XML string. The resulting XML string is then what we will try to capture values from. See the example below. |
Back to top
Property capture—simple
Property capture can be divided into two phases:
- extract the capture buffer or the target piece of text from the device's command output, using the prefix and suffix related attributes to define the delimiters, and the buffer attribute to isolate a substring.
- for each <property> element, extract the relevant parts of the capture buffer (or use the whole capture buffer) and assign to the property.
The following example shows a device command containing an interaction with a simple property capture:
Example of a simple property capture
<deviceCommand>
<interaction>
<command>text_A</command>
<response>text_B</response>
<capture prefix="text_C" suffix="text_D">
<property name="property_1"/>
</capture>
</interaction>
<interaction>
<prompt>%property_1%</prompt>
<command>text_E</command>
<response>text_F</response>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<command> | clear read buffer, send text_A to the device |
<response> | read device output until text_B found in the read buffer |
<capture> | if the read buffer contains text_C.*text_D then copy read buffer that is in between text_C and text_D into the property named property_1 else throw exception endif |
<prompt> | read device output until the text stored in property_1 found in the read buffer |
<command> | clear read uffer, send text_E |
<response> | read device output until text_F found in the read buffer |
The prefix and suffix attributes in the preceding example are optional and define the delimiters of the text of interest within all the text read from the device. If you omit prefix, text_B (the echoed command) is used as the prefix (or starting delimiter). If you omit suffix, text_B (the response) is used as the suffix (or ending delimiter).
You can specify includePrefixor includeSuffixor both attributes (they default to false) to adjust whether or not the delimiters are included in the capture buffer. If both are true, for example, the value of property_1 includes the surrounding text_C and text_D strings instead of containing just the text in between them.
TheoptionalPrefix andoptionalSuffix attributes can be used if you want to indicate that the prefix/suffix might not always be present. The normal behavior is for the absence of the indicated prefix/suffix to generate an error, since the capture cannot locate its delimiters.
TheeagerPrefix andeagerSuffix attributes are available to help you control which match of the prefix and suffix to use to bound your capture. This can be useful if they can appear in the command output multiple times. A value of true foreagerPrefix results in using the last match of the prefix, while a value of false results in using the first match of the prefix. Likewise, a value of true foreagerSuffix results in using the last match of the suffix, while a value of false results in using the first match of the suffix.
If you do not specify the<response> tag and specify the<capture> tag, an unbounded capture is performed. For unbounded captures, the underlying interpreter is slowed down so that it waits up to 1 second in between reads on an empty buffer before assuming that no more data is incoming. This is opposed to 10 milliseconds, which is the normal jitter time allowed for non-blocking read attempts. You can also specify a <pauseSeconds> tag if desired to help on unbounded captures. However, such mitigation can still fail, so unbounded captures are not recommended.
Anappend attribute is available on the<capture> tag if you want the captured string to be appended to a potentially existing property. The default behavior is to replace the value of any existing property of the same name. When appending, you can use anomitEOL attribute to control whether a trailing EOL is added to the captured value when it does not already have one. Making sure the capture always ends in an EOL is necessary for certain prompt capture logic. This check is always made when append is false. When append is true, the check is made by default, unless omitEOL is true.
Capturing in append mode can be used, for instance, to construct a configuration file by using the output of multiple commands within the device. Another way to do this is to use the<deviceCommand> tag and its capture attribute to capture the output of every interaction, in sequence, into a single property.
Note
If you see any warnings related to <capture> tags in the
TrueSight Network Automation
log file when the server is starting up or being upgraded, seeProperty capture warnings.
Back to top
Property capture—complex
More complex forms of property capture allow you to perform regular expression based matching within the normal capture boundaries to copy various substring snippets into regular expression buffers, which can then be assigned to one or more named properties.
The following example shows a device command containing an interaction with a complex property capture:
Example of a complex property capture
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_D</response>
<capture prefix="text_C" suffix="text_D" buffer="X(.*)Y"
ignoreFailure="true" defValue="unknown">
<property name="property_0">{0}</property>
<property name="property_1">{1} bytes</property>
</capture>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_D found in read buffer |
<capture> | if read buffer contains text_C.*text_D then if read buffer contents between text_C and text_D contains X.*Y snippet then copy all bytes in snippet to property_0 (the {0} means everything that matched the buffer) copy first grouped bytes in snippet, plus the word "bytes" to property_1 (the {1} means what matched inside the first set of parentheses) else set property_0 to unknown set property_1 to unknown endif else set property_0 to unknown set property_1 to unknown endif |
The buffer regular expression can include as many parenthesized capture groups as you need, for assigning the bits and pieces into different properties in different combinations. The <property> element's value can then refer to these capture groups by number, and can mix in hard-coded strings as well. The <property> element's value can also be a hard-coded string and not refer to anything in the device command's output.
TheignoreFailure anddefValue attributes are optional. If ignoreFailure is used but defValue is not, the properties are left unset in the preceding example. If defValue is used, ignoreFailure must also be used.
Note
If you see any warnings related to <capture> tags in the
TrueSight Network Automation
log file when the server is starting up or being upgraded, seeProperty capture warnings.
Back to top
Property capture—xpath
You can specify anxpathattribute in the <capture> tag to process command output as an XML string.If specified, the sequence of characters on which the capture will be performed (after any prefix and suffix bounding has been performed) is limited to those which match the specified xpath. It can be used with both simple and complex captures.
The following example shows a device command containing an interaction with a simple property capture that uses xpath filtering:
Example of a simple property capture with xpath filtering
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_D</response>
<capture prefix="<root>" includePrefix="true"
suffix="</root>" includeSuffix="true"
xpath="//TagA/ChildTagB[name='MyName']/id/text()">
<property name="property_1"/>
</capture>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_D found in read buffer |
<capture> | if read buffer contains <root>.*</root> then copy buffer between <root> and </root> (inclusive) to temp if xpath matches content within temp then copy xpath matches to property property_1 else throw exception endif else throw exception endif |
For example, consider a device sent back the following characters after you sent thetext_B command:
<root>
<TagA>
<ChildTagA>
<name>OtherName</name>
<id>OtherId</id>
</ChildTagA>
<ChildTagB>
<name>MyName</name>
<id>MyId</id>
</ChildTagB>
</TagA>
</root>
The portion highlighted in blue is the portionthat matches the prefix and suffix boundaries. While the portion highlighted in green is the portion that further matches the xpath filter. The result therefore would be to capture the value “MyId” to property_1.
Note
The xpath style matching can be particularly powerful when combined with the multi-value capture logic (for example,if the xpath filter matches multiple snippets). Refer to the xpath documentation for further details if you are unfamiliar with its syntax.
Note
If you see any warnings related to <capture> tags in the
TrueSight Network Automation
log file when the server is starting up or being upgraded, seeProperty capture warnings.
Back to top
Property capture—multiple values
If themultipleValues attribute is set to true, a special “multiple values” style of capture is performed. The buffer regular expression is applied multiple times and the <property> elements applied to each match.
The following example shows multiple-value property capture into a normal array:
Example of a multiple-value property capture into a normal array
<capture buffer="X(.*)Y" multipleValues="true">
<property name="arrayA">{1}</property>
</capture>
If the receive buffer contains the text XAAAY XBBBY, the capture would populate three properties:
- property named arrayA.0 with value AAA
- property named arrayA.1 with value BBB
- property named attayA.length with value 2
The regular expression pattern “X(.*)Y” is applied as many times as possible to the receive buffer when multipleValues is true, causing a numbered sequence of “arrayA.#” properties to be populated. If it had not been matched successfully at least once, an exception would have been thrown.The number of elements that are captured into the array is stored in a property named “arrayA.length”.
Theprecedingexample captures multiple values into a normal array of properties (thatis, an array indexed by numeric labels). You can also capture multiple values into an associative array of properties (that isan array indexed by string labels instead of a numeric counter).
The following example shows multiple-value property capture into an associative array:
Example of a multiple-value property capture into an associated associated array
<capture buffer="B(.)D(.)F" multipleValues="true" index="{1}">
<property name="arrayB">{2}</property>
</capture>
In thepreceding example, if the receive buffer contains the text ABCDEF\nABXDYF, then the resultis the capture of two properties:
- property named arrayB[C] with value E
- property named arrayB[X] with value Y
The first capture group in the regular expression is used for the array index (as indicated by the indexattribute) and the second (as indicated by the {2} group selector in the <property>) is used as the value.
If the regular expression in the buffer does notmatch successfully at least once, an exception is thrown.
Note
If you see any warnings related to <capture> tags in the
TrueSight Network Automation
log file when the server is starting up or being upgraded, seeProperty capture warnings.
Back to top
Property capture—multiple passes
If theiterVariablesanditerArrayscapture attributes are set, a special “multiple passes” style of capture is performed.
The following example shows a multiple passes property capture:
Example of a multiple passes property capture
<capture buffer="XXX %capture.varA%(.*) %capture.varB% ZZZ"
iterVariables="varA,varB"
iterArrays="arrayA,arrayB">
<property name="property_1">{1}</property>
</capture>
If the current properties include the entries { "arrayA.0”=”A0”, “arrayA.1=”A1”, “arrayA.2”=”A2”, “arrayB.0”=”B0”, “arrayB.1”=”B1”, “arrayB.2”=”B2” }, and the receive buffer contains the text XXX A1 YYY B1 ZZZ, this capture results in “YYY” being assigned to the “property_1” property.
The capture logic in this example makes two passes over the receive buffer. In the first pass, the values from the “%arrayA.0%” and “%arrayB.0%” properties (“A0” and “B0” respectively) are substituted into the “%capture.varA%” and “%capture.varB%” keywords, causing the capture pattern to be “XXX A0 (.*) B0ZZZ” during the first pass.
Because that pattern does not match the receive buffer, you make a second pass. This time the values from the “%arrayA.1%” and “%arrayB.1%” properties (“A1”and “B0” respectively) are substituted into the “%capture.varA%” and “%capture.varB%” keywords, causing the capture pattern to be “XXX A1 (.*) B1ZZZ” during the second pass.
Because that pattern does match the receive buffer, the capture succeeds (capturing the value “YYY”) and you do not attempt any more passes. If the capture does not succeed and you have exhausted the arrays of property values to try, an exception is generated.
The number of comma-delimited labels in theiterVariablesanditerArraysattributes must be the same in order for this logic to work. The first variable initerVariablesis populated by using values from the first array initerArrays, while the second variable is populated by using values from the second array, and so on. Also, the length of each property array specified in theiterArraysattribute must be the same.
Note
If you see any warnings related to <capture> tags in the
TrueSight Network Automation
log file when the server is starting up or being upgraded, seeProperty capture warnings.
Back to top
Property capture warnings
You might see the following warnings in the TrueSight Network Automation log files when the web server is starting up or being upgraded. These result from validation being performed on the <capture> elements that require you to make corrections in your adapters:
Type 1: Appears when buffer contains capture groups, but no <property> elements use them. A sample warning looks like the following:
in capture tag Capture, capture groups are referenced in the property wrappers
but no capture groups are specified in regex buffer
Type 2: Appears when <property> elements specify capture groups, but buffer does not have them defined. A sample warning looks like the following:
in capture tag Capture, capture group <CaptureGroupNumber> is referenced in
the property wrappers but there are only <TotalNumberOfCaptureGroups>
capture groups in regex buffer
These warnings are generated when the device adapters are being loaded from the database into memory, and a<capture>tag within the contents is noticed to be odd. The reason could either be that the tag specifies a capture group in its regex buffer attribute, but then does not use that capture group to populate any properties (Type 1); or the tag specifies to populate properties via capture groups that are not defined in the regex buffer (Type 2).
The following is an example of a capture tag that would generate a Type 1 warning:
<capture buffer="foo (.*) bar">
<property name="myprop">xyz</property>
</capture>
The following is an example of a capture tag that would generate a Type 2 warning:
<capture buffer="foo .* bar">
<property name="myprop">{1}</property>
</capture>
If theskipComponentStringificationproperty is set to true in theglobal.properties.importedfile, then instead of the wordCaptureshown in the Type 1 and Type 2 warnings, the stringified version of theCaptureinstance (its attributes expressed as comma-delimited name=value pairs, enclosed within braces) appears. You should setskipComponentStringificationto false if you see these types of warnings to identify which<capture>tag in the device adapter the warnings are actually about.
Usually, the Type 1 warning indicates a mistake in your adapter. However, it might not be a mistake. It is possible to specify a capture group in the regex buffer purely for matching an ORed combination of two strings, within a larger context. In such a case, use the "?:" qualifier within parentheses to indicate that it is not really a capture group. For example, instead of “aaa (foo|bar) bbb”, specify "aaa (?:foo|bar) bbb"). This avoids the warning that would otherwise be generated.
Back to top
Property assignment
<assign>tags are used to set a property value directly rather than via capturing text in the device response stream. The value assigned is either specified explicitly, or specified as a BeanShell script (seewww.beanshell.org) which is Java code evaluated at run time.
The following example of an explicit assignment assigns the string “value_1” to the connection property “property_1.” You can embed a reference to another property in the value attribute if desired (for example, value=”%property_2%”):
<assign property="property_1" value="value_1"/>
The following example shows a script-based assignment:
Example of a script-based assignment
<assign property="property_1">
import foo.Bar;
String string_1 = Bar.transmogrify("%property_2%");
String value = string_1 + "%property_3%";
</assign>
This script concatenates a transmogrified property_2 value with property_3 and stores the result in a special local variable namedvalue, which is used to assign property_1. Youmustset aStringvariable calledvalueto hold the result of your assignment calculations. The contents ofvaluefinally become the property value.
The code within the <assign> container in this example is a Java snippet. Any datatype supported by Java is supported in the snippet. These datatypes include the Java primitive datatypes (such as int and float), arrays, and classes defined in the Java JDK (such as String.) Because it is a Java snippet, you can define or import any data type that you need in the snippet.
The<assign>tag supports the following optional attributes:append,encodeForUrl, andomitEOL. Whenappendis set to true (defaults to false), the string value assigned to the property is appended to any existing string value. By default, a newline character is added before appending to the existing value, unlessomitEOLis true (defaults to false). WhenencodeForUrlis true, the valueis massaged to turn embedded spaces into “+” signs for instance, in order to make the value safe for use in the URL of a<get>tag within an<httpInteraction>.
Note
In the preceding example, TrueSight Network Automation executes a method on a sample foo.Bar Java class. This Java class does not exist in the standard libraries that are part of the Java SE system. Therefore, for this example to work, a jar file containing the foo.Bar class needs to be found in the classpath of the TrueSight Network Automation device agent which is executing the device command. For the local device agent, you can place the jar file in the BCAN_HOME\tomcat\endorsed\lib directory on the application server. For a remote device agent, you can place the jar file in the BCAN_HOME\installed\lib directory on the remote device agent. Alternately, you can place the jar file in the application server classpath as described earlier, and then modify the agentJarDownloads entry in the BCAN_DATA\global.properties file to add a reference to the new jar file, so that it gets automatically distributed and made available to all the remote device agents.
Back to top
Conditions
Device commands can contain not only simple sequences of interactions, but also conditions andloops.
A condition can be used to specify a block of interactions that should only be executed if the condition's test expression evaluates to true. It can also contain other nested device conditions or loops.
The following example shows a device command containing a condition:
Example of a condition
<deviceCommand>
<condition test = "-EXISTS- property_1">
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_C</response>
</interaction>
</condition>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<condition> | if property property_1 is set then |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C found in read buffer else, do nothing endif |
The test expression is parsed and evaluated against the current set of properties. Boolean and string comparison operators and arithmetic functions are supported. See Common-concepts-and-XML-elements for an overview of the syntax.
Any grammar syntax violations present in your condition tests are reported when you import the device adapter.
Back to top
Response properties
The<response>elements can include a property attribute. When multiple<response>elements are present, only the property of the firstresponse that is matched is set, with responses tested in the order they are coded. This allows you to handle different responses emitted under different operating conditions. This also allows you to handle different models or operating system versions, which can respond in multiple ways to the same command.
The following example shows a device command containing an interaction with response properties:
Example of response properties
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response property=cmd.property_1>text_C</response>
<response property=cmd.property_2>text_D</response>
</interaction>
<condition test="-EXISTS- cmd.property_1">
<interaction>
<prompt>text_C</prompt>
<command>text_E</command>
<response>text_F</response>
</interaction>
</condition>
<condition test="-EXISTS- cmd.property_2">
<interaction>
<prompt>text_D</prompt>
<command>text_G</command>
<response>text_H</response>
</interaction>
</condition>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C or text_D found in the read buffer if read buffer contains text_C then set cmd.property_1 to true else if read buffer contains text_D set cmd.property_2 to true endif |
<condition> | if cmd.property_1 property is set then |
<prompt> | read device output until text_C found in the read buffer |
<command> | clear read buffer, send text_E to the device |
<response> | read device output until text_F found in the read buffer endif |
<condition> | if cmd.property_2 property is set then |
<prompt> | read device output until text_D found in the read buffer |
<command> | clear read buffer, send text_G to the device |
<response> | read device output until text_H found in read buffer endif |
Back to top
Error properties
The<error>elements can also include a property attribute. This element is used as a mechanism to allow handling for errors which are logically recoverable. If the error element is matched, instead of aborting execution via an exception, a property is set, which can be handled in the subsequent device interactions.
Errors take precedence over responses. If there are multiple <error> elements, they are checked in the order they are coded and the checking stops once a match is made.
The following example shows a device command containing an interaction with error properties:
Example of error properties
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response property="cmd.property_1">text_C</response>
<error property="cmd.property_2">text_D</error>
<capture>
<property name="fileContents"/>
</capture>
</interaction>
<condition test="-EXISTS- cmd.property_1">
<interaction>
<prompt>text_C</prompt>
<command>text_E</command>
<response>text_F</response>
</interaction>
</condition>
<condition test="-EXISTS- cmd.property_2">
<interaction>
<prompt>text_D</prompt>
<command>text_G</command>
<response>text_H</response>
</interaction>
</condition>
<assert test="-NOT- -EXISTS- cmd.property_2" onFailure="abort">
Error occurred while processing command text_B
</assert>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C or text_D found in the read buffer if read buffer contains text_D then set cmd.property_2 to true else if read buffer contains text_C then set cmd.property_1 to true set property fileContents to the captured output of the command endif |
<condition> | if cmd.property_1 property is set then |
<prompt> | read device output until text_C found in the read buffer |
<command> | clear read buffer, send text_E to the device |
<response> | read device output until text_F found in the read buffer endif |
<condition> | if cmd.property_2 property is set then |
<prompt> | read device output until text_D found in the read buffer |
<command> | clear read buffer, send text_G to the device |
<response> | read device output until text_H found in the read buffer endif |
<assert> | if cmd.property_2 property is set then throw an exception with the specified error message endif |
When such a recoverable error occurs, any<capture>tag that is specified is skipped. This capture skipping is the only justification for supporting error properties separately from response properties. Note also that errors are matched before responses.
Since the normal error handling is bypassed when you include a property setting, you should ensure the occurrence of the error is reported all the way back to the user. An <assert> statement can be used for that purpose.
Back to top
Retry
The<error>element can include aretryflag (defaults to false). This flag is used as a mechanism to allow retrying (once) the execution of the enclosing devicecommandif a trivial and potentially recoverable error has occurred (for instance, concurrency collision with another user on the same device or a file system being busy). Aretryattribute causes the command to be retried once again if it initially matches the <error> string.
The following example shows a device command containing an interaction with the retry attribute:
Example of the retry attribute
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_C</response>
</interaction>
<interaction>
<prompt>text_C</prompt>
<command>text_D</command>
<response>text_E</response>
<error retry="true">text_F</error>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C found in the read buffer |
<prompt> | read device output until text_C found in the read buffer |
<command> | clear read buffer, send text_D to the device |
<response> | read device output until text_E or text_F found in the read buffer if read buffer contains text_F then if first execution attempt then pause re-execute this device command from the beginning else throw exception endif else if read buffer contains text_E success, proceed to next step endif |
The retry flag behaves differently depending on if the device command is the login sequence or not. If the login sequence encounters an error with a retry set to true, then the connection to the device is cycled and the system re-logs in to the device to start clean. If the device command is not the login sequence, the retry starts back at the top of the device command (does not cycle the device connection).
Back to top
Disconnect
An interaction can include adisconnectattribute. The attribute can have a value of always, sometimes, or never (default). If there is a chance of the device disconnecting after the command is sent, such an interaction should use this attribute. For thelogoutandrebootcommands, the command that finally logs out or reboots should always include disconnect="always". For some devices, deploying a configuration or an operating system image or performing a commit causes the device to reboot as a side effect as well, so include disconnect="always".
Use disconnect="sometimes" when a command might disconnect or might present additional prompts depending on the state of the device. For example, a reboot request might proceed immediately if there are no pending changes, but it will prompt you if there are pending unsaved changes. Using sometimes tells the system that a disconnect is expected, but not required.
The default of disconnect="never" means that losing the connection to the device is to be treated as an error.
The following example shows a device command containing an interaction with the disconnect attribute:
Example of the disconnect attribute
<deviceCommand>
<interaction disconnect="always">
<prompt>text_A</prompt>
<command>text_B</command>
<error>text_C</error>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C found in the read buffer if read buffer contains text_C then throw exception close connection to the device if it is still open log in again if needed |
Explicitly declaring when a disconnection is expected is only necessary because some devices do not close their sockets when they logically disconnect. When the disconnect value is always or sometimes, the connection always times out waiting for the response of the interaction within 15 seconds if necessary, to avoid a potentially hung socket read.
If the disconnect value is sometimes, enforcement of this timeout is taken as an indication that a logical disconnect occurred; otherwise, the system assumes that the connection is active.
If a disconnection has occurred, the system considers this to be expected, closes the socket, and re-logs into the device for the reboot, commit, OS image deploy, configuration deploy commands, and custom actions that are not inspection-only.
Back to top
Loops - Types
A<loop>contains other device interactions and other nested loops or conditions. These loops can be either in the style of aforloop, awhileloop, adoloop, or aforeachloop.
For loop
The following example shows a device command with a for loop:
Example of a 'for' loop
<deviceCommand>
<loop counter="i" start="1" stop="2">
<interaction>
<prompt>text_A</prompt>
<command>%loop.i%</command>
<response>text_B</response>
</interaction>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | for (loop.i = 1, loop.i <= 2, loop.i++) do |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send value of the property loop.i to the device |
<response> | read device output until text_B found in the read buffer endloop |
A for loop iterates using a counter. You choose the name of the counter variable, its start value, and its maximum or stop value.
The iteration counter property “i” is automatically prefixed as “loop.i” when it is used. This is the default prefix. You can specify a non-default prefix via thenamespaceattribute. Properties of the form namespace.* are automatically removed after the loop terminates.
while loop
The following example shows a device command with a while loop:
Example of a 'while' loop
<deviceCommand>
<loop condition="-NOT- (-EXISTS- loop.property_1)">
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response property="loop.property_1">text_C</response>
<response>text_D</response>
</interaction>
<condition test="-NOT- (-EXISTS- loop.property_1)">
<sleep timeSeconds="1"/>
</condition>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | while loop.property_1 is not set do |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C or text_D found in the read buffer if read buffer contains text_C then set loop.property_1 to true else if read buffer contains text_D then success, proceed to next step endif |
<condition> | if loop.property_1 is not set then sleep one second. to slow down the polling loop endif endloop |
Include a <sleep> when polling the device, to prevent the system from running the loop as fast as it can. Not pausing somewhere inside of a polling loop can cause a huge amount of data to end up in the transcript, as well as consume the device agent's host CPU.
do loop
The following example shows a device command with a do loop:
Example of a 'do' loop
<deviceCommand>
<loop>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response property=loop.property_1>text_C</response>
<response>text_D</response>
</interaction>
<break condition="-EXISTS- loop.property_1"/>
<sleep timeSeconds="1"/>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | do |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C or text_D found in the read buffer if read buffer contains text_C then set loop.property_1 to true else if read buffer contains text_D then success, proceed to next step endif |
<break> | if loop.property_1 property is set then terminate loop endif |
<sleep> | pause for one second, to slow down the polling loop endloop |
You use a<break>tag to allow the loop to terminate after the text_C response is found.
foreach loop
TrueSight Network Automation supports the following variations of theforeach loop:
- First variation involves looping over the values in successive properties in a non-associative properties array (for example, list.0, list.1, list.2, ...).
- Second variation involves looping over the values in successive properties in an associative properties array (for example, list[A], list[B], list[C], ...).
- Third variation involves looping over successive embedded values within a delimited property.
foreach loop - variation 1
The following example shows a device command with a foreach loop that iterates over a non-associative properties array:
Example of first variation of a 'foreach' loop
<deviceCommand>
<loop variable="entry" input="list">
<interaction>
<prompt>text_A</prompt>
<command>%loop.entry%</command>
<response>text_B</response>
</interaction>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | foreach loop.entry in list.0 list.1 list.2 … |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send the value of property loop.entry to the device |
<response> | read device output until receive text_B endloop |
It is assumed that the properties, list.0, list.1, list.2, and so on are already populated (such as from a multi-value capture). On each iteration, the loop.entry property is assigned the value of the list.n property, where n is the loop iteration number starting from 0.
This foreach style of loop is used during tunneled file transfers, to transfer a configuration file by sending it line by line to the device.
foreach loop - variation 2
The following example shows a device command with a foreach loop that iterates over an associative properties array:
Example of second variation of a 'foreach' loop
<deviceCommand>
<loop variable="entry" input="list" associativeFlag="true">
<interaction>
<prompt>text_A</prompt>
<command>%loop.entry%</command>
<response>text_B</response>
</interaction>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | foreach loop.entry in list[A] list[B] list[C] … |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send the value of property loop.entry to the device |
<response> | read device output until receive text_B endloop |
It is assumed that the properties, list[A], list[B], list[C], and so on are already populated (such as from a multi-value capture). On each iteration, the loop.entry property is assigned the value of the next entry in the list associative properties array. Note that the order in which it iterates over the entries in the associative properties array is random.
foreach loop - variation 3
The following example shows a device command with a foreach loop that iterates over the values embedded within a delimited property:
Example of third variation of a 'foreach' loop
<deviceCommand>
<loop variable="entry" input="property_x" inputSeparator=":">
<interaction>
<prompt>text_A</prompt>
<command>%loop.entry%</command>
<response>text_B</response>
</interaction>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | foreach loop.entry in property_x_first_value property_x_second_value … |
<prompt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send the value of property loop.entry to the device |
<response> | read device output until receive text_B endloop |
It is assumed here that property_x contains multiple embedded values, each delimited by a colon. For example, it might contain the string, a:b:c:d, in which case the loop.entry property is assigned the values, a, b, c, and d on successive iterations of the loop.
Back to top
Loops - Multiple Arrays
New in 8.9.03You can use <loop> to iterate over multiple arrays simultaneously.
The following example shows a device command with aforloop that iterates over the multiple property arrays simultaneously.
<deviceCommand>
<loop counter="i" start="0" stop="%listA.length% -MINUS- 1">
<assign property="loop.entryA" valueOf="listA.%loop.i%"/>
<assign property="loop.entryB" valueOf="listB.%loop.i%"/>
<interaction>
<prompt>text_A</prompt>
<command>%loop.entryA% %loop.entryB%</command>
<response>text_B</response>
</interaction>
</loop>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<loop> | for (loop.i = 0, loop.i < length of listA property array, loop.i++) do |
<assign> | assign value of loop.i entry from listA property array to loop.entryA property |
<assign> | assign value of loop.i entry from listB property array to loop.entryB property |
<promopt> | read device output until text_A found in the read buffer |
<command> | clear read buffer, send value of the properties loop.entryA and loop.entryB to the device |
<response> | read device output until text_B found in the read buffer endloop |
This example assumes that the listA and listB property arrays were populated earlier (for example, via a multi-value capture), and are of equal length. This example is iterating over both the listA and listB property arrays simultaneously. To implement this, a "for" style loop is used to iterate over index values, and the assign tag is used with the valueOf attribute to fetch successive entries from both arrays using those index values.
Assertions
An<assert>tag can be inserted anywhere in an interaction. If the conditional expression of the assertion evaluates to false, an exception is generated and the device command execution ends immediately.
AnonFailureattribute can be used to specify skip, warning, or abort, to control the type of exception thrown, and the type of handling performed, ultimately bubbling up into the job completion status.
A skip causes the device action to be marked as skipped in the action's results. A warning causes the action to be marked as succeeded with warning. An abort causes the action to be marked as failed.
The following example shows a device command with the assert statement:
Example of an 'assert' condition
<deviceCommand>
<assert condition="%property_1% -EQ- value_1" onFailure="skip">
message
</assert>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<assert> | if value of the property_1 property equals value_1 then throw skip exception containing "message" endif |
TheminVersionattribute available in the<deviceCommand>tag functions the same way as an assertion, which tests the discovered version against the specified minimum version and throws a skip exception on failures. It is simply a convenient shorthand for a common type of assertion logic.
Back to top
Regular expression support
Device interactions can also include regular expressions in the<prompt>,<response>, and<error>elements. These regular expressions are useful when you are not sure of the exact response from the device, or you want to match on multiple variations of similar responses. In the<interaction>tag, you must set the regex attribute to true to use this feature. See Regular expressions for an introduction to regular expression syntax.
The following example shows a device command containing an interaction with regular expressions:
Example of a regular expression
<deviceCommand>
<interaction regex="true">
<prompt>A.*B</prompt>
<command>text_X</command>
<response>C.*D</response>
<error>E.*F</error>
</interaction>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until regex A.*B is matched in the the read buffer |
<command> | clear read buffer, send text_X to the device |
<response> | read device output until regex C.*D or E.*F is matched in the read buffer if regex E.*F is matched then throw exception endif |
Back to top
Jitter time
Jitter time controls how long the interpreter reading device output lingers while gathering bytes from the device before it checks whether what it has received so far matches the prompt or response string(s) it is currently expecting. In some scenarios, the default jitter time of 10 milliseconds might be unsatisfactory. When the expected string is loosely specified (for example, a “.+” regular expression pattern), it might be problematic if the interpreter tries to match the expected string before the device has completely finished sending all the bytes involved. Specifying the expected string loosely is generally not advisable for this reason, but sometimes due to the complexities of the device, it might be unavoidable.
To work around this problem, you can temporarily establish a non-default jitter time. The<prompt>tag supports ajitterMilliSecondsattribute, which sets the interpreter jitter time to the specified value while it is matching that particular prompt, after which it is reset to the default value. The<interaction>tag also supports aresponseJitterMilliSecondsattribute, which sets the interpreter jitter time to the specified value while it is matching that interaction’s responses/errors, after which it is reset to the default value.
If you examine a transcript for a failed action and find that partial chopped offresponses appear during an interaction with such a loosely specified response, you can try increasing the jitter setting on that interaction. If this fixes the problem, you should then consider setting the jitter on that interaction just a bit higher, since you have clearly found a command whose output is jittery. If the device were to slow down just a bit more (such as when it gets a more busy), you might run into the problem again. Increased jitter slows down the interaction, so it should be done only when necessary.
Back to top
Stutter time
Stutter time controls the inter-character pause when sending commands to a device. The system sends one character, pauses, sends the next character, pauses, and so on until the command is complete. The pauses help the computer that is talking to the device appear more like a human who is typing at a keyboard, who takes natural pauses between keystrokes. The device's command line interpreter software may have been developed with a human in mind. It might run at a lower priority when the device is busy. It might simply be inefficient at reading what is typed (since there is no need to be efficient). It might be auto-completing at each character, busily looking up what might come next and neglecting to keep up with the input.
When a command is sent to a device as fast as a computer can send it, some devices can miss characters and garble the command. This can be observed in the transcript when what appears is what the device echoes out as it reads the command and garbles it. The device may have complained that the command is invalid, though you may not have included an <error> tag to catch it, causing the action to succeed when it actually failed.
Adding a stutter slows down the input to the device so that the device can handle it. Since this phenomenon is widely prevalent, the default stutter is set to 50 milliseconds, derived from thedeviceCommandStutterMilliseconds property in the global.properties.imported file. The <command> element supports astutterMilliSeconds attribute to allow you to override the default on a per-command basis. You can set the stutter to 0 to disable it.
Note that coding in a longer stutterintroduces a fixed delay into your interactions, a delay incurred every time that command is executed. The delay is also based on the length of the command; the longer the command, the longer the delay. Use caution when overriding the default stutter, be sensitive to the frequency of use of the command, and be conservative in how large you make it.
Back to top
Sensitive commands
The<command>tag supports asensitiveflag. If set to true, any error, exception, or debug trace generated while executing the interaction replaces the command text with {HIDDEN}. This is typically used in interactions that send passwords to the device to mask such sensitive information from users.
The following example shows an interaction with the sensitive flag:
Example of the sensitive flag
<interaction>
<prompt>%prompt%</prompt>
<command sensitive="true">%privPassword%</command>
<response>#</response>
</interaction>
You can hide part of the command line (instead of the entire command line) by using thesensitiveattribute in conjunction with thesensitivePhraseattribute. In the following example, only the %ftpPassword% part of the command is replaced with {HIDDEN} in the transcript output, the rest of the command is displayed as clear text. Note how the ftpPassword keyword is used in both the sensitivePhrase and in the command text. Keyword substitution occurs in both places.
Example of the sensitivePhrase attribute
<interaction>
<prompt>%prompt%</prompt>
<command sensitive="true" sensitivePhrase="%ftpPassword%">
copy running-config ftp://%ftpUsername%:%ftpPassword%@%address%
</command>
<response>>%prompt%</response>
</interaction>
Back to top
Finally Block
You can add an optional<finallyBlock>tag at the bottom of the<deviceCommand>tag to encapsulate the logic that you want to be executed after all the normal logic within the device command is executed. The<finallyBlock>logic is executed regardless of whether the normal logic executed successfully or unsuccessfully. Use a <finallyBlock> to perform any necessary cleanup functions (such as deleting temporary files) which you want to do regardless of whether or not an error condition was encountered.
The <finally> block is limited to the following child elements:
- <assert>
- <assign>
- <condition>
- <httpInteraction>
- <interaction>
- <loop>
- <sleep>
The following example shows a device command containing the<finallyBlock>tag:
Example of the <finallyBlock> tag
<deviceCommand>
<interaction>
<prompt>text_A</prompt>
<command>text_B</command>
<response>text_C</response>
</interaction>
<finallyBlock>
<interaction>
<command>text_D</command>
</interaction>
<finallyBlock>
</deviceCommand>
The preceding example executes the following logic:
Tag | Execution order |
---|---|
<prompt> | read device output until text_A found in the read buffer or the interaction times out if the interaction timed out then throw exception endif |
<command> | clear read buffer, send text_B to the device |
<response> | read device output until text_C found in read buffer or the interaction times out if interaction timed out then throw exception endif |
<finally> | catch any exception that was thrown |
<command> | clear read buffer, send text_D to the device if exception was caught rethrow it, to report it back to the user endif |
In this sequence, the final interaction to send text_D is guaranteed to execute last, regardless of whether the preceding interaction succeeded or timed out.
Back to top
Sleep
You can insert a<sleep>tag anywhere within an interaction. ThetimeSecondsattribute specifies the duration of the sleep period, in seconds. This mechanism is helpful within a loop where you must poll the device for the transition to some expected new state.
The following example inserts a sleep period of five seconds:
Example of the sleep tag
<deviceCommand>
<sleep timeSeconds="5">
</deviceCommand>
Back to top
Auto discovery
The user can request the system to auto discover the device's access mode, login credentials, and file transfer mode. The discovery of access mode and login credentials is performed in Java logic, but the discovery of the file transfer mode requires logic in the device type adapter when the device type supports both FTP and SCP. (TFTP is not part of file transfer mode discovery.)
When the user has the device set to auto transfer mode, the system sets the discoverTransferMode property to true. The device type adapter can then check that property during the discover-core device command and set the disc.supportsScp and/or disc.supportsFtp properties in response. Some devices might simply always support those transfer modes, so no conditional logic is needed beyond the check on discoverTransferMode; hardcode setting the disc.supports* properties. But if there is variation in what is supported (for example if SCP is supported only by the right kind of operating system),then logic is required to set the properties accurately.
The following example shows how this can be done, based on the Cisco IOS device type adapter. When you type copy ?, the device emits something like this:
bcan-cisco2600-01#copy ?
/erase Erase destination file system.
/noverify Don't verify image signature before reload.
/verify Verify image signature before reload.
flash: Copy from flash: file system
ftp: Copy from ftp: file system
http: Copy from http: file system
https: Copy from https: file system
null: Copy from null: file system
nvram: Copy from nvram: file system
running-config Copy from current system configuration
scp: Copy from scp: file system
startup-config Copy from startup configuration
system: Copy from system: file system
tftp: Copy from tftp: file system
Here is how you would use this output to set the associated properties:
Example of file transfer mode discovery
<deviceCommand>
<guid>1E91FAD6-FBB7-5D7C-120F-ABD77583A086</guid> <!-- discover core -->
<condition test="%discoverTransferMode% -EQ- true">
<!-- device has file transfer mode set to auto -->
<interaction>
<!-- copy ? emits help for the copy command, which shows the file transfer modes it supports -->
<command>copy ?</command>
<response>%prompt%</response>
<capture buffer="scp" ignoreFailure="true">
<property name="disc.supportsScp">true</property>
</capture>
<capture buffer="ftp(?<!tftp)" ignoreFailure="true">
<!-- match ftp only, don't match tftp -->
<property name="disc.supportsFtp">true</property>
</capture>
</interaction>
</condition>
Back to top
Reusable responses and errors
When coding sequences of similar commands (such as transferring files in different transfer modes), you might find that you are repeating lists of identical responses or identical errors. For example, sending a file or setting a file can emit the same errors referring to unresolved host names or invalid routes, whether you are using TFTP, FTP, or SCP. Rather than repeating this list for every trail (and the image file), you can declare them once and reuse them.
In the following code snippets, reusable blocks are declared in the header section of the device type adapter. Then within the device command sequence of interactions, the previously declared response and error blocks are referred back to, where the command could emit the same set of outputs, among other responses and errors. Anywhere the reusable block is referred to, the system plugs in the contents of the declared block.
Example of reusable blocks
<responseBlockDeclarations>
<responseBlockDeclaration name="common file transfer successes">
<response>file is uploaded</response>
<response>file is downloaded</response>
<response>file is copied</response>
</responseBlockDeclaration>
</responseBlockDeclarations>
<errorBlockDeclarations>
<errorBlockDeclaration name="common file transfer errors">
<error>Access is denied</error>
<error>cannot find the file specified</error>
<error>User cannot log in</error>
<error>Connection timed out</error>
<error>Incomplete command</error>
<error retry="true">Filesystem busy</error>
</errorBlockDeclaration>
</errorBlockDeclarations>
...
<interaction>
<command>sensitive="true" sensitivePhrase="%ftpPassword%">
copy running-config ftp %address% %cmd.path% %ftpUsername% %ftpPassword%
</command>
<responseBlockReference name="common file transfer successes"/>
<errorBlockReference name="common file transfer errors"/>
<error>Write failed</error>
</interaction>
...
<interaction>
<command sensitive="true" sensitivePhrase="%ftpPassword%">
copy ftp running-config %address% %cmd.path% %transferFilename% %ftpUsername% %ftpPassword%
</command>
<response>file contains errors</response>
<responseBlockReference name="common file transfer successes"/>
<errorBlockReference name="common file transfer errors"/>
</interaction>
Back to top