Skip to content

Commit

Permalink
topotato: has_logmsg & has_defun for templates
Browse files Browse the repository at this point in the history
Already have these implemented for requirements checks, also allow using
them in templates to determine what to put in FRR configs.

Signed-off-by: David Lamparter <[email protected]>
  • Loading branch information
eqvinox committed Sep 6, 2024
1 parent 263cccc commit 8a73dd5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 3 deletions.
30 changes: 27 additions & 3 deletions topotato/frr/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def __init__(self, instance: TopotatoNetwork, name: str):
router=router,
routers=rtrmap,
topo=topo,
frr=TemplateUtils(router, daemon),
frr=TemplateUtils(router, daemon, self),
)

# TODO: rework mgmtd integration, particularly for supporting older
Expand Down Expand Up @@ -176,17 +176,41 @@ def require_defun(self, cmd: str, contains: Optional[str] = None) -> None:
f"DEFUN {cmd!r} does not contain {contains!r}"
)

def require_logmsg(self, msgid: str) -> None:
def has_defun(self, cmd: str, contains: Optional[str] = None) -> bool:
"""
Wrap :py:meth:`require_defun`, but return a bool rather than throwing
an exception.
This wrapper is "the other way around" because the exception thrown
above contains additional information beyond what can be conveyed in a
``bool``.
"""
try:
self.require_defun(cmd, contains)
return True
except FRRRequirementNotMet:
return False

def has_logmsg(self, msgid: str) -> bool:
"""
Check that a log message exists in this FRR version by looking up its
unique ID in ``frr.xref``.
:param msgid: ID (``XXXXX-XXXXX``) of the log message to look for.
"""
return msgid in (self.frr.xrefs or {}).get("refs", {})

def require_logmsg(self, msgid: str) -> None:
"""
Wrap :py:meth:`has_logmsg` and raise exception if given log message
does not exist in this FRR version.
:param msgid: ID (``XXXXX-XXXXX``) of the log message to look for.
:raises FRRRequirementNotMet: if the log message is not found. This
causes the test to be skipped, but can be caught (e.g. if there
are multiple alternatives to check.)
"""
if msgid not in (self.frr.xrefs or {}).get("refs", {}):
if not self.has_logmsg(msgid):
raise FRRRequirementNotMet(f"missing log message {msgid!r}")

def requirements(self) -> None:
Expand Down
23 changes: 23 additions & 0 deletions topotato/frr/templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Callable,
List,
Literal,
Optional,
Set,
Tuple,
Union,
Expand All @@ -21,6 +22,7 @@

if typing.TYPE_CHECKING:
from .. import toponom
from .params import FRRParams

jenv = jinlinja.InlineEnv()

Expand Down Expand Up @@ -52,6 +54,7 @@
class TemplateUtils:
router: "toponom.Router"
daemon: str
params: "FRRParams"

def static_route_for(
self,
Expand Down Expand Up @@ -95,3 +98,23 @@ def static_route_for(
queue.append((nbr, nbr_path))

raise RuntimeError(f"no route for {dst!r} on {self.router!r}")

def has_defun(self, cmd: str, contains: Optional[str] = None) -> bool:
"""
Expose :py:meth:`FRRParams.has_defun` for template use.
:param cmd: Name of the command as defined in the C source, i.e.
second argument to `DEFUN` macro. Generally ends in ``_cmd``.
:param contains: String that must appear in the command's syntax
definition (use if some new option is added to an existing
command.)
"""
return self.params.has_defun(cmd, contains)

def has_logmsg(self, msgid: str) -> bool:
"""
Expose :py:meth:`FRRParams.has_logmsg` for template use.
:param msgid: ID (``XXXXX-XXXXX``) of the log message to look for.
"""
return self.params.has_logmsg(msgid)

0 comments on commit 8a73dd5

Please sign in to comment.