Skip to content
This repository has been archived by the owner on Nov 15, 2024. It is now read-only.

Ntc rosetta #25

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion netnir/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
doesn't exist, netnir will create the default config and folders.
"""

__version__ = "0.0.20"
__version__ = "0.0.21"
2 changes: 1 addition & 1 deletion netnir/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def __init__(self):
self.plugins = NETNIR_CONFIG["plugins"]
self.parser = MyParser(prog="netnir")
self.parser.add_argument(
"--version", default=False, action="store_true", help="display version"
"--version", default=False, action="store_true", help="display version",
)
subparsers = self.parser.add_subparsers(title="netnir commands", dest="command")
self.loaded_plugins = plugins_import(tasks=self.plugins, subparsers=subparsers)
Expand Down
2 changes: 1 addition & 1 deletion netnir/core/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, **kwargs):
initialize the NornirInventory class and load the data into nornir
"""
super().__init__(
hosts=self.nhosts(), groups=self.ngroups(), defaults=self.ndefaults()
hosts=self.nhosts(), groups=self.ngroups(), defaults=self.ndefaults(),
)

def nhosts(self):
Expand Down
20 changes: 20 additions & 0 deletions netnir/helpers/common/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,23 @@ def netconf_capabilities(parser, required: bool = False):
nargs="?",
const=True,
)


def config_to_yang(parser, required: bool = False) -> None:
"""
common argument to convert configuration text to a yang model via the
--config-to-yang flag.
"""
parser.add_argument(
"--config-to-yang", help="convert configuration text to a yang model",
)


def yang_to_config(parser, required: bool = False) -> None:
"""
common argument to convert yang model to configuration text via the
--yang-to-config flag.
"""
parser.add_argument(
"--yang-to-config", help="convert configuration text to a yang model",
)
14 changes: 7 additions & 7 deletions netnir/helpers/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@
"output": "./output",
"hier": "./conf/hier",
},
"domain": "example.net",
"domain": None,
"nornir": {"config": "./conf/nornir.yaml"},
"plugins": {
"user": {
"class": "netnir.core.tasks.user.User",
"class": "netnir.plugins.tasks.user.User",
"description": "netnir user commands",
},
"inventory": {
"class": "netnir.core.tasks.inventory.Inventory",
"class": "netnir.plugins.tasks.inventory.Inventory",
"description": "inventory search command",
},
"cp": {
"class": "netnir.core.tasks.config_plan.ConfigPlan",
"class": "netnir.plugins.tasks.config_plan.ConfigPlan",
"description": "config plan commands",
},
"ssh": {
"class": "netnir.core.tasks.ssh.Ssh",
"class": "netnir.plugins.tasks.ssh.Ssh",
"description": "command and config execution over SSH",
},
"netconf": {
"class": "netnir.core.tasks.netconf.NetConf",
"class": "netnir.plugins.tasks.netconf.NetConf",
"description": "command and config execution over NETCONF",
},
"fetch": {
"class": "netnir.core.tasks.fetch.Fetch",
"class": "netnir.plugins.tasks.fetch.Fetch",
"description": "fetch commands",
},
},
Expand Down
2 changes: 1 addition & 1 deletion netnir/plugins/hier.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def hier_host(
)

host = Host(
hostname=task.host.name, os=operating_system, hconfig_options=hier_options
hostname=task.host.name, os=operating_system, hconfig_options=hier_options,
)
host.load_config_from(
config_type="running", name=running_config, load_file=load_file
Expand Down
43 changes: 43 additions & 0 deletions netnir/plugins/rosetta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
def convert_config_to_yang(operating_system: str, config_file: str):
"""
convert a config string into a yang model

:param operating_system: type str
:param config_file: configuration file from CWD

:returns: YANG output in JSON format
"""
from ntc_rosetta import get_driver
import json

with open(config_file) as f:
config_string = f.read()

os_driver = get_driver(operating_system, "openconfig")
driver = os_driver()
parsed = driver.parse(native={"dev_conf": config_string})

return json.dumps(parsed.raw_value(), indent=2)


def convert_yang_to_config(operating_system: str, yang_file: str):
"""
convert a yang model to configuration text

:param operating_system: type str
:param yang_file: yang file from CWD

:returns: configuration text
"""
from ntc_rosetta import get_driver
import json

with open(yang_file) as f:
yang_string = f.read()
yang_model = json.loads(yang_string)

os_driver = get_driver(operating_system, "openconfig")
driver = os_driver()
config_text = driver.translate(candidate=yang_model)

return config_text
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def run(self):
to_console=self._verbose()["to_console"],
)
output_writer(nornir_results=results, output_file="compiled.conf")
print_result(results)
print_result(result=results, severity_level=self._verbose()["level"])

if self.args.compile:
return results
Expand All @@ -77,7 +77,7 @@ def run(self):
to_console=self._verbose()["to_console"],
)
output_writer(nornir_results=results, output_file="running.conf")
print_result(results)
print_result(result=results, severity_level=self._verbose()["level"])

results = self.nr.run(
task=hier_host,
Expand All @@ -94,7 +94,6 @@ def run(self):
to_console=self._verbose()["to_console"],
)
output_writer(nornir_results=results, output_file="remediation.conf")

print_result(result=results, severity_level=self._verbose()["level"])

return results
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Fetch(SubCommandParser):
title = "fetch commands"
tasks = {
"config": {
"class": "netnir.core.tasks.fetch.config.FetchConfig",
"class": "netnir.plugins.tasks.fetch.config.FetchConfig",
"description": "fetch current config from a network device",
},
}
Expand Down
File renamed without changes.
File renamed without changes.
3 changes: 1 addition & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ filterwarnings =
addopts =
-vv
--cov=netnir tests/
--cov-report term-missing
--black netnir
--flake8 netnir
python_files = tests/*/*.py
flake8-max-line-length = 127
flake8-ignore =
netnir/core/__init__.py F401
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"hier_config==v1.6.1",
"keyring>=21.2.1",
"keyrings.alt>=3.4.0",
"ntc-rosetta>=v0.2.0",
"dataclasses<0.7.0,>=0.6.0",
],
tests_require=[
"pytest",
Expand Down
45 changes: 45 additions & 0 deletions tests/data/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"openconfig-interfaces:interfaces": {
"interface": [
{
"name": "FastEthernet1",
"config": {
"name": "FastEthernet1",
"type": "iana-if-type:ethernetCsmacd",
"description": "This is Fa1",
"enabled": false
}
}
]
},
"openconfig-network-instance:network-instances": {
"network-instance": [
{
"name": "default",
"config": {
"name": "default"
},
"vlans": {
"vlan": [
{
"vlan-id": 10,
"config": {
"vlan-id": 10,
"name": "prod",
"status": "ACTIVE"
}
},
{
"vlan-id": 20,
"config": {
"vlan-id": 20,
"name": "dev",
"status": "SUSPENDED"
}
}
]
}
}
]
}
}
15 changes: 15 additions & 0 deletions tests/data/config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface FastEthernet1
description This is Fa1
shutdown
exit
!
vlan 10
name prod
no shutdown
exit
!
vlan 20
name dev
shutdown
exit
!
12 changes: 6 additions & 6 deletions tests/data/netnir.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ nornir:

plugins:
cp:
class: netnir.core.tasks.config_plan.ConfigPlan
class: netnir.plugins.tasks.config_plan.ConfigPlan
description: "config plan commands"
fetch:
class: netnir.core.tasks.fetch.Fetch
class: netnir.plugins.tasks.fetch.Fetch
description: fetch commands
inventory:
class: netnir.core.tasks.inventory.Inventory
class: netnir.plugins.tasks.inventory.Inventory
description: "inventory search command"
user:
class: netnir.core.tasks.user.User
class: netnir.plugins.tasks.user.User
description: "netnir user commands"
ssh:
class: netnir.core.tasks.ssh.Ssh
class: netnir.plugins.tasks.ssh.Ssh
description: "command and config execution over SSH"
netconf:
class: netnir.core.tasks.netconf.NetConf
class: netnir.plugins.tasks.netconf.NetConf
description: "command and config execution over NETCONF"
10 changes: 8 additions & 2 deletions tests/netnir/helpers/test_filter_type.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
def test_filter_type(initial_setup):
from netnir.helpers import filter_type

assert filter_type(host="router.dc1") == {"type": "host", "data": "router.dc1"}
assert filter_type(host="router.dc1") == {
"type": "host",
"data": "router.dc1",
}
assert filter_type(group="dc1") == {"type": "group", "data": "dc1"}
assert filter_type(filter="os:iosxr") == {"type": "filter", "data": "os:iosxr"}
assert filter_type(filter="os:iosxr") == {
"type": "filter",
"data": "os:iosxr",
}
12 changes: 6 additions & 6 deletions tests/netnir/helpers/test_netnir_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ def test_netnir_config(initial_setup):
"nornir": {"config": "./tests/data/nornir.yaml"},
"plugins": {
"user": {
"class": "netnir.core.tasks.user.User",
"class": "netnir.plugins.tasks.user.User",
"description": "netnir user commands",
},
"inventory": {
"class": "netnir.core.tasks.inventory.Inventory",
"class": "netnir.plugins.tasks.inventory.Inventory",
"description": "inventory search command",
},
"cp": {
"class": "netnir.core.tasks.config_plan.ConfigPlan",
"class": "netnir.plugins.tasks.config_plan.ConfigPlan",
"description": "config plan commands",
},
"ssh": {
"class": "netnir.core.tasks.ssh.Ssh",
"class": "netnir.plugins.tasks.ssh.Ssh",
"description": "command and config execution over SSH",
},
"netconf": {
"class": "netnir.core.tasks.netconf.NetConf",
"class": "netnir.plugins.tasks.netconf.NetConf",
"description": "command and config execution over NETCONF",
},
"fetch": {
"class": "netnir.core.tasks.fetch.Fetch",
"class": "netnir.plugins.tasks.fetch.Fetch",
"description": "fetch commands",
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def test_tasks_config_plan():
from netnir.core.tasks.config_plan import ConfigPlan
from netnir.plugins.tasks.config_plan import ConfigPlan
from netnir.helpers.common.args import (
filter_group,
filter_host,
Expand All @@ -8,6 +8,8 @@ def test_tasks_config_plan():
verbose,
num_workers,
make_changes,
config_to_yang,
yang_to_config,
)
import argparse

Expand All @@ -19,6 +21,8 @@ def test_tasks_config_plan():
verbose(parser)
num_workers(parser)
make_changes(parser)
config_to_yang(parser)
yang_to_config(parser)
parser.add_argument("--compile", const=True, nargs="?")
parser.add_argument("--include-tags", action="append")
parser.add_argument("--exclude-tags", action="append")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def test_tasks_inventory():
from netnir.core.tasks.inventory import Inventory
from netnir.plugins.tasks.inventory import Inventory
from netnir.helpers.common.args import (
filter_group,
filter_hosts,
Expand Down
22 changes: 22 additions & 0 deletions tests/netnir/plugins/tasks/test_tasks_rosetta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
def test_rosetta_config_to_yang():
from netnir.plugins.rosetta import convert_config_to_yang
import json

with open("./tests/data/config.json") as f:
data = f.read()
model = json.loads(data)

config = json.loads(convert_config_to_yang("ios", "./tests/data/config.txt"))

assert config == model


def test_rosetta_yang_to_config():
from netnir.plugins.rosetta import convert_yang_to_config

with open("./tests/data/config.txt") as f:
config = f.read()

model = convert_yang_to_config("ios", "./tests/data/config.json")

assert model == config