Skip to content

Commit

Permalink
Version 2.3.0 (#61)
Browse files Browse the repository at this point in the history
* Change URLs in Usage to docs

* Update project description

* Add video presentation

* Closes #50: Add template field to ConfigDiffScript (#51)

* Add name template for searching in DataSource

* Add docs for templating files name in DataSource

* Closes #47: Move plugin to separete menu item in navbar (#52)

* Move plugin into separate menu item

* Add tab for devices with their config compliance

* Closes #53: Add netbox-rq to installation process docs

* Changelog for 2.2.0 version

* Handle junipers templates with set commands (#58)

* Reverse columns in diff (#59)

* Add python 3.12 and Netbox 3.7.5 in CI

* Add warning about using set commands in Juniper

* Version 2.3.0
  • Loading branch information
miaow2 authored Apr 11, 2024
1 parent fc45a92 commit d00fdf5
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
max-parallel: 10
matrix:
python: ["3.10", "3.11"]
python: ["3.10", "3.11", "3.12"]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -31,7 +31,7 @@ jobs:
strategy:
max-parallel: 10
matrix:
netbox_version: ["v3.5.9", "v3.6.9"]
netbox_version: ["v3.5.9", "v3.6.9", "v3.7.5"]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc

| NetBox Version | Plugin Version |
|----------------|----------------|
| 3.5, 3.6 | =>0.1.0 |
| 3.5, 3.6, 3.7 | =>0.1.0 |

<!--install-start-->
## Installing
Expand Down
6 changes: 6 additions & 0 deletions docs/configuratiom-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ Supported platforms:

Plugin using [scrapli-cfg](https://github.com/scrapli/scrapli_cfg) for this feature.

!!! warning
If you use Juniper and render config in set commands, please read next info.
Plugin uses `load override` command to load config to a device, set commands load with `load set`.
With `load set` commnad you can't replace all config, because this command uses `merge` action.
So, please, be careful when using set commands in rendering config and pushig it with plugin, it can have unexpected side effects.

## Substitutes

If you render not full configuration, it is acceptable to pull missing config sections from the actual configuration to render full configuration.
Expand Down
2 changes: 1 addition & 1 deletion netbox_config_diff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

__author__ = "Artem Kotik"
__email__ = "[email protected]"
__version__ = "2.2.0"
__version__ = "2.3.0"


class ConfigDiffConfig(PluginConfig):
Expand Down
2 changes: 1 addition & 1 deletion netbox_config_diff/compliance/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def __init__(self, choices, *args, **kwargs):

def get_unified_diff(rendered_config: str, actual_config: str, device: str) -> str:
diff = unified_diff(
rendered_config.strip().splitlines(),
actual_config.splitlines(),
rendered_config.strip().splitlines(),
fromfiledate=device,
tofiledate=device,
lineterm="",
Expand Down
2 changes: 1 addition & 1 deletion netbox_config_diff/configurator/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ async def _collect_one_diff(self, device: ConfiguratorDeviceDataClass) -> None:
)
device.rendered_config = rendered_config
else:
actual_config = await conn.get_config()
actual_config = await conn.get_config(config_template=device.rendered_config)
device.actual_config = conn.clean_config(actual_config.result)

device.diff = get_unified_diff(device.rendered_config, device.actual_config, device.name)
Expand Down
73 changes: 70 additions & 3 deletions netbox_config_diff/configurator/platforms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import re
from typing import Pattern
from typing import Any, Pattern

from scrapli_cfg.exceptions import TemplateError
from scrapli_cfg.platform.core.arista_eos import AsyncScrapliCfgEOS
Expand Down Expand Up @@ -94,13 +94,17 @@ async def render_substituted_config(
"""
self.logger.info("fetching configuration and replacing with provided substitutes")

source_config = await self.get_config(source=source)
source_config = await self.get_config(config_template=config_template, source=source)
return source_config, self._render_substituted_config(
config_template=config_template,
substitutes=substitutes,
source_config=source_config.result,
)

async def get_config(self, **kwargs) -> ScrapliCfgResponse:
kwargs.pop("config_template", None)
return await super().get_config(**kwargs)


class CustomAsyncScrapliCfgEOS(CustomScrapliCfg, AsyncScrapliCfgEOS):
pass
Expand All @@ -119,4 +123,67 @@ class CustomAsyncScrapliCfgNXOS(CustomScrapliCfg, AsyncScrapliCfgNXOS):


class CustomAsyncScrapliCfgJunos(CustomScrapliCfg, AsyncScrapliCfgJunos):
pass
is_set_config = False

async def get_config(self, config_template: str, source: str = "running") -> ScrapliCfgResponse:
response = self._pre_get_config(source=source)

command = "show configuration"
if re.findall(r"^set\s+", config_template, flags=re.I | re.M):
self.is_set_config = True
command += " | display set"

if self._in_configuration_session is True:
config_result = await self.conn.send_config(config=f"run {command}")
else:
config_result = await self.conn.send_command(command=command)

return self._post_get_config(
response=response,
source=source,
scrapli_responses=[config_result],
result=config_result.result,
)

async def load_config(self, config: str, replace: bool = False, **kwargs: Any) -> ScrapliCfgResponse:
"""
Load configuration to a device
Supported kwargs:
set: bool indicating config is a "set" style config (ignored if replace is True)
Args:
config: string of the configuration to load
replace: replace the configuration or not, if false configuration will be loaded as a
merge operation
kwargs: additional kwargs that the implementing classes may need for their platform,
see above for junos supported kwargs
Returns:
ScrapliCfgResponse: response object
Raises:
N/A
"""
response = self._pre_load_config(config=config)

config = self._prepare_load_config(config=config, replace=replace)

config_result = await self.conn.send_config(config=config, privilege_level="root_shell")

if self.is_set_config is True:
load_config = f"load set {self.filesystem}{self.candidate_config_filename}"
else:
if self._replace is True:
load_config = f"load override {self.filesystem}{self.candidate_config_filename}"
else:
load_config = f"load merge {self.filesystem}{self.candidate_config_filename}"

load_result = await self.conn.send_config(config=load_config)
self._in_configuration_session = True

return self._post_load_config(
response=response,
scrapli_responses=[config_result, load_result],
)
2 changes: 1 addition & 1 deletion tests/test_compliance_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ def test_exclude_lines(regex: str, expected: str) -> None:
ids=["diff", "no diff"],
)
def test_get_unified_diff(render: str, actual: str, expected: str) -> None:
assert get_unified_diff(render, actual, "test-1") == expected
assert get_unified_diff(actual, render, "test-1") == expected

0 comments on commit d00fdf5

Please sign in to comment.