feat: licenses, a hypervisor's hosts and the package proxy as facts (4.14.0) #43
No files matched your search
@@ -90,6 +90,7 @@ from napalm_device_types.fixes import (
|
||||
run_fix_steps,
|
||||
)
|
||||
from napalm_device_types.health_metrics import HealthMetricsMixin
|
||||
from napalm_device_types.licenses import LicenseMixin
|
||||
from napalm_device_types.host_reboot import HostRebootMixin
|
||||
from napalm_device_types.interface_filter import InterfaceFilterMixin
|
||||
from napalm_device_types.kernel import KERNEL_FACTS_COMMAND, KernelFactsMixin, parse_kernel_facts
|
||||
@@ -114,6 +115,8 @@ from napalm_device_types.models import (
|
||||
ManagementProtocolsDict,
|
||||
PowerAction,
|
||||
PowerStateDict,
|
||||
HypervisorHostDict,
|
||||
LicenseDict,
|
||||
FixResultDict,
|
||||
FixStepDict,
|
||||
FixStepOutcomeDict,
|
||||
@@ -167,6 +170,9 @@ from napalm_device_types.storage import StorageDriver
|
||||
from napalm_device_types.switch import SwitchDriver
|
||||
|
||||
__all__ = [
|
||||
"HypervisorHostDict",
|
||||
"LicenseDict",
|
||||
"LicenseMixin",
|
||||
"EnsurePackageMixin",
|
||||
"FixResultDict",
|
||||
"FixStepDict",
|
||||
|
||||
@@ -140,6 +140,12 @@ class PackageProxyMixin:
|
||||
"""Have the package manager fetch through *url*; an empty *url* removes it."""
|
||||
...
|
||||
|
||||
def get_package_proxy(self) -> Optional[str]:
|
||||
"""The proxy the package manager fetches through now; None for none.
|
||||
|
||||
A fact: whether it is the right one is the caller's to judge."""
|
||||
...
|
||||
|
||||
|
||||
__all__ = [
|
||||
"EnsurePackageMixin",
|
||||
|
||||
@@ -16,6 +16,7 @@ from napalm_device_types.packages import PackageManagementMixin
|
||||
from napalm_device_types.health_metrics import HealthMetricsMixin
|
||||
from napalm_device_types.provisioning import QEMU_GUEST_AGENTS, GuestAgents
|
||||
from napalm_device_types.models import (
|
||||
HypervisorHostDict,
|
||||
NICConfigDict,
|
||||
NetworkTargetDict,
|
||||
SnapshotDict,
|
||||
@@ -637,6 +638,12 @@ class HypervisorDriver(PackageManagementMixin, HealthMetricsMixin, DeviceTypeDri
|
||||
"""
|
||||
...
|
||||
|
||||
def get_hypervisor_hosts(self) -> List[HypervisorHostDict]:
|
||||
"""The hosts this hypervisor or its manager runs, and how each stands:
|
||||
connected, in maintenance, with configuration issues, under a central
|
||||
manager. Facts; what is a problem is the caller's to decide."""
|
||||
...
|
||||
|
||||
def get_vm_cpu_types(self) -> List[VMCpuTypeDict]:
|
||||
"""
|
||||
List the virtual CPU models a new VM may be given on the node it will
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Licenses and subscriptions a device reports.
|
||||
|
||||
A fact for the caller (docs/STRUCTURE.md): whether a free edition, a missing
|
||||
subscription or a license a feature needs is a problem is decided above the
|
||||
driver. Declared only; a driver that can read licenses implements it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from napalm_device_types.models import LicenseDict
|
||||
|
||||
|
||||
class LicenseMixin:
|
||||
if TYPE_CHECKING: # pragma: no cover - declared for type checkers only
|
||||
|
||||
def get_licenses(self) -> List[LicenseDict]:
|
||||
"""Every license or subscription the device knows of, with its status.
|
||||
|
||||
Example::
|
||||
|
||||
[{"name": "pve-subscription", "status": "none"},
|
||||
{"name": "vSphere", "status": "active", "edition": "Free"}]
|
||||
"""
|
||||
...
|
||||
@@ -993,6 +993,33 @@ class HealthMetricsDict(TypedDict):
|
||||
interfaces: NotRequired[Dict[str, HealthMetricsIfaceDict]]
|
||||
|
||||
|
||||
LicenseStatus = Literal["active", "missing", "expired", "invalid", "none", "unknown"]
|
||||
|
||||
|
||||
class LicenseDict(TypedDict):
|
||||
"""A license or subscription the device reports (``LicenseMixin.get_licenses``).
|
||||
|
||||
A fact, not a judgement: whether a free edition or a missing subscription is
|
||||
a problem is the caller's to decide.
|
||||
"""
|
||||
|
||||
name: str # what it licenses, as the device names it
|
||||
status: LicenseStatus # "none": the device runs without one, as installed
|
||||
edition: NotRequired[str] # the edition or level, e.g. "Free", "Enterprise Plus"
|
||||
expires: NotRequired[Optional[str]] # ISO date, None for no expiry
|
||||
detail: NotRequired[str] # the device's own words, e.g. why a feature is refused
|
||||
|
||||
|
||||
class HypervisorHostDict(TypedDict):
|
||||
"""One host of a hypervisor or cluster (``HypervisorDriver.get_hypervisor_hosts``)."""
|
||||
|
||||
name: str
|
||||
connected: Optional[bool] # reachable by its manager; None where it cannot tell
|
||||
maintenance: Optional[bool] # in maintenance mode
|
||||
config_issues: List[str] # the manager's configuration warnings, verbatim
|
||||
managed_by: NotRequired[Optional[str]] # the address of a central manager, if any
|
||||
|
||||
|
||||
class FixStepOutcomeDict(TypedDict):
|
||||
"""What one step of a fix routine reports (see ``napalm_device_types.fixes``)."""
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "napalm-device-types"
|
||||
version = "4.13.0"
|
||||
version = "4.14.0"
|
||||
description = "Abstract device-type base classes for NAPALM drivers"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Facts instead of warnings (docs/STRUCTURE.md, NetOrk/netork#1111).
|
||||
|
||||
A driver reports what it reads; the application decides what is a warning. Three
|
||||
facts that drivers so far only reported as warning codes get contracts of their
|
||||
own: the package manager's proxy, licenses and subscriptions, and the state of a
|
||||
hypervisor's hosts. All are declared only, so a capability check stays truthful.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import get_type_hints
|
||||
|
||||
from napalm_device_types import (
|
||||
HypervisorDriver,
|
||||
HypervisorHostDict,
|
||||
LicenseDict,
|
||||
LicenseMixin,
|
||||
PackageProxyMixin,
|
||||
)
|
||||
|
||||
|
||||
def test_a_license_says_what_it_is_and_whether_it_holds():
|
||||
hints = get_type_hints(LicenseDict)
|
||||
assert {"name", "status"} <= set(hints)
|
||||
assert LicenseDict.__required_keys__ == frozenset({"name", "status"})
|
||||
assert set(hints) == {"name", "status", "edition", "expires", "detail"}
|
||||
|
||||
|
||||
def test_a_hypervisor_host_says_how_it_stands():
|
||||
hints = get_type_hints(HypervisorHostDict)
|
||||
assert set(hints) == {"name", "connected", "maintenance", "config_issues", "managed_by"}
|
||||
assert HypervisorHostDict.__required_keys__ == frozenset(
|
||||
{"name", "connected", "maintenance", "config_issues"}
|
||||
)
|
||||
|
||||
|
||||
def test_the_getters_are_declared_only():
|
||||
assert not hasattr(PackageProxyMixin, "get_package_proxy")
|
||||
assert not hasattr(LicenseMixin, "get_licenses")
|
||||
assert not hasattr(HypervisorDriver, "get_hypervisor_hosts")
|
||||
Reference in new issue
Block a user