Examples of CLI-based XML elements
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
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.
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:
<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 exception to trigger error handling else if read buffer contains text_H then throw exception to 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.
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:
<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.
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:
<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) if read buffer contains text_A then |
<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. Loops and 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.
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. See Common concepts and XML elements for 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 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 |
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 |
defValue | String containing the default value to assign to the property Used only when |
eagerPrefix |
Default value is |
eagerSuffix |
Default value is |
failsafe |
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 |
ignoreFailure |
Default value is false. |
ignorePrefix |
Default value is false. |
ignoreSuffix |
Default value is false. |
includePrefix |
Default value is false. |
includeSuffix |
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 |
Default value is |
omitEOL |
Default value is |
optionalPrefix |
Default value is |
optionalSuffix |
Default value is |
prefix | String or regular expression containing the delimiter that starts the text to be examined for storage into property values. If the 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 Default is to examine the command output up to but not including the matched |
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. |
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
andsuffix
related attributes to define the delimiters, and thebuffer
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:
<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 includePrefix
or includeSuffix
or 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.
The optionalPrefix
and optionalSuffix
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.
The eagerPrefix
and eagerSuffix
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 for eagerPrefix
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 for eagerSuffix
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.
An append
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 an omitEOL
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
<capture>
tags in the TrueSight Network Automation log file when the server is starting up or being upgraded, see Property capture warnings.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:
<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.
The ignoreFailure
and defValue
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
<capture>
tags in the TrueSight Network Automation log file when the server is starting up or being upgraded, see Property capture warnings.Property capture—xpath
You can specify an xpath
attribute 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:
<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 the text_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 portion that 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
<capture>
tags in the TrueSight Network Automation log file when the server is starting up or being upgraded, see Property capture warnings.Property capture—multiple values
If the multipleValues
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:
<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”.
The preceding example captures multiple values into a normal array of properties (that is, an array indexed by numeric labels). You can also capture multiple values into an associative array of properties (that is an array indexed by string labels instead of a numeric counter).
The following example shows multiple-value property capture into an associative array:
<capture buffer="B(.)D(.)F" multipleValues="true" index="{1}">
<property name="arrayB">{2}</property>
</capture>
In the preceding example, if the receive buffer contains the text ABCDEF\nABXDYF
, then the result is 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 index
attribute) 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 not match successfully at least once, an exception is thrown.
Note
<capture>
tags in the TrueSight Network Automation log file when the server is starting up or being upgraded, see Property capture warnings.Property capture—multiple passes
If the iterVariables
and iterArrays
capture attributes are set, a special “multiple passes” style of capture is performed.
The following example shows 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 the iterVariables
and iterArrays
attributes must be the same in order for this logic to work. The first variable in iterVariables
is populated by using values from the first array in iterArrays
, 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 the iterArrays
attribute must be the same.
Note
<capture>
tags in the TrueSight Network Automation log file when the server is starting up or being upgraded, see Property capture warnings.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, butbuffer
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 the skipComponentStringification
property is set to true in the global.properties.imported file, then instead of the word Capture
shown in the Type 1 and Type 2 warnings, the stringified version of the Capture
instance (its attributes expressed as comma-delimited name=value pairs, enclosed within braces) appears. You should set skipComponentStringification
to 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.
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 (see www.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:
<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 named value
, which is used to assign property_1. You must set a String
variable called value
to hold the result of your assignment calculations. The contents of value
finally 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
, and omitEOL
. When append
is 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, unless omitEOL
is true (defaults to false). When encodeForUrl
is true, the value is 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.
Conditions
Device commands can contain not only simple sequences of interactions, but also conditions and loops.
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:
<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.
Response properties
The <response>
elements can include a property attribute. When multiple <response>
elements are present, only the property of the first response 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:
<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 |
| 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 |
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:
<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 |
| 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.
Retry
The <error>
element can include a retry
flag (defaults to false). This flag is used as a mechanism to allow retrying (once) the execution of the enclosing device command if 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). A retry
attribute 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:
<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).
Disconnect
An interaction can include a disconnect
attribute. 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 the logout and reboot commands, 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:
<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.
Loops - Types
A <loop>
contains other device interactions and other nested loops or conditions. These loops can be either in the style of a for loop, a while loop, a do loop, or a foreach loop.
For loop
The following example shows a device command with 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 the namespace
attribute. 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:
<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:
<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 the foreach 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:
<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:
<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:
<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.
Loops - Multiple Arrays
NEW IN 8.9.03 You can use <loop>
to iterate over multiple arrays simultaneously.
The following example shows a device command with a for loop 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.
An onFailure
attribute 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:
<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 |
The minVersion
attribute 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.
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:
<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 |
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 a jitterMilliSeconds
attribute, 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 a responseJitterMilliSeconds
attribute, 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 off responses 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.
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 the deviceCommandStutterMilliseconds property in the global.properties.imported file. The <command>
element supports a stutterMilliSeconds
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 stutter introduces 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.
Sensitive commands
The <command>
tag supports a sensitive
flag. 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:
<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 the sensitive
attribute in conjunction with the sensitivePhrase
attribute. 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.
<interaction>
<prompt>%prompt%</prompt>
<command sensitive="true" sensitivePhrase="%ftpPassword%">
copy running-config ftp://%ftpUsername%:%ftpPassword%@%address%
</command>
<response>>%prompt%</response>
</interaction>
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:
<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.
Sleep
You can insert a <sleep>
tag anywhere within an interaction. The timeSeconds
attribute 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:
<deviceCommand>
<sleep timeSeconds="5">
</deviceCommand>
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:
<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>
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.
<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>
Comments
Log in or register to comment.