Skip to content
Merged
Show file tree
Hide file tree
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
42 changes: 24 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,18 @@ jobs:
uses: "actions/checkout@v2"
- name: "Setup environment"
uses: "networktocode/gh-action-setup-poetry-environment@v2"
- name: "Cache Docker images"
uses: "actions/cache@v2"
id: "cached-docker-images"
with:
path: "/tmp/docker"
key: "${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('./Dockerfile') }}"
- name: "Load docker image"
run: "docker load < /tmp/docker/netutils-py${{ matrix.python-version }}.tar"
- name: "Show docker images"
run: "docker image ls"
# - name: "Cache Docker images"
# uses: "actions/cache@v2"
# id: "cached-docker-images"
# with:
# path: "/tmp/docker"
# key: "${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('./Dockerfile') }}"
# - name: "Load docker image"
# run: "docker load < /tmp/docker/netutils-py${{ matrix.python-version }}.tar"
# - name: "Show docker images"
# run: "docker image ls"
- name: "Build Container"
run: "poetry run invoke build"
- name: "Linting: Pylint"
run: "poetry run invoke pylint"
needs:
Expand All @@ -144,14 +146,18 @@ jobs:
uses: "actions/checkout@v2"
- name: "Setup environment"
uses: "networktocode/gh-action-setup-poetry-environment@v2"
- name: "Cache Docker images"
uses: "actions/cache@v2"
id: "cached-docker-images"
with:
path: "/tmp/docker"
key: "${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('./Dockerfile') }}"
- name: "Load docker image"
run: "docker load < /tmp/docker/netutils-py${{ matrix.python-version }}.tar"
# - name: "Cache Docker images"
# uses: "actions/cache@v2"
# id: "cached-docker-images"
# with:
# path: "/tmp/docker"
# key: "${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('./Dockerfile') }}"
# - name: "Load docker image"
# run: "docker load < /tmp/docker/netutils-py${{ matrix.python-version }}.tar"
- name: "Build Container"
run: "poetry run invoke build"
- name: "Linting: Pylint"
run: "poetry run invoke pylint"
- name: "Run Tests"
run: "poetry run invoke pytest"
needs:
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## v0.2.4 - 2021-11

### Added

- #33 Add interface range compress function
- #53 Add get peer address function
- #59 Add bandwidth converting function
- #65 Added Docker caching
- #68 Add Fortinet Fortios Parser support

### Changed

- #64 CI implementation on GitHub actions

### Fixed

- #52 Update pyproject.toml build-server
- #55 update version in toml and init files
- #63 Fix lack of zero padding on ip to binary conversion
- #70 Fix lack of zero padding on ip to hex conversion
- #68 Update Black pinning

## v0.2.3 - 2021-09

### Added
Expand Down
2 changes: 1 addition & 1 deletion docs/source/sphinxext/exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def run(self):
return [
nodes.error(
None,
nodes.paragraph(text="Unable to execute python code at %s:%d:" % (basename(source), self.lineno)),
nodes.paragraph(text=f"Unable to execute python code at {basename(source)}:{self.lineno}:"),
nodes.paragraph(text=str(sys.exc_info()[1])),
)
]
Expand Down
2 changes: 1 addition & 1 deletion netutils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Initialization file for library."""

__version__ = "0.2.3"
__version__ = "0.2.4"
8 changes: 4 additions & 4 deletions netutils/config/compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _is_feature_ordered_compliant(feature_intended_cfg, feature_actual_cfg):
def _open_file_config(cfg_path):
"""Open config file from local disk."""
try:
with open(cfg_path) as filehandler:
with open(cfg_path, encoding="utf-8") as filehandler:
device_cfg = filehandler.read()
except IOError:
return False
Expand Down Expand Up @@ -168,7 +168,7 @@ def compliance(features, backup, intended, network_os, cfg_type="file"):
backup_cfg = backup
intended_cfg = intended

compliance_results = dict()
compliance_results = {}

for feature in features:
backup_str = section_config(feature, backup_cfg, network_os)
Expand Down Expand Up @@ -207,7 +207,7 @@ def config_section_not_parsed(features, device_cfg, network_os):
{'remaining_cfg': '!\naccess-list 1 permit 10.10.10.10\naccess-list 1 permit 10.10.10.11', 'section_not_found': []}
"""
remaining_cfg = device_cfg
section_not_found = list()
section_not_found = []
for feature in features:
feature_cfg = section_config(feature, device_cfg, network_os)
if not feature_cfg:
Expand Down Expand Up @@ -357,7 +357,7 @@ def find_unordered_cfg_lines(intended_cfg, actual_cfg):
"""
intended_lines = intended_cfg.splitlines()
actual_lines = actual_cfg.splitlines()
unordered_lines = list()
unordered_lines = []
if len(intended_lines) == len(actual_lines):
# Process to find actual lines that are misordered
unordered_lines = [(e1, e2) for e1, e2 in zip(intended_lines, actual_lines) if e1 != e2]
Expand Down
2 changes: 1 addition & 1 deletion netutils/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _remove_parents(self, line, current_spaces):
previous_parent = self._current_parents[-deindent_level]
previous_indent = self.get_leading_space_count(previous_parent)
except IndexError:
raise IndexError("\nValidate the first line does not begin with a space" "\n{}\n".format(line))
raise IndexError(f"\nValidate the first line does not begin with a space\n{line}\n")
parents = self._current_parents[:-deindent_level] or (self._current_parents[0],)
return parents

Expand Down
4 changes: 2 additions & 2 deletions netutils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from netutils import __file__ as netutils_file

# Load the PROTOCOLS json file.
with open("/".join([dirname(netutils_file), "protocols.json"])) as f:
PROTOCOLS = json.loads(f.read())
with open("/".join([dirname(netutils_file), "protocols.json"]), encoding="utf-8") as fh:
PROTOCOLS = json.loads(fh.read())

# This variable provides mapping for known interface variants, to the associated long form.
BASE_INTERFACES = {
Expand Down
5 changes: 3 additions & 2 deletions netutils/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import itertools
import re
import typing as t
from abc import ABC, abstractmethod, abstractproperty
from abc import ABC, abstractmethod
from functools import total_ordering
from operator import itemgetter
from .constants import BASE_INTERFACES, REVERSE_MAPPING
Expand Down Expand Up @@ -253,7 +253,8 @@ def __lt__(self, other) -> bool: # noqa: D105
def __eq__(self, other) -> bool: # noqa: D105
return self.weight == other.weight and self.val == other.val

@abstractproperty
@property
@abstractmethod
def weight(self) -> int:
"""Weight property."""
...
Expand Down
9 changes: 5 additions & 4 deletions netutils/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ def ip_to_hex(ip):
Example:
>>> from netutils.ip import ip_to_hex
>>> ip_to_hex("10.100.100.100")
'a646464'
'0a646464'
>>>
"""
return str(hex(int(ipaddress.ip_address(ip))))[2:]
ip_obj = ipaddress.ip_address(ip)
return str(hex(int(ip_obj)))[2:].zfill(int(ip_obj.max_prefixlen / 4))


def ip_addition(ip, val):
Expand Down Expand Up @@ -243,7 +244,7 @@ def get_first_usable(ip_network):
>>>
"""
net = ipaddress.ip_network(ip_network)
if net.prefixlen == 31 or net.prefixlen == 127:
if net.prefixlen in [31, 127]:
return str(net[0])
return str(net[1])

Expand Down Expand Up @@ -302,7 +303,7 @@ def get_usable_range(ip_network):
>>>
"""
net = ipaddress.ip_network(ip_network)
if net.prefixlen == 31 or net.prefixlen == 127:
if net.prefixlen in [31, 127]:
lower_bound = str(net[0])
upper_bound = str(net[1])
else:
Expand Down
9 changes: 5 additions & 4 deletions netutils/password.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def encrypt_type5(unencrypted_password, salt=None, salt_len=4):
if not salt:
salt = "".join(secrets.choice(ALPHABET) for i in range(salt_len))
elif not set(salt) <= set(ALPHABET):
raise ValueError("type5_pw salt used inproper characters, must be one of %s" % (ALPHABET))
raise ValueError(f"type5_pw salt used inproper characters, must be one of {ALPHABET}")
return crypt.crypt(unencrypted_password, f"$1${salt}$")


Expand All @@ -207,9 +207,10 @@ def encrypt_type7(unencrypted_password, salt=None):
"""
if not salt:
salt = random.randrange(0, 15) # nosec
encrypted_password = "%02x" % salt
encrypted_password = "%02x" % salt # pylint: disable=consider-using-f-string
for i, _ in enumerate(unencrypted_password):
encrypted_password += "%02x" % (ord(unencrypted_password[i]) ^ XLAT[salt])
hex_password = "%02x" % (ord(unencrypted_password[i]) ^ XLAT[salt]) # pylint: disable=consider-using-f-string
encrypted_password += hex_password
salt += 1
if salt == 51:
salt = 0
Expand All @@ -233,5 +234,5 @@ def get_hash_salt(encrypted_password):
"""
split_password = encrypted_password.split("$")
if len(split_password) != 4:
raise ValueError("Could not parse salt out password correctly from {0}".format(encrypted_password))
raise ValueError(f"Could not parse salt out password correctly from {encrypted_password}")
return split_password[2]
4 changes: 2 additions & 2 deletions netutils/vlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ def vlanlist_to_config(vlan_list, first_line_len=48, other_line_len=44):
raise ValueError("Valid VLAN range is 1-4094")

# Group consecutive VLANs
vlan_groups = list()
vlan_groups = []
for _, vlan in groupby(enumerate(clean_vlan_list), lambda vlan: vlan[0] - vlan[1]):
vlan_groups.append(list(map(itemgetter(1), vlan)))

# Create VLAN portion of config
vlan_strings = list()
vlan_strings = []
for group in vlan_groups:
if len(group) == 1:
vlan_strings.append(f"{group[0]}")
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "netutils"
version = "0.2.3"
version = "0.2.4"
description = "Common helper functions useful in network automation."
authors = ["Network to Code, LLC <opensource@networktocode.com>"]
license = "Apache-2.0"
Expand Down Expand Up @@ -78,6 +78,7 @@ good-names="i,ip,j,k,ex,Run,_"
disable = """,
line-too-long,
bad-continuation,
consider-iterating-dictionary,
"""

[tool.pylint.miscellaneous]
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _method(_file):
Returns:
dict: The data structure from the JSON file.
"""
with open(_file) as file:
with open(_file, encoding="utf-8") as file:
data = json.load(file)
return data

Expand All @@ -39,7 +39,7 @@ def _method(_file):
Returns:
str: The data structure from the text file.
"""
with open(_file) as file:
with open(_file, encoding="utf-8") as file:
data = file.read()
return data

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
]


with open("README.md", "r") as file:
with open("README.md", "r", encoding="utf-8") as file:
README_LIST = file.readlines()
README_LIST.insert(0, "")

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
IP_TO_HEX = [
{
"sent": {"ip": "10.1.1.1"},
"received": "a010101",
"received": "0a010101",
},
{
"sent": {"ip": "2001:db8:3333:4444:5555:6666:7777:8888"},
Expand Down