-
Notifications
You must be signed in to change notification settings - Fork 58
4. Module
For using it as module, it provides following functions under class Jsnapy:
-
snap(config_file/config_data, snap_file_name, dev, folder)
This function lets you take snapshot.snap_file_name : User can give either - full file path (but file should exists) - prefix, in this case file name is formed automatically (<devicename>_<prefix>_<command/rpc>.<xml/text>) all snapshots are taken from '/etc/jsnapy/snapshots' unless complete path of snapshot file is specified. config_file : User can give either full path or name of config file, in that case it should be present in current working directory. Inside this config file, user can give test files by giving: - full path of test file - only name of test file, this file should be present in '/etc/Jsnapy/testfiles'. config_data : Instead of test details in config file, user can also specify yaml content in some variable. It can also be passed as a dictionary containing test details. For example refer sample program 4. dev : PyEZ device object, by default it is None If device object is given then it will connect to given device otherwise take device details from config file. folder : Use this command to specify custom jsnapy lookup directory. For more info refer [here](https://github.com/Juniper/jsnapy/wiki/3.-Command-Line-Tool#optional-arguments) snap function return list of objects. Each object is associated per device (as included in config file, if the config file got one device detail only, list will contain 1 element only). Each object has attributes rpc_list, command_list, test_included to give details of snapshots being taken.
Note:
PyEZ
folder:Added in v1.1
-
snapcheck (config_file_name/ config_yaml_data, snap_file_name, dev, local, folder)
This function compares the current configuration against pre-defined criteria.local : Boolean. Pass `True` to run snapcheck on local snapshot(s). Behaviour is same as that of command line param mentioned [here](https://github.com/Juniper/jsnapy/wiki/3.-Command-Line-Tool#optional-arguments) rest parameters mean same as snap function <br> snapcheck function return list of objects. Each object is associated per device. Each object has attributes device, result, no_passed, no_failed, test_results to give details of results.
-
check (config_file_name, snap_filename1, snap_filename2, dev, folder)
This function compares two snapshots based on given test cases.
parameters mean same as snap functioncheck function return list of objects. Each object is associated per device. Each object has attributes device, result, no_passed, no_failed, test_results to give details of results.
*Work of functions snap, check, snapcheck is same as mentioned in command line argument.
Output format:
- Default : A list of jsnapy.Operator objects. Each Operator object has a
test_results
dictionary which contains all details about total number of test cases passed/failed. - Using
local=True
:Added in v1.1
In this case the snapcheck function returns a list of dictionary, where the dictionary is keyed with the various snapshot names passed and the value is an Operator object which contains the test details.
Sample Program:
1] Using JSNAPy as a module:
### Performing function similar to --check in command line ###
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
from jnpr.junos import Device
js = SnapAdmin()
config_file = "/etc/jsnapy/testfiles/demo_check.yml"
js.snap(config_file, "pre")
js.snap(config_file, "post")
chk = js.check(config_file, "pre", "post")
for check in chk:
print "Tested on", check.device
print "Final result: ", check.result
print "Total passed: ", check.no_passed
print "Total failed:", check.no_failed
pprint(check.test_results)
/etc/jsnapy/testfiles/demo_check.yml
# for one device, can be given like this:
hosts:
- device: device
username : foo
passwd: bar
tests:
- test_no_diff.yml
test_no_diff.yml
test_command_version:
- command: show interfaces terse lo*
- iterate:
xpath: physical-interface
id: ['./name']
tests:
- no-diff: admin-status # element in which test is performed
err: "Failed!! admin-status got changed, PRE: <{{pre['admin-status']}}>, POST: <{{post['admin-status']}}>"
info: "Passed!! admin-status is same PRE: <{{pre['admin-status']}}> POST: <{{post['admin-status']}}>"
test_command_version:
- command: show interfaces terse
- iterate:
xpath: physical-interface
id: ['./name']
tests:
- no-diff: admin-status # element in which test is performed
err: "Failed!! admin-status got changed, PRE: <{{pre['admin-status']}}>, POST: <{{post['admin-status']}}>"
info: "Passed!! admin-status is same PRE: <{{pre['admin-status']}}> POST: <{{post['admin-status']}}>"
Output:
Tested on device
Final result: Failed
Total passed: 0
Total failed: 1
{'show interfaces terse': [{'count': {'fail': 3, 'pass': 53},
'failed': [{'id_missing_pre': {'./name': 'demux0'}},
{'id_missing_post': {'./name': 'demux01'}},
{'id': {'./name': 'cbp0'},
'post': {'admin-status': ['up']},
'post_node_value': ['up'],
'pre': {'admin-status': ['down']},
'pre_node_value': ['down']}],
'node_name': 'admin-status',
'passed': [{'id': {'./name': 'ge-2/2/3'},
'post': {'admin-status': ['up']},
'post_node_value': ['up'],
'pre': {'admin-status': ['up']},
'pre_node_value': ['up']},
.............
.......
{'id': {'./name': 'ge-2/2/4'},
'post': {'admin-status': ['up']},
'post_node_value': ['up'],
'pre': {'admin-status': ['up']},
'pre_node_value': ['up']},
'result': False,
'testoperation': 'no-diff',
'xpath': 'physical-interface'}]}
2] Here, I am not creating new device object. Reusing already existing PyEZ device object to take snapshot:
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
from jnpr.junos import Device
dev_obj = Device(host='10.209.1.1', user='foo', password='bar')
dev_obj.open()
js = SnapAdmin()
config_file = "/etc/jsnapy/config_snapcheck.yml"
snapvalue = js.snapcheck(config_file, "pre", dev=dev_obj)
for snapcheck in snapvalue:
print "\n -----------snapcheck----------"
print "Tested on", snapcheck.device
print "Final result: ", snapcheck.result
print "Total passed: ", snapcheck.no_passed
print "Total failed:", snapcheck.no_failed
pprint(snapcheck.test_results)
/etc/jsnapy/config_snapcheck.yml
hosts:
- device: device
username : foo
passwd: bar
tests:
- test_is_equal.yml
- test_not_in.yml
test_is_equal.yml
test_interfaces_terse:
- command: show interfaces terse lo*
- iterate:
id: ./name
xpath: //physical-interface
tests:
- is-equal: admin-status, up
info: "Test Succeeded !! admin-status of interface <{{post['name']}}> is equal to <{{post['admin-status']}}> with oper-status <{{ pre['oper-status'] }}>"
err: "Test Failed !! admin-status of interface <{{ post['name'] }}> is not equal to down, it is <{{post['admin-status']}}> with oper-status <{{pre['oper-status']}}>"
test_not_in.yml
check_show_interfaces_terse:
- command: show interfaces terse
- iterate:
xpath: //physical-interface
tests:
- not-in: oper-status, down, up
info: "Test Succeeded!! Physical operational status is-in down-up, it is: <{{post['oper-status']}}> with admin status <{{post['admin-status']}}>"
err: "Test Failed!!! Physical operational status is not in downoo-up, it is: <{{post['oper-status']}}> with admin status <{{post['admin-status']}}> "
Sample Output:
Tested on 10.209.1.1
Final result: Failed
Total passed: 1
Total failed: 1
{'show interfaces terse': [{'count': {'fail': 17, 'pass': 0},
'expected_node_value': ['down', 'up'],
'failed': [{'actual_node_value': 'up',
'id': {},
'post': {'admin-status': 'up',
'oper-status': 'up'},
'pre': {'oper-status': 'up'}},
{'actual_node_value': 'up',
'id': {},
'post': {'admin-status': 'up',
'oper-status': 'up'},
'pre': {'oper-status': 'up'}},
............
{'actual_node_value': 'up',
'id': {},
'post': {'admin-status': 'up',
'oper-status': 'up'},
'pre': {'oper-status': 'up'}}],
'node_name': 'oper-status',
'passed': [],
'result': False,
'testoperation': 'not-in',
'xpath': '//physical-interface'}],
'show interfaces terse lo*': [{'count': {'fail': 0, 'pass': 1},
'expected_node_value': 'up',
'failed': [],
'node_name': 'admin-status',
'passed': [{'actual_node_value': 'up',
'id': {'./name': 'lo0'},
'post': {'admin-status': 'up',
'name': 'lo0'},
'pre': {'admin-status': 'up',
'oper-status': 'up'}}],
'result': True,
'testoperation': 'is-equal',
'xpath': '//physical-interface'}]}
3] Instead of passing config file in yaml, you can pass file details as yaml data also.
### Example showing how to pass yaml data in same file ###
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
from jnpr.junos import Device
js = SnapAdmin()
config_data = """
hosts:
- device: 1.1.1.1
username : demo
passwd: demo123
tests:
- test_is_equal.yml
"""
snapchk = js.snapcheck(config_data, "pre")
for val in snapchk:
print "Tested on", val.device
print "Final result: ", val.result
print "Total passed: ", val.no_passed
print "Total failed:", val.no_failed
pprint(val.test_results)
Output:
Tested on 1.1.1.1
Final result: Passed
Total passed: 1
Total failed: 0
{'show interfaces terse lo*': [{'count': {'fail': 0, 'pass': 1},
'expected_node_value': 'up',
'failed': [],
'node_name': 'admin-status',
'passed': [{'actual_node_value': 'up',
'id': {'./name': 'lo0'},
'post': {'admin-status': 'up',
'name': 'lo0'},
'pre': {'admin-status': 'up',
'oper-status': 'up'}}],
'result': True,
'testoperation': 'is-equal',
'xpath': '//physical-interface'}]}
4] Passing test details as dictionary to functions
### Example showing how to pass test details directly to function ###
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
from jnpr.junos import Device
js = SnapAdmin()
snap = js.snap({'tests': ['test_is_equal_iter.yml', 'test_route_summary.yml']}, 'PRE', dev=dev)
snap = js.snap({'tests': ['test_is_equal_iter.yml', 'test_route_summary.yml']}, 'POST', dev=dev)
chk = js.check({'tests': ['test_is_equal_iter.yml', 'test_route_summary.yml']}, "PRE", "POST", dev=dev)
for checkvalue in chk:
print "\n -----------check----------"
print "Tested on", checkvalue.device
print "Final result: ", checkvalue.result
print "Total passed: ", checkvalue.no_passed
print "Total failed:", checkvalue.no_failed
pprint(checkvalue.test_results)
5] Return value from snap can give details of rpc/commands executed and test included from the config file.
### Example showing how to pass test details directly to function ###
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
from jnpr.junos import Device
js = SnapAdmin()
snap = js.snap('/home/user/config.yml', 'PRE')
for item in snap:
print item.test_included
print item.rpc_list
print item.command_list
6] JSNAPy results can now also be obtained with testname as key in output dictionary
Two Properties are defined, user can use as per need
- test_results: will provide output dictionary with command as keys
- testname_results: will provide output dictionary with testname as keys
Added in v1.2
from jnpr.jsnapy import SnapAdmin
from pprint import pprint
js = SnapAdmin()
pre_pass = js.snap('config.yml', 'pre_check')
post_pass = js.snap('config.yml', 'post_check')
snapval = js.check('config.yml', 'pre_check', 'post_check')
for item in snapval:
print("\n -----------snapcheck----------")
print("Tested on", item.device)
print("Final result: ", item.result)
print("Total passed: ", item.no_passed)
print("Total failed:", item.no_failed)
pprint(item.test_results)
pprint(item.testname_results)
config.yml
hosts:
- device: 1.1.1.1
username: abc
passwd: xyz
tests:
- test_in_range.yml
test_in_range.yml
check_chassis_fpc:
- command: show chassis fpc
- iterate:
xpath: fpc[normalize-space(slot) = "0"]
tests:
- in-range: memory-heap-utilization, 5, 40
info: "Test Succeeded!! memory heap utilisation of the FPCs is within the range of 5-40, it is <{{post['memory-heap-utilization']}}> with temperature: <{{post['temperature']}}>"
err: "Test Failed!! memory heap utilisation of the FPCs is not in range of 5-40, it is <{{post['memory-heap-utilization']}}> with temperature: <{{post['temperature']}}>"
Final Output
-----------snapcheck----------
('Tested on', '1.1.1.1')
('Final result: ', 'Passed')
('Total passed: ', 1)
('Total failed:', 0)
{'show chassis fpc': [{'count': {'fail': 0, 'pass': 1},
'expected_node_value': [5.0, 40.0],
'failed': [],
'node_name': 'memory-heap-utilization',
'passed': [{'actual_node_value': '20',
'id': {},
'message': 'Test Succeeded!! memory heap utilisation of the FPCs is within the range of 5-40, it is <20> with temperature: <Testing>',
'post': {'memory-heap-utilization': '20',
'temperature': 'Testing'},
'pre': {'memory-heap-utilization': '20'}}],
'result': True,
'test_name': 'check_chassis_fpc',
'testoperation': 'in-range',
'xpath': 'fpc[normalize-space(slot) = "0"]'}]}
{'check_chassis_fpc': [{'command': 'show chassis fpc',
'count': {'fail': 0, 'pass': 1},
'expected_node_value': [5.0, 40.0],
'failed': [],
'node_name': 'memory-heap-utilization',
'passed': [{'actual_node_value': '20',
'id': {},
'message': 'Test Succeeded!! memory heap utilisation of the FPCs is within the range of 5-40, it is <20> with temperature: <Testing>',
'post': {'memory-heap-utilization': '20',
'temperature': 'Testing'},
'pre': {'memory-heap-utilization': '20'}}],
'result': True,
'testoperation': 'in-range',
'xpath': 'fpc[normalize-space(slot) = "0"]'}]}
Added in v1.2
Note: The message field in the output, under the key passed
or failed
is the err/info string. Depending on the output, the message field will be in either of them. The message will contain the value of the nodes defined in testfiles err/info message using the jinja template(<{{post['temperature']}}>
). The message string will contain the value of 'temperature' from post snapshot. Look in the above example for reference.
Note: To hide messages coming in console, apart from explicitly given print statements, please remove console file handler from list of handlers in /etc/jsnapy/logging.yml
(venv)sh-3.2# cat /etc/jsnapy/logging.yml
version: 1
disable_existing_loggers: True
## use formatters to cutomize your output
## add of remove parameters accordingly
##
formatters:
custom_format:
format: "%(asctime)s - %(name)s - %(levelname)s - %(hostname)s ............. \n %(message)s"
simple:
format: "%(hostname)s-- %(message)s"
default:
format: "%(message)s"
default_file:
format: "%(asctime)s - %(name)s - %(levelname)s - \n %(message)s"
handlers:
console:
class: logging.StreamHandler
level: INFO
formatter: default
stream: ext://sys.stdout
.......
....
root:
level: DEBUG
handlers: [debug_file_handler] ## removed console option from here