Skip to content

Commit

Permalink
Implement poe management for juniper
Browse files Browse the repository at this point in the history
  • Loading branch information
stveit committed Sep 5, 2023
1 parent 9d89679 commit b7e22c1
Showing 1 changed file with 61 additions and 1 deletion.
62 changes: 61 additions & 1 deletion python/nav/portadmin/napalm/juniper.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"""
from __future__ import annotations
from operator import attrgetter
from typing import List, Any, Dict, Tuple, Sequence
from typing import List, Any, Dict, Tuple, Sequence, Optional

from django.template.loader import get_template
from napalm.base.exceptions import ConnectAuthError, ConnectionException
Expand All @@ -44,6 +44,10 @@
AuthenticationError,
NoResponseError,
ProtocolError,
PoeState,
POENotSupportedError,
POEStateNotSupportedError,
XMLParseError,
)
from nav.junos.nav_views import (
EthernetSwitchingInterfaceTable,
Expand Down Expand Up @@ -102,6 +106,8 @@ class Juniper(ManagementHandler):

VENDOR = VENDOR_ID_JUNIPER_NETWORKS_INC
PROTOCOL = manage.ManagementProfile.PROTOCOL_NAPALM
POE_ENABLED = PoeState(state=1, name="ENABLED")
POE_DISABLED = PoeState(state=2, name="DISABLED")

def __init__(self, netbox: manage.Netbox, **kwargs):
super().__init__(netbox, **kwargs)
Expand Down Expand Up @@ -441,6 +447,60 @@ def raise_if_not_configurable(self):
if not self.profile:
raise DeviceNotConfigurableError("Device has no NAPALM profile")

def get_poe_state_options(self) -> Sequence[PoeState]:
options_list = [self.POE_ENABLED, self.POE_DISABLED]
return tuple(options_list)

Check warning on line 452 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L451-L452

Added lines #L451 - L452 were not covered by tests

@wrap_unhandled_rpc_errors
def set_poe_state(self, interface: manage.Interface, state: PoeState):
if not isinstance(state, PoeState):
raise TypeError("state must be a PoeState object")
if state == self.POE_ENABLED:
template = get_template("portadmin/junos-enable-poe.djt")
elif state == self.POE_DISABLED:
template = get_template("portadmin/junos-disable-poe.djt")

Check warning on line 461 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L456-L461

Added lines #L456 - L461 were not covered by tests
else:
raise POEStateNotSupportedError(f"state {state} is not a valid state")
master, _ = split_master_unit(interface.ifname)
config = template.render({"ifname": master})
self.device.load_merge_candidate(config=config)

Check warning on line 466 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L463-L466

Added lines #L463 - L466 were not covered by tests

def get_poe_states(
self, interfaces: Sequence[manage.Interface] = None
) -> Dict[int, Optional[PoeState]]:
state_dict = {}
for interface in interfaces:
try:
state_dict[interface.ifindex] = self._get_poe_state(interface)
except POENotSupportedError:
state_dict[interface.ifindex] = None
return state_dict

Check warning on line 477 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L471-L477

Added lines #L471 - L477 were not covered by tests

@wrap_unhandled_rpc_errors
def _get_poe_state(self, interface: manage.Interface):
tree = self.device.device.rpc.get_poe_interface_information(

Check warning on line 481 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L481

Added line #L481 was not covered by tests
ifname=interface.ifname
)
matching_elements = tree.xpath(

Check warning on line 484 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L484

Added line #L484 was not covered by tests
"//poe/interface-information-detail/interface-enabled-detail"
)
# Interfaces that do not support PoE will not have this element
if not matching_elements:
raise POENotSupportedError(

Check warning on line 489 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L488-L489

Added lines #L488 - L489 were not covered by tests
f"Interface {interface.ifname} does not support PoE"
)
if len(matching_elements) != 1:
raise XMLParseError(

Check warning on line 493 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L492-L493

Added lines #L492 - L493 were not covered by tests
f"Expected 1 matching element in xml response, {len(matching_elements)} found"
)
poe_state = matching_elements[0].text.lower()
if poe_state == "enabled":
return self.POE_ENABLED
elif poe_state == "disabled":
return self.POE_DISABLED

Check warning on line 500 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L496-L500

Added lines #L496 - L500 were not covered by tests
else:
raise POEStateNotSupportedError(f"Unknown PoE state {poe_state}")

Check warning on line 502 in python/nav/portadmin/napalm/juniper.py

View check run for this annotation

Codecov / codecov/patch

python/nav/portadmin/napalm/juniper.py#L502

Added line #L502 was not covered by tests

# FIXME Implement dot1x fetcher methods
# dot1x authentication configuration fetchers aren't implemented yet, for lack
# of configured devices to test on
Expand Down

0 comments on commit b7e22c1

Please sign in to comment.