mirror of
https://github.com/thatmattlove/hyperglass.git
synced 2026-04-17 21:38:27 +00:00
Merge branch 'thatmattlove:main' into main
This commit is contained in:
commit
cc558e62e8
5 changed files with 29 additions and 16 deletions
|
|
@ -7,10 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- [#280](https://github.com/thatmattlove/hyperglass/issues/280): Fix: `condition: None` caused error in directive
|
- [#280](https://github.com/thatmattlove/hyperglass/issues/280): Fix: `condition: None` caused error in directive @Jimmy01240397
|
||||||
- [#306](https://github.com/thatmattlove/hyperglass/issues/306): Fix: allow integer values in ext_community_list_raw field for Arista BGP - @cooperwinser
|
- [#306](https://github.com/thatmattlove/hyperglass/issues/306): Fix: allow integer values in ext_community_list_raw field for Arista BGP - @cooperwinser
|
||||||
|
- [#311](https://github.com/thatmattlove/hyperglass/issues/311): Fix: device and directive errors.
|
||||||
|
- [#315](https://github.com/thatmattlove/hyperglass/issues/315): Impossibile to use command "BGP Route" with Huawei NetEngine 8000
|
||||||
|
- [#315](https://github.com/thatmattlove/hyperglass/issues/187): Error in bgp_router query on Huawei
|
||||||
- [#325](https://github.com/thatmattlove/hyperglass/pull/325): Fix code block padding in the documentation - @jagardaniel
|
- [#325](https://github.com/thatmattlove/hyperglass/pull/325): Fix code block padding in the documentation - @jagardaniel
|
||||||
- [#327](https://github.com/thatmattlove/hyperglass/pull/327): Fix huawei bgp route and plugin validation/transform order - @JelsonRodrigues
|
- [#332](https://github.com/thatmattlove/hyperglass/pull/332): Fix custom proxy port support in SSH proxy tunnels @jessiebryan
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ your-directive:
|
||||||
- condition: null
|
- condition: null
|
||||||
command: show ip route {target}
|
command: show ip route {target}
|
||||||
field:
|
field:
|
||||||
|
description: IP of target
|
||||||
validation: '[0-9a-f\.\:]+'
|
validation: '[0-9a-f\.\:]+'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -178,6 +179,7 @@ your-directive:
|
||||||
- condition: null
|
- condition: null
|
||||||
command: show ip bgp community {target}
|
command: show ip bgp community {target}
|
||||||
field:
|
field:
|
||||||
|
description: BGP community to show
|
||||||
options:
|
options:
|
||||||
- value: "65001:1"
|
- value: "65001:1"
|
||||||
description: Provider A Routes
|
description: Provider A Routes
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,9 @@ class SSHConnection(Connection):
|
||||||
proxy.credential.password.get_secret_value()
|
proxy.credential.password.get_secret_value()
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
return open_tunnel(proxy._target, proxy.port, **tunnel_kwargs)
|
return open_tunnel(
|
||||||
|
ssh_address_or_host=proxy._target, ssh_port=proxy.port, **tunnel_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
except BaseSSHTunnelForwarderError as scrape_proxy_error:
|
except BaseSSHTunnelForwarderError as scrape_proxy_error:
|
||||||
log.bind(device=self.device.name, proxy=proxy.name).error(
|
log.bind(device=self.device.name, proxy=proxy.name).error(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ import secrets
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# Third Party
|
# Third Party
|
||||||
from pydantic import Field, BaseModel, ConfigDict, field_validator
|
from pydantic import BaseModel, ConfigDict, field_validator, StringConstraints
|
||||||
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
# Project
|
# Project
|
||||||
from hyperglass.log import log
|
from hyperglass.log import log
|
||||||
|
|
@ -21,6 +22,11 @@ from hyperglass.exceptions.private import InputValidationError
|
||||||
from ..config.devices import Device
|
from ..config.devices import Device
|
||||||
|
|
||||||
|
|
||||||
|
QueryLocation = Annotated[str, StringConstraints(strict=True, min_length=1, strip_whitespace=True)]
|
||||||
|
QueryTarget = Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)]
|
||||||
|
QueryType = Annotated[str, StringConstraints(strict=True, min_length=1, strip_whitespace=True)]
|
||||||
|
|
||||||
|
|
||||||
class SimpleQuery(BaseModel):
|
class SimpleQuery(BaseModel):
|
||||||
"""A simple representation of a post-validated query."""
|
"""A simple representation of a post-validated query."""
|
||||||
|
|
||||||
|
|
@ -39,12 +45,12 @@ class Query(BaseModel):
|
||||||
model_config = ConfigDict(extra="allow", alias_generator=snake_to_camel, populate_by_name=True)
|
model_config = ConfigDict(extra="allow", alias_generator=snake_to_camel, populate_by_name=True)
|
||||||
|
|
||||||
# Device `name` field
|
# Device `name` field
|
||||||
query_location: str = Field(strict=True, min_length=1, strip_whitespace=True)
|
query_location: QueryLocation
|
||||||
|
|
||||||
query_target: t.Union[t.List[str], str] = Field(min_length=1, strip_whitespace=True)
|
query_target: t.Union[t.List[QueryTarget], QueryTarget]
|
||||||
|
|
||||||
# Directive `id` field
|
# Directive `id` field
|
||||||
query_type: str = Field(strict=True, min_length=1, strip_whitespace=True)
|
query_type: QueryType
|
||||||
_kwargs: t.Dict[str, t.Any]
|
_kwargs: t.Dict[str, t.Any]
|
||||||
|
|
||||||
def __init__(self, **data) -> None:
|
def __init__(self, **data) -> None:
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
|
|
||||||
@field_validator("address")
|
@field_validator("address")
|
||||||
def validate_address(
|
def validate_address(
|
||||||
cls, value: t.Union[IPv4Address, IPv6Address, str], values: t.Dict[str, t.Any]
|
cls, value: t.Union[IPv4Address, IPv6Address, str], info: ValidationInfo
|
||||||
) -> t.Union[IPv4Address, IPv6Address, str]:
|
) -> t.Union[IPv4Address, IPv6Address, str]:
|
||||||
"""Ensure a hostname is resolvable."""
|
"""Ensure a hostname is resolvable."""
|
||||||
|
|
||||||
|
|
@ -178,14 +178,14 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
if not any(resolve_hostname(value)):
|
if not any(resolve_hostname(value)):
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
"Device '{d}' has an address of '{a}', which is not resolvable.",
|
"Device '{d}' has an address of '{a}', which is not resolvable.",
|
||||||
d=values["name"],
|
d=info.data["name"],
|
||||||
a=value,
|
a=value,
|
||||||
)
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@field_validator("avatar")
|
@field_validator("avatar")
|
||||||
def validate_avatar(
|
def validate_avatar(
|
||||||
cls, value: t.Union[FilePath, None], values: t.Dict[str, t.Any]
|
cls, value: t.Union[FilePath, None], info: ValidationInfo
|
||||||
) -> t.Union[FilePath, None]:
|
) -> t.Union[FilePath, None]:
|
||||||
"""Migrate avatar to static directory."""
|
"""Migrate avatar to static directory."""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
|
|
@ -198,7 +198,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
target = Settings.static_path / "images" / value.name
|
target = Settings.static_path / "images" / value.name
|
||||||
copied = shutil.copy2(value, target)
|
copied = shutil.copy2(value, target)
|
||||||
log.bind(
|
log.bind(
|
||||||
device=values["name"],
|
device=info.data["name"],
|
||||||
source=str(value),
|
source=str(value),
|
||||||
destination=str(target),
|
destination=str(target),
|
||||||
).debug("Copied device avatar")
|
).debug("Copied device avatar")
|
||||||
|
|
@ -210,24 +210,24 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@field_validator("platform", mode="before")
|
@field_validator("platform", mode="before")
|
||||||
def validate_platform(cls: "Device", value: t.Any, values: t.Dict[str, t.Any]) -> str:
|
def validate_platform(cls: "Device", value: t.Any, info: ValidationInfo) -> str:
|
||||||
"""Validate & rewrite device platform, set default `directives`."""
|
"""Validate & rewrite device platform, set default `directives`."""
|
||||||
|
|
||||||
if value == "http":
|
if value == "http":
|
||||||
if values.get("http") is None:
|
if info.data.get("http") is None:
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
"Device '{device}' has platform 'http' configured, but no http parameters are defined.",
|
"Device '{device}' has platform 'http' configured, but no http parameters are defined.",
|
||||||
device=values["name"],
|
device=info.data["name"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
if values.get("http") is not None:
|
if info.data.get("http") is not None:
|
||||||
value = "http"
|
value = "http"
|
||||||
else:
|
else:
|
||||||
# Ensure device platform is defined.
|
# Ensure device platform is defined.
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
"Device '{device}' is missing a 'platform' (Network Operating System) property",
|
"Device '{device}' is missing a 'platform' (Network Operating System) property",
|
||||||
device=values["name"],
|
device=info.data["name"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if value in SCRAPE_HELPERS.keys():
|
if value in SCRAPE_HELPERS.keys():
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue