Skip to content

Commit

Permalink
Merge pull request #314 from networktocode/develop
Browse files Browse the repository at this point in the history
Release 2.0.1
  • Loading branch information
jeffkala authored Sep 14, 2024
2 parents 3014dfa + aa806ed commit 510aa8c
Show file tree
Hide file tree
Showing 20 changed files with 689 additions and 583 deletions.
8 changes: 8 additions & 0 deletions docs/admin/release_notes/version_2_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@
- [308](https://github.com/networktocode/pyntc/pull/308) Deprecated netmiko argument `delay_factor` in favor of `read_timeout` as per changes in Netmiko 4.0.

Refer to this blog post for more info about changes in netmiko 4.0: https://pynet.twb-tech.com/blog/netmiko-read-timeout.html


## [2.0.1] 09-2024
### Added
- [311](https://github.com/networktocode/pyntc/pull/311) Extend cisco_ios set_boot_options method.

### Fixed
- [312](https://github.com/networktocode/pyntc/pull/312) Fix Arista EOS file copy issues.
1,211 changes: 645 additions & 566 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyntc/devices/asa_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def _get_ipv4_addresses(self, host: str) -> Dict[str, List[IPv4Address]]:
elif host == "peer":
command = "failover exec mate show ip address"

show_ip_address = self.show(command)
show_ip_address = self.show(command) # pylint: disable=possibly-used-before-assignment
re_ip_addresses = RE_SHOW_IP_ADDRESS.findall(show_ip_address)

results = {
Expand Down Expand Up @@ -188,7 +188,7 @@ def _get_ipv6_addresses(self, host: str) -> Dict[str, List[IPv6Address]]:
elif host == "peer":
command = "failover exec mate show ipv6 interface"

show_ipv6_interface = self.show(command)
show_ipv6_interface = self.show(command) # pylint: disable=possibly-used-before-assignment
show_ipv6_interface_lines: List[str] = show_ipv6_interface.strip().splitlines()
first_line = show_ipv6_interface_lines.pop(0)
interface: str = first_line.split()[0]
Expand Down
9 changes: 6 additions & 3 deletions pyntc/devices/eos_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ def __init__(self, host, username, password, transport="http", port=None, timeou
self._connected = False
log.init(host=host)

def _file_copy_instance(self, src, dest=None, file_system="flash:"):
def _file_copy_instance(self, src, dest=None, file_system="/mnt/flash"):
# "flash:" is only valid locally, "/mnt/flash" is used externally
if file_system == "flash:":
file_system = "/mnt/flash"
if dest is None:
dest = os.path.basename(src)

Expand Down Expand Up @@ -175,7 +178,7 @@ def boot_options(self):
dict: Key is ``sys`` with value being the image on the device.
"""
image = self.show("show boot-config")["softwareImage"]
image = image.replace("flash:", "")
image = image.replace("flash:/", "")
log.debug("Host %s: the boot options are %s", self.host, {"sys": image})
return {"sys": image}

Expand Down Expand Up @@ -375,7 +378,7 @@ def file_copy(self, src, dest=None, file_system=None):
file_copy = self._file_copy_instance(src, dest, file_system=file_system)

try:
file_copy.enable_scp()
# file_copy.enable_scp()
file_copy.establish_scp_conn()
file_copy.transfer_file()
log.info("Host %s: File %s transferred successfully.", self.host, src)
Expand Down
5 changes: 5 additions & 0 deletions pyntc/devices/ios_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,11 @@ def set_boot_options(self, image_name, **vendor_specifics):
): # TODO: Update to CommandError when deprecating config_list
command = f"boot system switch all {file_system}{image_name}"
self.config(["no boot system", command])

# If boot system is not found in the running config, but it exists in show boot or show bootvar
elif self.boot_options["sys"]:
command = f"boot system {file_system}/{image_name}"
self.config(command)
else:
raise CommandError(
command=command,
Expand Down
1 change: 1 addition & 0 deletions pyntc/devices/iosxewlc_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module for using a Cisco IOSXE WLC device over SSH."""

import time

from pyntc import log
Expand Down
1 change: 1 addition & 0 deletions pyntc/devices/jnpr_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module for using a Juniper junOS device."""

import hashlib
import os
import re
Expand Down
1 change: 1 addition & 0 deletions pyntc/devices/nxos_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module for using an NXOS device over NX-API."""

import os
import re
import time
Expand Down
1 change: 1 addition & 0 deletions pyntc/devices/system_features/vlans/base_vlans.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Base Vlan checks."""

from pyntc.errors import NTCError

from ..base_feature import BaseFeature
Expand Down
1 change: 1 addition & 0 deletions pyntc/errors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""pyntc custom exceptions."""

import warnings


Expand Down
1 change: 1 addition & 0 deletions pyntc/log.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Logging utilities for Pyntc."""

import os
import logging

Expand Down
1 change: 1 addition & 0 deletions pyntc/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""PyNTC Utilities."""

from .templates import get_structured_data
from .converters import convert_dict_by_key, convert_list_by_key, recursive_key_lookup

Expand Down
1 change: 1 addition & 0 deletions pyntc/utils/templates/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module to use NTC_TEMPLATES."""

import os
import textfsm

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyntc"
version = "2.0.0"
version = "2.0.1"
description = "SDK to simplify common workflows for Network Devices."
authors = ["Network to Code, LLC <[email protected]>"]
readme = "README.md"
Expand Down
1 change: 1 addition & 0 deletions tasks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tasks for use with Invoke."""

import os
import sys
from distutils.util import strtobool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"command": "show boot-config",
"result": {
"memTestIterations": 0,
"softwareImage": "flash:EOS.swi",
"softwareImage": "EOS.swi",
"abootPassword": "(not set)"
},
"encoding": "json"
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_devices/test_asa_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@


class TestASADevice:
def setup(self, api):
def setup_method(self, api):
with mock.patch("pyntc.devices.asa_device.ConnectHandler") as api:
if not getattr(self, "device", None):
self.device = ASADevice("host", "user", "password")
Expand All @@ -60,7 +60,7 @@ def setup(self, api):
self.device.native = api
self.count_setup += 1

def teardown(self):
def teardown_method(self):
# Reset the mock so we don't have transient test effects
self.device.native.reset_mock()
self.count_teardown += 1
Expand Down
12 changes: 7 additions & 5 deletions tests/unit/test_devices/test_eos_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,10 @@ def test_file_copy(self, mock_open, mock_close, mock_ssh, mock_ft):
mock_ft_instance.check_file_exists.side_effect = [False, True]
self.device.file_copy("path/to/source_file")

mock_ft.assert_called_with(self.device.native_ssh, "path/to/source_file", "source_file", file_system="flash:")
mock_ft_instance.enable_scp.assert_any_call()
mock_ft.assert_called_with(
self.device.native_ssh, "path/to/source_file", "source_file", file_system="/mnt/flash"
)
# mock_ft_instance.enable_scp.assert_any_call()
mock_ft_instance.establish_scp_conn.assert_any_call()
mock_ft_instance.transfer_file.assert_any_call()

Expand All @@ -255,8 +257,8 @@ def test_file_copy_different_dest(self, mock_open, mock_close, mock_ssh, mock_ft
mock_ft_instance.check_file_exists.side_effect = [False, True]
self.device.file_copy("source_file", "dest_file")

mock_ft.assert_called_with(self.device.native_ssh, "source_file", "dest_file", file_system="flash:")
mock_ft_instance.enable_scp.assert_any_call()
mock_ft.assert_called_with(self.device.native_ssh, "source_file", "dest_file", file_system="/mnt/flash")
# mock_ft_instance.enable_scp.assert_any_call()
mock_ft_instance.establish_scp_conn.assert_any_call()
mock_ft_instance.transfer_file.assert_any_call()

Expand Down Expand Up @@ -289,7 +291,7 @@ def test_set_boot_options(self):
[{"result": {"output": "flash:"}}],
[{"result": {"output": "new_image.swi"}}],
[{"result": {}}],
[{"result": {"softwareImage": "flash:new_image.swi"}}],
[{"result": {"softwareImage": "flash:/new_image.swi"}}],
]
calls = [
mock.call(["dir"], encoding="text"),
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_devices/test_f5_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, fullPath, version, build):


class TestF5Device:
def setup(self):
def setup_method(self):
with mock.patch("pyntc.devices.f5_device.ManagementRoot") as big_ip:
self.device = F5Device("host", "user", "password")
self.device.api_handler = big_ip
Expand All @@ -40,7 +40,7 @@ def setup(self):

self.count_setup += 1

def teardown(self):
def teardown_method(self):
self.device.api_handler.reset_mock()
self.count_teardown += 1

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_devices/test_ios_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ def test_set_boot_options_pass_with_switch_all(mock_save, mock_boot_options, moc

@mock.patch.object(IOSDevice, "_get_file_system")
@mock.patch.object(IOSDevice, "config")
@mock.patch.object(IOSDevice, "boot_options", new_callable=mock.PropertyMock)
@mock.patch.object(IOSDevice, "boot_options", new_callable=lambda: {"sys": None})
@mock.patch.object(IOSDevice, "save")
def test_set_boot_options_raise_commanderror(mock_save, mock_boot_options, mock_config, mock_file_system, ios_show):
device = ios_show(["dir_flash:.txt", "boot flash:c3560-advipservicesk9-mz.122-44.SE.bin"])
Expand Down

0 comments on commit 510aa8c

Please sign in to comment.