Skip to content

Commit

Permalink
Pull request #1: SOFT-8495
Browse files Browse the repository at this point in the history
Merge in NCA/pysros from ~RICCARDOV/pysros:SOFT-8495 to master

* commit 'fb4f3a679005ca4f7202d4acd3fa97e7c0e23feb':
  Replacing dependency_links which does not work with tox
  Add copyright
  Add packaging and QA
  Remove redundant variable
  Correct setup.py
  Add setup, requirements and decorator
  Create command line script
  Initial Commit
  • Loading branch information
linx-riccardo committed Jul 28, 2021
2 parents b360571 + fb4f3a6 commit 7bcbb02
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# pySROS
Python library to interact with Nokia SROS napalm driver.

## License

Copyright 2021 LINX

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
2 changes: 2 additions & 0 deletions configuration/config.yml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
username: xxx
password: xxx
24 changes: 24 additions & 0 deletions pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[MASTER]
extension-pkg-whitelist=lxml

[MESSAGES CONTROL]
disable=fixme,
no-value-for-parameter,
too-few-public-methods,
not-callable,
no-name-in-module,
argument-differ,
missing-module-docstring

[BASIC]
good-names=e,i,j,k
# Enabling two chars variables
argument-rgx=(([a-z_][a-z0-9_]{1,})|(_[a-z0-9_]*)|(__[a-z][a-z0-9_]+__))$
attr-rgx=(([a-z_][a-z0-9_]{1,})|(_[a-z0-9_]*)|(__[a-z][a-z0-9_]+__))$
variable-rgx=(([a-z_][a-z0-9_]{1,})|(_[a-z0-9_]*)|(__[a-z][a-z0-9_]+__))$

[TYPECHECK]
ignored-classes=optparse.Values,thread._local,_thread._local,linxapi.LinxClient

[REPORTS]
reports=yes
3 changes: 3 additions & 0 deletions pysros/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright (c) 2021 London Internet Exchange Ltd.

__version__ = "0.0.1"
165 changes: 165 additions & 0 deletions pysros/command_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Copyright (c) 2021 London Internet Exchange Ltd.

import argparse
import logging
import textwrap
import time

import napalm # pylint: disable=import-error
import yaml # pylint: disable=import-error

logging.basicConfig()
# logging.getLogger('').setLevel(logging.DEBUG)


def time_func(func):
""" Decorator adding the execution time for the decorated function """
def wrapper():
t1 = time.time()
func()
t2 = time.time()
print(f'Function: "{func.__name__}", completed in: "{t2 - t1}" s')
return wrapper


def parse_and_get_args():
"""
Create arg parser.
Returns: argparse.ArgumentParser
"""
parser = argparse.ArgumentParser(
description='Diff and Replace/Merge configs.',
formatter_class=argparse.RawTextHelpFormatter
)

parser.add_argument(
'config_file_path',
help='Config file with user details like username and password',
)

parser.add_argument(
'hostname',
help='Hostname of the switch',
)

parser.add_argument(
'action',
choices=[
'diff',
'replace',
'merge',
'running'
],
help=textwrap.dedent("""
Please choose one action from below
'diff' Compare Running config with Candidate config.
'replace' Replace Running config with Candidate config.
'merge' Merge Candidate config with Running config.
'running' Get running config from switch and save it to a file.
"""),
)

parser.add_argument(
'-s',
'--save-config-file-path',
dest='save_config_file_path',
default="running.conf",
help=textwrap.dedent("""
File path to save running config in.
If no path is given than file will be saved in current dir
with hostname-action.xml. For example for running config with
hostname foo.bar foo.bar-running.xml will be created.
""")
)

parser.add_argument(
'-f',
'--format',
dest='format',
choices=["xml", "cli"],
default="xml",
help=textwrap.dedent("""
The format in which interact with the Nokia device.
If using a payload its format will overwrite this option.
""")
)

parser.add_argument(
'-c',
'--candidate-file-path',
dest='candidate_file_path',
help='Candidate file path',
)

parser.add_argument(
'-v',
'--verbosity',
action='count',
default=0,
help=textwrap.dedent("""
Set logging verbose level. It accepts a number >= 0.
The default value is 0,
the minimal log besides stack backtrace is given;
Verbose level 1 enables debug level logging for pyocnos;
Verbose level 2 emits ncclient debug level logging as well.
""")
)

args = parser.parse_args()
if any(action in args.action for action in
['diff', 'replace', 'merge']) and not args.candidate_file_path:
parser.error(
"diff, replace and merge action requires -c,"
" --candidate-file-path."
)
return args


@time_func
def main():
""" Main function """
args = parse_and_get_args()
config_path = args.config_file_path
switch_name = args.hostname
operation = args.action
running_conf_path = args.save_config_file_path
candidate_conf_path = args.candidate_file_path
config_format = args.format

with open(config_path) as config_file:
config = yaml.safe_load(config_file)['config']

driver = napalm.get_network_driver('sros')
with driver(hostname=switch_name,
username=config['username'],
timeout=180,
password=config['password']) as device:
if operation == 'running':
# pylint: disable=unexpected-keyword-arg
result = device.get_config(retrieve='running',
optional_args={"format": config_format}
)
with open(running_conf_path, 'w') as running:
running.write(result['running'])

elif operation == 'merge':
device.load_merge_candidate(filename=candidate_conf_path)
device.commit_config()

elif operation == 'replace':
device.load_replace_candidate(filename=candidate_conf_path)
device.commit_config()

elif operation == 'diff':
device.load_replace_candidate(filename=candidate_conf_path)
# pylint: disable=unexpected-keyword-arg
print(device.compare_config(optional_args={"json_format": True}))


if __name__ == '__main__':
main()
32 changes: 32 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python
""" Python simple CLI to interact with Nokia Napalm driver. """

from setuptools import setup, find_packages

version = '0.0.1'
setup(
name='pysros',
version=version,
py_modules=['pysros'],
packages=find_packages(),
install_requires=[
"napalm==3.3.1",
"napalm-sros@git+https://[email protected]/napalm-automation-community/"
"napalm-sros.git",
"PyYAML"
],
include_package_data=True,
description='Python simple CLI to interact with Nokia Napalm Driver',
author='LINX',
author_email='[email protected]',
url='https://github.com/LINXNet/pysros/',
download_url='https://github.com/LINXNet/pysros/tarball/%s' % version,
keywords=['SROS', 'networking'],
classifiers=[
'Programming Language :: Python :: 3'
],
python_requires='~=3.6.6',
entry_points={
'console_scripts': ['pysros=pysros.command_line:main'],
}
)
4 changes: 4 additions & 0 deletions tests/test_basic_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) 2021 London Internet Exchange Ltd.

def test():
""" test """
26 changes: 26 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tox]
envlist = py3-test,py3-lint,py3-flake8
module = pysros

[tox:jenkins]
envlist = py3-test-jenkins,py3-lint-jenkins,py3-flake8

[testenv]
deps=
test: pytest
test: pytest-cov
lint: pylint
flake8: flake8
flake8: flake8-import-order
install_command = pip install --extra-index-url https://dist.linx.net/linx-python {opts} {packages}
whitelist_externals = bash
commands=
test: py.test --cov={envsitepackagesdir}/{[tox]module} --cov-report=xml --cov-report=term-missing --junitxml=test_report_{envname}.xml {posargs}
lint: pylint {[tox]module} tests
# Check that all .py files contain the copyright
lint: bash -c 'for file in $(find {[tox]module} tests -name "*.py" -print); do if ! grep -q "# Copyright (c) [0-9,-]* London Internet Exchange Ltd." $file; then echo "ERROR: Missing copyright in " $file; exit 1; fi; done'
flake8: flake8 {[tox]module} tests --import-order-style=google --application-import-names={[tox]module}
recreate = jenkins: True

[pytest]
junit_family=xunit2

0 comments on commit 7bcbb02

Please sign in to comment.