Skip to content

Commit

Permalink
Merge pull request #69 from nautobot/develop
Browse files Browse the repository at this point in the history
2.3.0 release
  • Loading branch information
jvanderaa authored Oct 28, 2022
2 parents 95bafff + 86c0549 commit 28160df
Show file tree
Hide file tree
Showing 12 changed files with 975 additions and 802 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9"]
python-version: ["3.7", "3.8", "3.9", "3.10"]
runs-on: "ubuntu-20.04"
env:
PYTHON_VER: "${{ matrix.python-version }}"
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v2.3.0

- (#67) fix pylint, tests, and drop py36 support #67

## v2.2.0

- (#41) Added jinja2 filter pass to generate config
Expand Down
2 changes: 1 addition & 1 deletion docs/task/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ task.run(
)
```

The dispatcher expects the two primary objects, the `obj` and `logger` objects. The `obj` object should be a Device model instance. The logger should be `NornirLogger` instance which is imported from `nornir_nautobot.utils.logger`. This logging object optionally takes in a Nautobot job_result object. This is for use within the Nautobot platform Jobs.
The dispatcher expects the two primary objects, the `obj` and `logger` objects. The `obj` object should be a Device model instance. The logger should be `NornirLogger` instance which is imported from `nornir_nautobot.utils.logger`. This logging object optionally takes in a Nautobot Job object named nautobot_job. This is for use within the Nautobot platform Jobs.

Each task will raise a `NornirNautobotException` for known issues. Using a custom processor, the user can predict when it was an well known error.
11 changes: 5 additions & 6 deletions nornir_nautobot/plugins/processors/get_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import hashlib
import logging
import os

from pathlib import Path

from nornir.core.inventory import Host
Expand All @@ -24,9 +23,9 @@ class GetConfig(BaseProcessor):

def __init__(self) -> None:
"""Initialize the processor and ensure some variables are properly initialized."""
self.current_md5 = dict()
self.previous_md5 = dict()
self.config_filename = dict()
self.current_md5 = {}
self.previous_md5 = {}
self.config_filename = {}
self.config_dir = None
self.existing_config_hostnames = None

Expand Down Expand Up @@ -76,7 +75,7 @@ def subtask_instance_started(self, task: Task, host: Host) -> None:
self.config_filename[host.name] = f"{self.config_dir}/{task.host.name}.{self.config_extension}"

if os.path.exists(self.config_filename[host.name]):
current_config = Path(self.config_filename[host.name]).read_text()
current_config = Path(self.config_filename[host.name]).read_text(encoding="utf-8")
self.previous_md5[host.name] = hashlib.md5(current_config.encode("utf-8")).hexdigest() # nosec

def subtask_instance_completed(self, task: Task, host: Host, result: MultiResult) -> None:
Expand Down Expand Up @@ -121,7 +120,7 @@ def subtask_instance_completed(self, task: Task, host: Host, result: MultiResult
self.existing_config_hostnames.remove(host.name)

# Save configuration to file and verify the new MD5
with open(self.config_filename[host.name], "w") as config_:
with open(self.config_filename[host.name], "w", encoding="utf-8") as config_:
config_.write(conf)

host.data["has_config"] = True
Expand Down
2 changes: 1 addition & 1 deletion nornir_nautobot/plugins/tasks/dispatcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"cisco_asa": "nornir_nautobot.plugins.tasks.dispatcher.cisco_asa.NautobotNornirDriver",
"cisco_nxos": "nornir_nautobot.plugins.tasks.dispatcher.cisco_nxos.NautobotNornirDriver",
"cisco_ios": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios.NautobotNornirDriver",
"cisco_xr": "nornir_nautobot.plugins.tasks.dispatcher.cisco_xr.NautobotNornirDriver",
"cisco_xr": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios_xr.NautobotNornirDriver",
"juniper_junos": "nornir_nautobot.plugins.tasks.dispatcher.juniper_junos.NautobotNornirDriver",
"arista_eos": "nornir_nautobot.plugins.tasks.dispatcher.arista_eos.NautobotNornirDriver",
}
Expand Down
34 changes: 19 additions & 15 deletions nornir_nautobot/plugins/tasks/dispatcher/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@
import os
import socket
from typing import Optional

import jinja2

from netmiko.ssh_exception import NetmikoAuthenticationException, NetmikoTimeoutException
try:
from netmiko.ssh_exception import NetmikoAuthenticationException, NetmikoTimeoutException
except ImportError:
from netmiko import NetmikoAuthenticationException, NetmikoTimeoutException

from netutils.config.clean import clean_config, sanitize_config
from netutils.config.compliance import compliance
from netutils.dns import is_fqdn_resolvable
from netutils.ip import is_ip
from netutils.ping import tcp_ping
from nornir.core.exceptions import NornirSubTaskError
from nornir.core.task import Result, Task
from nornir_jinja2.plugins.tasks import template_file
from nornir_napalm.plugins.tasks import napalm_get
from nornir_netmiko.tasks import netmiko_send_command
from netutils.config.compliance import compliance
from netutils.config.clean import clean_config, sanitize_config
from netutils.ip import is_ip
from netutils.dns import is_fqdn_resolvable
from netutils.ping import tcp_ping

from nornir_nautobot.exceptions import NornirNautobotException
from nornir_nautobot.utils.helpers import make_folder


RUN_COMMAND_MAPPING = {
"default": "show run",
"cisco_nxos": "show run",
Expand All @@ -41,7 +45,7 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su
Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
logger (NornirLogger): Custom NornirLogger object to reflect job results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
backup_file (str): The file location of where the back configuration should be saved.
remove_lines (list): A list of regex lines to remove configurations.
Expand Down Expand Up @@ -75,7 +79,7 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su

make_folder(os.path.dirname(backup_file))

with open(backup_file, "w") as filehandler:
with open(backup_file, "w", encoding="utf8") as filehandler:
filehandler.write(running_config)
return Result(host=task.host, result={"config": running_config})

Expand All @@ -85,7 +89,7 @@ def check_connectivity(task: Task, logger, obj) -> Result:
Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
logger (NornirLogger): Custom NornirLogger object to reflect job results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
Returns:
Expand Down Expand Up @@ -121,7 +125,7 @@ def compliance_config(
Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
logger (NornirLogger): Custom NornirLogger object to reflect job results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
features (dict): A dictionary describing the configurations required.
backup_file (str): The file location of where the back configuration should be saved.
Expand Down Expand Up @@ -160,7 +164,7 @@ def generate_config(
Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
logger (NornirLogger): Custom NornirLogger object to reflect job results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
jinja_template (str): The file location of the actual Jinja template.
jinja_root_path (str): The file folder where the file will be saved to.
Expand Down Expand Up @@ -203,7 +207,7 @@ def generate_config(
raise

make_folder(os.path.dirname(output_file_location))
with open(output_file_location, "w") as filehandler:
with open(output_file_location, "w", encoding="utf8") as filehandler:
filehandler.write(filled_template)
return Result(host=task.host, result={"config": filled_template})

Expand All @@ -217,7 +221,7 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su
Args:
task (Task): Nornir Task.
logger (NornirLogger): Custom NornirLogger object to reflect job_results (via Nautobot Jobs) and Python logger.
logger (NornirLogger): Custom NornirLogger object to reflect job results (via Nautobot Jobs) and Python logger.
obj (Device): A Nautobot Device Django ORM object instance.
remove_lines (list): A list of regex lines to remove configurations.
substitute_lines (list): A list of dictionaries with to remove and replace lines.
Expand Down Expand Up @@ -262,6 +266,6 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su

make_folder(os.path.dirname(backup_file))

with open(backup_file, "w") as filehandler:
with open(backup_file, "w", encoding="utf8") as filehandler:
filehandler.write(running_config)
return Result(host=task.host, result={"config": running_config})
31 changes: 19 additions & 12 deletions nornir_nautobot/utils/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,45 @@
class NornirLogger:
"""Similar to a mixin, to utilize Python logging and Jobs Result obj."""

def __init__(self, name, job_result=None, debug=False):
def __init__(self, name, nautobot_job=None, debug=False, job_result=None):
"""Initialize the object."""
self.job_result = job_result
self.job_result = job_result or nautobot_job
self.logger = logging.getLogger(name)
self.debug = debug
self.nautobot_job = nautobot_job or job_result
if job_result is not None:
log_message = (
"The arg named `job_result` has been renamed to `nautobot_job`; please update to use this name."
)
self.logger.warning(log_message)
job_result.log_warning(log_message)

def log_debug(self, message):
"""Debug, does not take obj, and only logs to jobs result when in global debug mode."""
if self.job_result and self.debug:
self.job_result.log_debug(message)
if self.nautobot_job and self.debug:
self.nautobot_job.log_debug(message)
self.logger.debug(message)

def log_info(self, obj, message):
"""Log to Python logger and jogs results for info messages."""
if self.job_result:
self.job_result.log_info(obj, message)
if self.nautobot_job:
self.nautobot_job.log_info(obj, message)
self.logger.info("%s | %s", str(obj), message)

def log_success(self, obj, message):
"""Log to Python logger and jogs results for success messages."""
if self.job_result:
self.job_result.log_success(obj, message)
if self.nautobot_job:
self.nautobot_job.log_success(obj, message)
self.logger.info("%s | %s", str(obj), message)

def log_warning(self, obj, message):
"""Log to Python logger and jogs results for warning messages."""
if self.job_result:
self.job_result.log_warning(obj, message)
if self.nautobot_job:
self.nautobot_job.log_warning(obj, message)
self.logger.warning("%s | %s", str(obj), message)

def log_failure(self, obj, message):
"""Log to Python logger and jogs results for failure messages."""
if self.job_result:
self.job_result.log_failure(obj, message)
if self.nautobot_job:
self.nautobot_job.log_failure(obj, message)
self.logger.error("%s | %s", str(obj), message)
Loading

0 comments on commit 28160df

Please sign in to comment.