@ -26,9 +26,8 @@ description:
- Cisco IOS XR configurations use a simple block indent file syntax
- Cisco IOS XR configurations use a simple block indent file syntax
for segmenting configuration into sections . This module provides
for segmenting configuration into sections . This module provides
an implementation for working with IOS XR configuration sections in
an implementation for working with IOS XR configuration sections in
a deterministic way . This module works with either CLI or NXAPI
a deterministic way .
transports .
extends_documentation_fragment : iosxr
extends_documentation_fragment : ios
options :
options :
lines :
lines :
description :
description :
@ -37,7 +36,9 @@ options:
in the device running - config . Be sure to note the configuration
in the device running - config . Be sure to note the configuration
command syntax as some commands are automatically modified by the
command syntax as some commands are automatically modified by the
device config parser .
device config parser .
required : true
required : false
default : null
aliases : [ ' commands ' ]
parents :
parents :
description :
description :
- The ordered set of parents that uniquely identify the section
- The ordered set of parents that uniquely identify the section
@ -46,6 +47,16 @@ options:
level or global commands .
level or global commands .
required : false
required : false
default : null
default : null
src :
description :
- Specifies the source path to the file that contains the configuration
or configuration template to load . The path to the source file can
either be the full path on the Ansible control host or a relative
path from the playbook or role root directory . This argument is mutually
exclusive with I ( lines ) .
required : false
default : null
version_added : " 2.2 "
before :
before :
description :
description :
- The ordered set of commands to push on to the command stack if
- The ordered set of commands to push on to the command stack if
@ -69,11 +80,13 @@ options:
the set of commands against the current device config . If
the set of commands against the current device config . If
match is set to I ( line ) , commands are matched line by line . If
match is set to I ( line ) , commands are matched line by line . If
match is set to I ( strict ) , command lines are matched with respect
match is set to I ( strict ) , command lines are matched with respect
to position . Finally if match is set to I ( exact ) , command lines
to position . If match is set to I ( exact ) , command lines
must be an equal match .
must be an equal match . Finally , if match is set to I ( none ) , the
module will not attempt to compare the source configuration with
the running configuration on the remote device .
required : false
required : false
default : line
default : line
choices : [ ' line ' , ' strict ' , ' exact ' ]
choices : [ ' line ' , ' strict ' , ' exact ' , ' none ' ]
replace :
replace :
description :
description :
- Instructs the module on the way to perform the configuration
- Instructs the module on the way to perform the configuration
@ -91,9 +104,26 @@ options:
current devices running - config . When set to true , this will
current devices running - config . When set to true , this will
cause the module to push the contents of I ( src ) into the device
cause the module to push the contents of I ( src ) into the device
without first checking if already configured .
without first checking if already configured .
- Note this argument should be considered deprecated . To achieve
the equivalent , set the match argument to none . This argument
will be removed in a future release .
required : false
required : false
default : false
default : false
choices : [ " true " , " false " ]
choices : [ " yes " , " no " ]
version_added : " 2.2 "
update :
description :
- The I ( update ) argument controls how the configuration statements
are processed on the remote device . Valid choices for the I ( update )
argument are I ( merge ) and I ( check ) . When the argument is set to
I ( merge ) , the configuration changes are merged with the current
device running configuration . When the argument is set to I ( check )
the configuration updates are determined but not actually configured
on the remote device .
required : false
default : merge
choices : [ ' merge ' , ' replace ' , ' check ' ]
version_added : " 2.2 "
config :
config :
description :
description :
- The module , by default , will connect to the remote device and
- The module , by default , will connect to the remote device and
@ -105,25 +135,56 @@ options:
config for comparison .
config for comparison .
required : false
required : false
default : null
default : null
backup :
description :
- This argument will cause the module to create a full backup of
the current C ( running - config ) from the remote device before any
changes are made . The backup file is written to the C ( backup )
folder in the playbook root directory . If the directory does not
exist , it is created .
required : false
default : no
choices : [ ' yes ' , ' no ' ]
version_added : " 2.2 "
comment :
description :
- Allows a commit description to be specified to be included
when the configuration is committed . If the configuration is
not changed or committed , this argument is ignored .
required : false
default : ' configured by iosxr_config '
version_added : " 2.2 "
"""
"""
EXAMPLES = """
EXAMPLES = """
- iosxr_config :
# Note: examples below use the following provider dict to handle
lines : [ ' hostname {{ inventory_hostname }} ' ]
# transport and authentication to the node.
force : yes
vars :
cli :
host : " {{ inventory_hostname }} "
username : cisco
password : cisco
transport : cli
- iosxr_config :
- name : configure top level configuration
lines :
iosxr_config :
- description configured by ansible
lines : hostname { { inventory_hostname } }
- ipv4 address 10.0 .0 .25 255.255 .255 .0
provider : " {{ cli }} "
parents : [ ' interface GigabitEthernet0/0/0/0 ' ]
- iosxr_config :
- name : configure interface settings
commands : " {{ lookup( ' file ' , ' datcenter1.txt ' )}} "
iosxr_config :
parents : [ ' ipv4 access-list test ' ]
lines :
before : [ ' no ip access-listv4 test ' ]
- description test interface
replace : block
- ip address 172.31 .1 .1 255.255 .255 .0
parents : interface GigabitEthernet0 / 0 / 0 / 0
provider : " {{ cli }} "
- name : load a config from disk and replace the current config
iosxr_config :
src : config . cfg
update : replace
backup : yes
provider : " {{ cli }} "
"""
"""
RETURN = """
RETURN = """
@ -132,82 +193,144 @@ updates:
returned : always
returned : always
type : list
type : list
sample : [ ' ... ' , ' ... ' ]
sample : [ ' ... ' , ' ... ' ]
backup_path :
responses :
description : The full path to the backup file
description : The set of responses from issuing the commands on the device
returned : when backup is yes
retured : always
type : path
type : list
sample : / playbooks / ansible / backup / iosxr01 .2016 - 07 - 16 @ 22 : 28 : 34
sample : [ ' ... ' , ' ... ' ]
"""
"""
from ansible . module_utils . basic import get_exception
from ansible . module_utils . netcfg import NetworkConfig , dumps
from ansible . module_utils . iosxr import NetworkModule , NetworkError
def get_config ( module ) :
DEFAULT_COMMIT_COMMENT = ' configured by iosxr_config '
config = module . params [ ' config ' ] or dict ( )
if not config and not module . params [ ' force ' ] :
config = module . config
return config
def main ( ) :
def invoke ( name , * args , * * kwargs ) :
func = globals ( ) . get ( name )
if func :
return func ( * args , * * kwargs )
def check_args ( module , warnings ) :
if module . params [ ' parents ' ] :
if not module . params [ ' lines ' ] or module . params [ ' src ' ] :
warnings . append ( ' ignoring unnecessary argument parents ' )
if module . params [ ' match ' ] == ' none ' and module . params [ ' replace ' ] :
warnings . append ( ' ignoring unnecessary argument replace ' )
if module . params [ ' update ' ] == ' replace ' and not module . params [ ' src ' ] :
module . fail_json ( msg = ' Must specify src when update is `replace` ' )
if module . params [ ' force ' ] :
warnings . append ( ' The force argument is deprecated, please use '
' match=none instead. This argument will be '
' removed in the future ' )
def get_config ( module , result ) :
contents = module . params [ ' config ' ] or result . get ( ' __config__ ' )
if not contents :
contents = module . config . get_config ( )
return NetworkConfig ( indent = 1 , contents = contents )
def get_candidate ( module ) :
candidate = NetworkConfig ( indent = 1 )
if module . params [ ' src ' ] :
candidate . load ( module . params [ ' src ' ] )
elif module . params [ ' lines ' ] :
parents = module . params [ ' parents ' ] or list ( )
candidate . add ( module . params [ ' lines ' ] , parents = parents )
return candidate
def load_config ( module , commands , result ) :
replace = module . params [ ' update ' ] == ' replace '
comment = module . params [ ' comment ' ]
commit = not module . check_mode
diff = module . config . load_config ( commands , replace = replace , commit = commit ,
comment = comment )
result [ ' diff ' ] = dict ( prepared = diff )
result [ ' changed ' ] = True
def run ( module , result ) :
match = module . params [ ' match ' ]
replace = module . params [ ' replace ' ]
update = module . params [ ' update ' ]
candidate = get_candidate ( module )
if match != ' none ' and update != ' replace ' :
config = get_config ( module , result )
configobjs = candidate . difference ( config , match = match , replace = replace )
else :
config = None
configobjs = candidate . items
if configobjs :
commands = dumps ( configobjs , ' commands ' )
if module . params [ ' before ' ] :
commands [ : 0 ] = module . params [ ' before ' ]
if module . params [ ' after ' ] :
commands . extend ( module . params [ ' after ' ] )
result [ ' updates ' ] = commands . split ( ' \n ' )
if update != ' check ' :
load_config ( module , commands , result )
def main ( ) :
""" main entry point for module execution
"""
argument_spec = dict (
argument_spec = dict (
lines = dict ( aliases = [ ' commands ' ] , required = True , type = ' list ' ) ,
lines = dict ( aliases = [ ' commands ' ] , type = ' list ' ) ,
parents = dict ( type = ' list ' ) ,
parents = dict ( type = ' list ' ) ,
src = dict ( type = ' path ' ) ,
before = dict ( type = ' list ' ) ,
before = dict ( type = ' list ' ) ,
after = dict ( type = ' list ' ) ,
after = dict ( type = ' list ' ) ,
match = dict ( default = ' line ' , choices = [ ' line ' , ' strict ' , ' exact ' ] ) ,
replace = dict ( default = ' line ' , choices = [ ' line ' , ' block ' ] ) ,
force = dict ( default = False , type = ' bool ' ) ,
config = dict ( )
)
module = get_module ( argument_spec = argument_spec ,
supports_check_mode = True )
lines = module . params [ ' lines ' ]
match = dict ( default = ' line ' , choices = [ ' line ' , ' strict ' , ' exact ' , ' none ' ] ) ,
parents = module . params [ ' parents ' ] or list ( )
replace = dict ( default = ' line ' , choices = [ ' line ' , ' block ' ] ) ,
before = module . params [ ' before ' ]
update = dict ( choices = [ ' merge ' , ' replace ' , ' check ' ] , default = ' merge ' ) ,
after = module . params [ ' after ' ]
backup = dict ( type = ' bool ' , default = False ) ,
comment = dict ( default = DEFAULT_COMMIT_COMMENT ) ,
match = module . params [ ' match ' ]
# this argument is deprecated in favor of setting match: none
replace = module . params [ ' replace ' ]
# it will be removed in a future version
force = dict ( default = False , type = ' bool ' ) ,
contents = get_config ( module )
config = dict ( ) ,
config = module . parse_config ( contents )
)
if not module . params [ ' force ' ] :
mutually_exclusive = [ ( ' lines ' , ' src ' ) ]
contents = get_config ( module )
config = NetworkConfig ( contents = contents , indent = 1 )
candidate = NetworkConfig ( indent = 1 )
module = NetworkModule ( argument_spec = argument_spec ,
candidate . add ( lines , parents = parents )
connect_on_load = False ,
mutually_exclusive = mutually_exclusive ,
supports_check_mode = True )
commands = candidate . difference ( config , path = parents , match = match , replace = replace )
if module . params [ ' force ' ] is True :
else :
module . params [ ' match ' ] = ' none '
commands = parents
commands . extend ( lines )
result = dict ( changed = False )
warnings = list ( )
check_args ( module , warnings )
if commands :
result = dict ( changed = False , warnings = warnings )
if before :
commands [ : 0 ] = before
if after :
if module . params [ ' backup ' ] :
commands . extend ( after )
config = module . config . get_config ( )
result [ ' __config__ ' ] = config
result [ ' __backup__ ' ] = config
if not module . check_mode :
try :
commands = [ str ( c ) . strip ( ) for c in commands ]
run ( module , result )
response = module . configure ( commands )
except NetworkError :
result [ ' responses ' ] = response
exc = get_exception ( )
result [ ' changed ' ] = True
module. fail_json ( msg = str ( exc ) , * * exc . kwargs )
result [ ' updates ' ] = commands
module . exit_json ( * * result )
module . exit_json ( * * result )
from ansible . module_utils . basic 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 ( )