Skip to content

Commit

Permalink
get running configed based on devicetypes in DEVICE_TYPES_WITH_INCLUD…
Browse files Browse the repository at this point in the history
…E_RUNNING_CONFIG, to be used together with jinja filter like: {{ running_config|get_config_section(firewall, junos) }}
  • Loading branch information
indy-independence committed Oct 21, 2024
1 parent b21ff9b commit 2806339
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
4 changes: 3 additions & 1 deletion src/cnaas_nms/app_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Optional
from typing import List, Optional

import yaml
from pydantic import field_validator
Expand Down Expand Up @@ -57,6 +57,7 @@ class ApiSettings(BaseSettings):
COMMIT_CONFIRMED_TIMEOUT: int = 300
COMMIT_CONFIRMED_WAIT: int = 1
SETTINGS_OVERRIDE: Optional[dict] = None
DEVICE_TYPES_WITH_INCLUDE_RUNNING_CONFIG: List[str] = []

@field_validator("MGMTDOMAIN_PRIMARY_IP_VERSION")
@classmethod
Expand Down Expand Up @@ -118,6 +119,7 @@ def construct_api_settings() -> ApiSettings:
COMMIT_CONFIRMED_TIMEOUT=config.get("commit_confirmed_timeout", 300),
COMMIT_CONFIRMED_WAIT=config.get("commit_confirmed_wait", 1),
SETTINGS_OVERRIDE=config.get("settings_override", None),
DEVICE_TYPES_WITH_INCLUDE_RUNNING_CONFIG=config.get("device_types_with_include_running_config", []),
)
else:
return ApiSettings()
Expand Down
17 changes: 15 additions & 2 deletions src/cnaas_nms/devicehandler/sync_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def get_mlag_vars(session, dev: Device) -> dict:


def populate_device_vars(
session, dev: Device, ztp_hostname: Optional[str] = None, ztp_devtype: Optional[DeviceType] = None
task, session, dev: Device, ztp_hostname: Optional[str] = None, ztp_devtype: Optional[DeviceType] = None
):
logger = get_logger()
device_variables = {
Expand Down Expand Up @@ -352,6 +352,19 @@ def populate_device_vars(
)
device_variables = {**device_variables, **fabric_device_variables}

# if device type in api_settings.DEVICE_TYPES_WITH_INCLUDE_RUNNING_CONFIG
for dt_str in api_settings.DEVICE_TYPES_WITH_INCLUDE_RUNNING_CONFIG:
if dev.device_type.name.lower() == dt_str.lower():
res = task.run(task=napalm_get, getters=["config"])

running_config = dict(res.result)["config"]["running"]
# Remove the first task result, which is the napalm_get result, since it's not needed anymore
del task.results[0]
if running_config is None:
raise Exception(f"Failed to get running configuration for {dev.hostname}")

device_variables["running_config"] = running_config

# Add all environment variables starting with TEMPLATE_SECRET_ to
# the list of configuration variables. The idea is to store secret
# configuration outside of the templates repository.
Expand Down Expand Up @@ -505,7 +518,7 @@ def push_sync_device(
hostname = task.host.name
with sqla_session() as session:
dev: Device = session.query(Device).filter(Device.hostname == hostname).one()
template_vars = populate_device_vars(session, dev)
template_vars = populate_device_vars(task, session, dev)
platform = dev.platform
devtype = dev.device_type

Expand Down
51 changes: 36 additions & 15 deletions src/cnaas_nms/tools/jinja_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@
import ipaddress
import re
from typing import Any, Callable, Optional, Union
from netutils.config.parser import BaseConfigParser, JunosConfigParser

from netutils.config.parser import (
BaseConfigParser,
EOSConfigParser,
IOSConfigParser,
IOSXRConfigParser,
JunosConfigParser,
NXOSConfigParser,
)

# This global dict can be used to update the Jinja environment filters dict to include all
# registered template filter function
Expand Down Expand Up @@ -214,28 +222,41 @@ def md5(s: str) -> str:


@template_filter()
def get_config_block_regex(config:str, section: str = "firewall", parser: Optional[BaseConfigParser] = JunosConfigParser) -> str:
def get_config_section(config: str, section: str, parser: str) -> str:
"""
Get the configuration block for a specific section.
Args:
config (str): The config used to for parsing and search a specific section.
section (str, optional): The section to retrieve. Defaults to "firewall". Regex can be used as ^(firewall)\s*\{
parser (str, optional): The parser corresponding to the config type. Defaults to "JunosConfigParser".
section (str): The section to retrieve. Regex can be used as "^(firewall)\s*\{"
parser (str): The parser corresponding to the config type, e.g. junos, eos, nxos, iosxr, ios.
Returns:
str: The text of the configuration block if found, empty string otherwise.
test:
get_config_block_regex(config=firewall_config, section="firewall")
"""

config_parser = parser(config)
config_relationship = config_parser.build_config_relationship()
get_config_section(config=firewall_config, section="firewall", parser="junos")
""" # noqa: W605
if parser.lower() == "junos":
parser_obj = JunosConfigParser
elif parser.lower() == "eos":
parser_obj = EOSConfigParser
elif parser.lower() == "nxos":
parser_obj = NXOSConfigParser
elif parser.lower() == "iosxr":
parser_obj = IOSXRConfigParser
elif parser.lower() == "ios":
parser_obj = IOSConfigParser
else:
parser_obj = BaseConfigParser
config_parser = parser_obj(config)
config_parser.build_config_relationship()
children = config_parser.find_all_children(section, match_type="regex")


if len(children) == 1:
return children[0]
if len(children) > 1:
collect = "\n".join(children)
return collect + "\n}" if isinstance(config_parser, JunosConfigParser) else collect
return []

return ""

0 comments on commit 2806339

Please sign in to comment.