@ -21,15 +21,12 @@ DOCUMENTATION = """
module : junos_config
version_added : " 2.1 "
author : " Peter Sprygada (@privateip) "
short_description : Manage configuration on remote devices running Junos
short_description : Manage configuration on devices running Juniper JUNOS
description :
- Provides an abstraction for working
with the configuration running on remote Junos devices . It can perform
operations that influence the configuration state .
- This module provides an implementation for configuring Juniper
JUNOS devices . The configuration statements must start with either
` set ` or ` delete ` and are compared against the current device
configuration and only changes are pushed to the device .
- This module provides an implementation for working with the active
configuration running on Juniper JUNOS devices . It provides a set
of arguments for loading configuration , performing rollback operations
and zeroing the active configuration on the device .
extends_documentation_fragment : junos
options :
lines :
@ -40,6 +37,38 @@ options:
file in role or playbook root folder in templates directory .
required : false
default : null
src :
description :
- The I ( src ) argument provides a path to the configuration file
to load into the remote system . The path can either be a full
system path to the configuration file if the value starts with /
or relative to the root of the implemented role or playbook .
This arugment is mutually exclusive with the I ( lines ) and
I ( parents ) arguments .
required : false
default : null
version_added : " 2.2 "
src_format :
description :
- The I ( src_format ) argument specifies the format of the configuration
found int I ( src ) . If the I ( src_format ) argument is not provided ,
the module will attempt to determine the format of the configuration
file specified in I ( src ) .
required : false
default : null
choices : [ ' xml ' , ' set ' , ' text ' , ' json ' ]
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 ( replace ) . When the argument is set to
I ( merge ) , the configuration changes are merged with the current
device active configuration .
required : false
default : merge
choices : [ ' merge ' , ' replace ' ]
version_added : " 2.2 "
rollback :
description :
- The C ( rollback ) argument instructs the module to rollback the
@ -82,11 +111,24 @@ options:
replace the current configuration hierarchy with the one specified
in the corresponding hierarchy of the source configuration loaded
from this module .
- Note this argument should be considered deprecated . To achieve
the equivalent , set the I ( update ) argument to C ( replace ) . This argument
will be removed in a future release .
required : false
required : true
choices :
- yes
- no
choices : [ ' yes ' , ' no ' ]
default : false
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 "
requirements :
- junos - eznc
notes :
@ -95,118 +137,181 @@ notes:
"""
EXAMPLES = """
- name : load configuration lines in device
# Note: examples below use the following provider dict to handle
# transport and authentication to the node.
vars :
netconf :
host : " {{ inventory_hostname }} "
username : ansible
password : Ansible
- name : load configure file into device
junos_config :
lines :
- set system host - name { { inventory_hostname } }
- delete interfaces ge - 0 / 0 / 0 description
src : srx . cfg
comment : update config
provider : " {{ netconf }} "
- name : rollback the configuration to id 10
junos_config :
rollback : 10
provider : " {{ netconf }} "
- name : zero out the current configuration
junos_config :
zeroize : yes
- name : confirm a candidate configuration
junos_config :
provider : " {{ netconf }} "
"""
RETURN = """
backup_path :
description : The full path to the backup file
returned : when backup is yes
type : path
sample : / playbooks / ansible / backup / config .2016 - 07 - 16 @ 22 : 28 : 34
"""
import re
import json
DEFAULT_COMMENT = ' configured by junos_config '
from lxml import etree
def diff_config ( candidate , config ) :
from ansible . module_utils . junos import NetworkModule , NetworkError
updates = set ( )
for line in candidate :
parts = line . split ( )
action = parts [ 0 ]
cfgline = ' ' . join ( parts [ 1 : ] )
DEFAULT_COMMENT = ' configured by junos_config '
if action not in [ ' set ' , ' delete ' ] :
module . fail_json ( msg = ' line must start with either `set` or `delete` ' )
elif action == ' set ' and cfgline not in config :
updates . add ( line )
def invoke ( name , * args , * * kwargs ) :
func = globals ( ) . get ( name )
if func :
return func ( * args , * * kwargs )
elif action == ' delete ' and not config :
updates . add ( line )
def run ( module , result ) :
if module . params [ ' rollback ' ] :
action = ' rollback_config '
elif module . params [ ' zeroize ' ] :
action = ' zeroize_config '
else :
action = ' load_config '
elif action == ' delete ' :
for cfg in config :
if cfg [ 4 : ] . startswith ( cfgline ) :
updates . add ( line )
return invoke ( action , module , result )
return list ( updates )
def main ( ) :
def check_args ( module , warnings ) :
if module . params [ ' replace ' ] is True :
warnings . append ( ' The replace argument is deprecated, please use '
' update=replace instead. This argument will be '
' removed in the future ' )
if module . params [ ' lines ' ] and module . params [ ' update ' ] == ' replace ' :
module . fail_json ( msg = ' config replace is only allowed when src is specified ' )
argument_spec = dict (
lines = dict ( type = ' list ' ) ,
rollback = dict ( type = ' int ' ) ,
zeroize = dict ( default = False , type = ' bool ' ) ,
confirm = dict ( default = 0 , type = ' int ' ) ,
comment = dict ( default = DEFAULT_COMMENT ) ,
replace = dict ( default = False , type = ' bool ' ) ,
transport = dict ( default = ' netconf ' , choices = [ ' netconf ' ] )
)
def guess_format ( config ) :
try :
json . loads ( config )
return ' json '
except ValueError :
pass
mutually_exclusive = [ ( ' lines ' , ' rollback ' ) , ( ' lines ' , ' zeroize ' ) ,
( ' rollback ' , ' zeroize ' ) ]
try :
etree . fromstring ( config )
return ' xml '
except etree . XMLSyntaxError :
pass
module = get_module ( argument_spec = argument_spec ,
mutually_exclusive = mutually_exclusive ,
supports_check_mode = True )
if config . startswith ( ' set ' ) or config . startswith ( ' delete ' ) :
return ' set '
rollback = module . params [ ' rollback ' ]
zeroize = module . params [ ' zeroize ' ]
return ' text '
def backup_config ( module , result ) :
result [ ' __backup__ ' ] = module . config . get_config ( )
def load_config ( module , result ) :
comment = module . params [ ' comment ' ]
confirm = module . params [ ' confirm ' ]
if module . params [ ' replace ' ] :
action = ' replace '
else :
action = ' merge '
update = module . params [ ' update ' ]
candidate = module . params [ ' lines ' ] or module . params [ ' src ' ]
commit = not module . check_mode
config_format = module . params [ ' src_format ' ] or guess_format ( candidate )
diff = module . config . load_config ( candidate , update = update , comment = comment ,
format = config_format , commit = commit ,
confirm = confirm )
if diff :
result [ ' changed ' ] = True
result [ ' diff ' ] = dict ( prepared = diff )
def rollback_config ( module , result ) :
rollback = module . params [ ' rollback ' ]
comment = module . params [ ' comment ' ]
lines = module . params [ ' lines ' ]
commit = not module . check_mode
results = dict ( changed = False )
diff = module . connection . rollback_config ( rollback , commit = commit ,
comment = comment )
if diff :
result [ ' changed ' ] = True
result [ ' diff ' ] = dict ( prepared = diff )
def zeroize_config ( module , result ) :
if not module . check_mode :
module . cli . run_commands ( ' request system zeroize ' )
result [ ' changed ' ] = True
if lines :
config = str ( module . get_config ( config_format = ' set ' ) ) . split ( ' \n ' )
updates = diff_config ( lines , config )
if updates :
updates = ' \n ' . join ( updates )
diff = module . load_config ( updates , action = action , comment = comment ,
format = ' set ' , commit = commit , confirm = confirm )
def main ( ) :
argument_spec = dict (
lines = dict ( type = ' list ' ) ,
src = dict ( type = ' path ' ) ,
src_format = dict ( choices = [ ' xml ' , ' text ' , ' set ' , ' json ' ] ) ,
# update operations
update = dict ( default = ' merge ' , choices = [ ' merge ' , ' replace ' ] ) ,
confirm = dict ( default = 0 , type = ' int ' ) ,
comment = dict ( default = DEFAULT_COMMENT ) ,
# config operations
backup = dict ( type = ' bool ' , default = False ) ,
rollback = dict ( type = ' int ' ) ,
zeroize = dict ( default = False , type = ' bool ' ) ,
# this argument is deprecated in favor of setting update=replace
# and will be removed in a future version
replace = dict ( default = False , type = ' bool ' ) ,
transport = dict ( default = ' netconf ' , choices = [ ' netconf ' ] )
)
mutually_exclusive = [ ( ' lines ' , ' rollback ' ) , ( ' lines ' , ' zeroize ' ) ,
( ' rollback ' , ' zeroize ' ) , ( ' lines ' , ' src ' ) ,
( ' src ' , ' zeroize ' ) , ( ' src ' , ' rollback ' ) ]
module = NetworkModule ( argument_spec = argument_spec ,
mutually_exclusive = mutually_exclusive ,
supports_check_mode = True )
if diff :
results [ ' changed ' ] = True
results [ ' diff ' ] = dict ( prepared = diff )
warnings = list ( )
check_args ( module , warnings )
elif rollback is not None :
diff = module . rollback_config ( rollback , commit = commit )
if diff :
results [ ' changed ' ] = True
results [ ' diff ' ] = dict ( prepared = diff )
if module . params [ ' replace ' ] is True :
module . params [ ' update ' ] = ' replace '
elif zeroize :
if not module . check_mode :
module . run_commands ( ' request system zeroize ' )
results [ ' changed ' ] = True
result = dict ( changed = False , warnings = warnings )
module . exit_json ( * * results )
try :
run ( module , result )
except NetworkError :
exc = get_exception ( )
module . fail_json ( msg = str ( exc ) , * * exc . kwargs )
module . exit_json ( * * result )
from ansible . module_utils . basic import *
from ansible . module_utils . junos import *
if __name__ == ' __main__ ' :
main ( )