Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds merge_config method #98

Merged
merged 4 commits into from
Aug 10, 2023
Merged
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
144 changes: 99 additions & 45 deletions nornir_nautobot/plugins/tasks/dispatcher/default.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""default driver for the network_importer."""
# pylint: disable=raise-missing-from,too-many-arguments

import logging
import os
import socket
from typing import Optional
Expand All @@ -27,6 +28,9 @@
from nornir_nautobot.utils.helpers import make_folder


_logger = logging.getLogger(__name__)


class NautobotNornirDriver:
"""Default collection of Nornir Tasks based on Napalm."""

Expand Down Expand Up @@ -276,6 +280,101 @@ def _save_file(logger, backup_file: str, _running_config: str) -> None:
with open(backup_file, "w", encoding="utf8") as filehandler:
filehandler.write(_running_config)

def provision_config(self, *args, **kwargs):
"""This method is being deprecated. Please use replace_config instead."""
_logger.warning(
"WARNING: The method 'provision_config()' will be removed in the next major release. Please use 'replace_config()' instead."
)
return self.replace_config(*args, **kwargs)

@staticmethod
def replace_config(
task: Task,
logger,
obj,
config: str,
) -> Result:
"""Push candidate configuration to the device.

Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
config (str): The candidate config.

Raises:
NornirNautobotException: Authentication error.
NornirNautobotException: Timeout error.
NornirNautobotException: Other exception.

Returns:
Result: Nornir Result object with a dict as a result containing what changed and the result of the push.
"""
logger.log_success(obj, "Config provision starting")
# Sending None to napalm_configure for revert_in will disable it, so we don't want a default value.
revert_in = os.getenv("NORNIR_NAUTOBOT_REVERT_IN_SECONDS")
if revert_in is not None:
revert_in = int(revert_in)

try:
push_result = task.run(
task=napalm_configure,
configuration=config,
replace=True,
revert_in=revert_in,
)
except NornirSubTaskError as exc:
logger.log_failure(obj, f"Failed with an unknown issue. `{exc.result.exception}`")
raise NornirNautobotException()

logger.log_success(obj, f"result: {push_result[0].result}, changed: {push_result.changed}")
logger.log_success(obj, "Config provision ended")
return Result(host=task.host, result={"changed": push_result.changed, "result": push_result[0].result})

@staticmethod
def merge_config(
task: Task,
logger,
obj,
config: str,
) -> Result:
"""Send configuration to merge on the device.

Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
config (str): The config set.

Raises:
NornirNautobotException: Authentication error.
NornirNautobotException: Timeout error.
NornirNautobotException: Other exception.

Returns:
Result: Nornir Result object with a dict as a result containing what changed and the result of the push.
"""
logger.log_success(obj, "Config merge starting")
# Sending None to napalm_configure for revert_in will disable it, so we don't want a default value.
revert_in = os.getenv("NORNIR_NAUTOBOT_REVERT_IN_SECONDS")
if revert_in is not None:
revert_in = int(revert_in)

try:
push_result = task.run(
task=napalm_configure,
configuration=config,
replace=False,
revert_in=revert_in,
)
except NornirSubTaskError as exc:
logger.log_failure(obj, f"Failed with an unknown issue. `{exc.result.exception}`")
raise NornirNautobotException()

logger.log_success(obj, f"result: {push_result[0].result}, changed: {push_result.changed}")
logger.log_success(obj, "Config merge ended")
return Result(host=task.host, result={"changed": push_result.changed, "result": push_result[0].result})


class NetmikoNautobotNornirDriver(NautobotNornirDriver):
"""Default collection of Nornir Tasks based on Netmiko."""
Expand Down Expand Up @@ -338,48 +437,3 @@ def get_config(
with open(backup_file, "w", encoding="utf8") as filehandler:
filehandler.write(running_config)
return Result(host=task.host, result={"config": running_config})

@staticmethod
def provision_config(
task: Task,
logger,
obj,
config: str,
) -> Result:
"""Push candidate configuration to the device.

Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
config (str): The candidate config.

Raises:
NornirNautobotException: Authentication error.
NornirNautobotException: Timeout error.
NornirNautobotException: Other exception.

Returns:
Result: Nornir Result object with a dict as a result containing the running configuration
{ "config: <running configuration> }
"""
logger.log_success(obj, "Config provision starting")
# Sending None to napalm_configure for revert_in will disable it, so we don't want a default value.
revert_in = os.getenv("NORNIR_NAUTOBOT_REVERT_IN_SECONDS")
if revert_in is not None:
revert_in = int(revert_in)

try:
push_result = task.run(
task=napalm_configure,
configuration=config,
replace=True,
revert_in=revert_in,
)
except NornirSubTaskError as exc:
logger.log_failure(obj, f"Failed with an unknown issue. `{exc.result.exception}`")
raise NornirNautobotException()

logger.log_success(obj, f"result: {push_result[0].result}, changed: {push_result.changed}")
logger.log_success(obj, "Config provision ended")
return Result(host=task.host, result={"changed": push_result.changed, "result": push_result[0].result})