@ -21,37 +21,53 @@ DOCUMENTATION = """
module : iosxr_command
module : iosxr_command
version_added : " 2.1 "
version_added : " 2.1 "
author : " Peter Sprygada (@privateip) "
author : " Peter Sprygada (@privateip) "
short_description : Run arbitrary commands on ios devices .
short_description : Run commands on remote devices running Cisco iosxr
description :
description :
- Sends arbitrary commands to an IOSXR node and returns the results
- Sends arbitrary commands to an iosxr node and returns the results
read from the device . This module includes an
read from the device . This module includes an
argument that will cause the module to wait for a specific condition
argument that will cause the module to wait for a specific condition
before returning or timing out if the condition is not met .
before returning or timing out if the condition is not met .
- This module does not support running commands in configuration mode .
Please use M ( iosxr_config ) to configure iosxr devices .
extends_documentation_fragment : iosxr
extends_documentation_fragment : iosxr
options :
options :
commands :
commands :
description :
description :
- List of commands to send to the remote ios device over the
- List of commands to send to the remote ios xr device over the
configured provider . The resulting output from the command
configured provider . The resulting output from the command
is returned . If the I ( wait for) argument is provided , the
is returned . If the I ( wait _ for) argument is provided , the
module is not returned until the condition is satisfied or
module is not returned until the condition is satisfied or
the number of ret ires as expired .
the number of ret ries h as expired .
required : true
required : true
wait for:
wait _ for:
description :
description :
- List of conditions to evaluate against the output of the
- List of conditions to evaluate against the output of the
command . The task will wait for a each condition to be true
command . The task will wait for each condition to be true
before moving forward . If the conditional is not true
before moving forward . If the conditional is not true
within the configured number of retries , the task fails .
within the configured number of retries , the task fails .
See examples .
See examples .
required : false
required : false
default : null
default : null
aliases : [ ' waitfor ' ]
version_added : " 2.2 "
match :
description :
- The I ( match ) argument is used in conjunction with the
I ( wait_for ) argument to specify the match policy . Valid
values are C ( all ) or C ( any ) . If the value is set to C ( all )
then all conditionals in the wait_for must be satisfied . If
the value is set to C ( any ) then only one of the values must be
satisfied .
required : false
default : all
choices : [ ' any ' , ' all ' ]
version_added : " 2.2 "
retries :
retries :
description :
description :
- Specifies the number of retries a command should by tried
- Specifies the number of retries a command should by tried
before it is considered failed . The command is run on the
before it is considered failed . The command is run on the
target device every retry and evaluated against the
target device every retry and evaluated against the
waitfor conditions .
I( wait_ for) conditions .
required : false
required : false
default : 10
default : 10
interval :
interval :
@ -65,31 +81,47 @@ options:
"""
"""
EXAMPLES = """
EXAMPLES = """
# Note: examples below use the following provider dict to handle
- iosxr_command :
# transport and authentication to the node.
commands :
vars :
- show version
cli :
register : output
host : " {{ inventory_hostname }} "
username : root
- iosxr_command :
password : root
tasks :
- name : run show version on remote devices
iosxr_command :
commands : show version
provider " {{ cli }} "
- name : run show version and check to see if output contains iosxr
iosxr_command :
commands : show version
wait_for : result [ 0 ] contains IOS - XR
provider " {{ cli }} "
- name : run multiple commands on remote nodes
iosxr_command :
commands :
commands :
- show version
- show version
waitfor :
- show interfaces
- " result[0] contains 6.0.0 "
provider " {{ cli }} "
- iosxr_command :
- name : run multiple commands and evaluate the output
iosxr_command :
commands :
commands :
- show version
- show version
- show interfaces
- show interfaces
waitfor :
wait _ for:
- " result[1] contains MgmtEth0/0/CPU0/0 "
- result [ 0 ] contains IOS - XR
- " result[0] contains 6.0.0 "
- result [ 1 ] contains Loopback0
provider : " {{ cli }} "
"""
"""
RETURN = """
RETURN = """
stdout :
stdout :
description : t he set of responses from the commands
description : T he set of responses from the commands
returned : always
returned : always
type : list
type : list
sample : [ ' ... ' , ' ... ' ]
sample : [ ' ... ' , ' ... ' ]
@ -101,78 +133,105 @@ stdout_lines:
sample : [ [ ' ... ' , ' ... ' ] , [ ' ... ' ] , [ ' ... ' ] ]
sample : [ [ ' ... ' , ' ... ' ] , [ ' ... ' ] , [ ' ... ' ] ]
failed_conditions :
failed_conditions :
description : the conditionals that failed
description : The list of conditionals that have failed
retur ed: failed
retur n ed: failed
type : list
type : list
sample : [ ' ... ' , ' ... ' ]
sample : [ ' ... ' , ' ... ' ]
"""
"""
from ansible . module_utils . basic import get_exception
from ansible . module_utils . netcli import CommandRunner
from ansible . module_utils . netcli import AddCommandError , FailedConditionsError
from ansible . module_utils . iosxr import NetworkModule , NetworkError
import time
VALID_KEYS = [ ' command ' , ' output ' , ' prompt ' , ' response ' ]
import shlex
import re
INDEX_RE = re . compile ( r ' ( \ [ \ d+ \ ]) ' )
def to_lines ( stdout ) :
def iterlines ( stdout ) :
for item in stdout :
for item in stdout :
if isinstance ( item , basestring ) :
if isinstance ( item , basestring ) :
item = str ( item ) . split ( ' \n ' )
item = str ( item ) . split ( ' \n ' )
yield item
yield item
def parse_commands ( module ) :
for cmd in module . params [ ' commands ' ] :
if isinstance ( cmd , basestring ) :
cmd = dict ( command = cmd , output = None )
elif ' command ' not in cmd :
module . fail_json ( msg = ' command keyword argument is required ' )
elif cmd . get ( ' output ' ) not in [ None , ' text ' ] :
module . fail_json ( msg = ' invalid output specified for command ' )
elif not set ( cmd . keys ( ) ) . issubset ( VALID_KEYS ) :
module . fail_json ( msg = ' unknown command keyword specified. Valid '
' values are %s ' % ' , ' . join ( VALID_KEYS ) )
yield cmd
def main ( ) :
def main ( ) :
spec = dict (
spec = dict (
commands = dict ( type = ' list ' ) ,
# { command: <str>, output: <str>, prompt: <str>, response: <str> }
waitfor = dict ( type = ' list ' ) ,
commands = dict ( type = ' list ' , required = True ) ,
wait_for = dict ( type = ' list ' , aliases = [ ' waitfor ' ] ) ,
match = dict ( default = ' all ' , choices = [ ' all ' , ' any ' ] ) ,
retries = dict ( default = 10 , type = ' int ' ) ,
retries = dict ( default = 10 , type = ' int ' ) ,
interval = dict ( default = 1 , type = ' int ' )
interval = dict ( default = 1 , type = ' int ' )
)
)
module = get_module ( argument_spec = spec ,
module = NetworkModule ( argument_spec = spec ,
connect_on_load = False ,
supports_check_mode = True )
supports_check_mode = True )
commands = module . params [ ' commands ' ]
commands = list ( parse_commands ( module ) )
conditionals = module . params [ ' wait_for ' ] or list ( )
warnings = list ( )
retries = module . params [ ' retries ' ]
runner = CommandRunner ( module )
interval = module . params [ ' interval ' ]
for cmd in commands :
if module . check_mode and not cmd [ ' command ' ] . startswith ( ' show ' ) :
warnings . append ( ' only show commands are supported when using '
' check mode, not executing ` %s ` ' % cmd [ ' command ' ] )
else :
if cmd [ ' command ' ] . startswith ( ' conf ' ) :
module . fail_json ( msg = ' iosxr_command does not support running '
' config mode commands. Please use '
' iosxr_config instead ' )
try :
try :
queue = set ( )
runner . add_command ( * * cmd )
for entry in ( module . params [ ' waitfor ' ] or list ( ) ) :
except AddCommandError :
queue . add ( Conditional ( entry ) )
except AttributeError :
exc = get_exception ( )
exc = get_exception ( )
module . fail_json ( msg = exc . message )
warnings . append ( ' duplicate command detected: %s ' % cmd )
for item in conditionals :
runner . add_conditional ( item )
result = dict ( changed = False )
runner . retries = module . params [ ' retries ' ]
runner . interval = module . params [ ' interval ' ]
runner . match = module . params [ ' match ' ]
while retries > 0 :
try :
response = module . execute ( commands )
runner . run ( )
result [ ' stdout ' ] = response
except FailedConditionsError :
exc = get_exception ( )
module . fail_json ( msg = str ( exc ) , failed_conditions = exc . failed_conditions )
except NetworkError :
exc = get_exception ( )
module . fail_json ( msg = str ( exc ) )
for item in list ( queue ) :
result = dict ( changed = False , stdout = list ( ) )
if item ( response ) :
queue . remove ( item )
if not queue :
for cmd in commands :
break
try :
output = runner . get_command ( cmd [ ' command ' ] )
except ValueError :
output = ' command not executed due to check_mode, see warnings '
result [ ' stdout ' ] . append ( output )
time . sleep ( interval )
result [ ' warnings ' ] = warnings
retries - = 1
result [ ' stdout_lines ' ] = list ( to_lines ( result [ ' stdout ' ] ) )
else :
failed_conditions = [ item . raw for item in queue ]
module . fail_json ( msg = ' timeout waiting for value ' , failed_conditions = failed_conditions )
result [ ' stdout_lines ' ] = list ( iterlines ( result [ ' stdout ' ] ) )
module . exit_json ( * * result )
return module . exit_json ( * * result )
from ansible . module_utils . basic import *
from ansible . module_utils . urls import *
from ansible . module_utils . shell import *
from ansible . module_utils . netcfg import *
from ansible . module_utils . iosxr import *
if __name__ == ' __main__ ' :
if __name__ == ' __main__ ' :
main ( )
main ( )