Skip to content

Commit

Permalink
Handle junipers templates with set commands (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
miaow2 authored Apr 9, 2024
1 parent 79c3ec3 commit a757ac7
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 4 deletions.
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],
)

0 comments on commit a757ac7

Please sign in to comment.