From 81aac2968183ae3e3abb57e946da9a083f4801d1 Mon Sep 17 00:00:00 2001 From: kszmitko Date: Tue, 17 Oct 2023 17:31:30 +0200 Subject: [PATCH 1/2] Netconf custom verifier --- verifiers/src/yang/verifiers/__init__.py | 2 - .../src/yang/verifiers/count_verifier.py | 50 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/verifiers/src/yang/verifiers/__init__.py b/verifiers/src/yang/verifiers/__init__.py index cd78d16..617a476 100644 --- a/verifiers/src/yang/verifiers/__init__.py +++ b/verifiers/src/yang/verifiers/__init__.py @@ -11,10 +11,8 @@ __contact__ = 'yang-python@cisco.com' __copyright__ = 'Cisco Systems, Inc.' -from .count_verifier import CountVerifier from .base_verifier import BaseVerifier __all__ = ( 'BaseVerifier', - 'CountVerifier', ) diff --git a/verifiers/src/yang/verifiers/count_verifier.py b/verifiers/src/yang/verifiers/count_verifier.py index 5fa404b..4ee6707 100644 --- a/verifiers/src/yang/verifiers/count_verifier.py +++ b/verifiers/src/yang/verifiers/count_verifier.py @@ -1,10 +1,10 @@ -from typing import List +from typing import Any, List from dataclasses import field, dataclass from google.protobuf import json_format # Import base classes. For non pyats installation you can use class provided within this module try: - from genie.libs.sdk.triggers.blitz.verifiers import GnmiDefaultVerifier + from genie.libs.sdk.triggers.blitz.verifiers import GnmiDefaultVerifier, NetconfDefaultVerifier except ImportError: from yang.verifiers.base_verifier import BaseVerifier as GnmiDefaultVerifier @@ -61,6 +61,50 @@ def end_subscription(self, errors): if errors: return False for ret in self.returns: - if ret.count != ret.found_items or ret.found_items < self.kwargs['min_count']: + if (ret.count != ret.found_items or + ret.found_items < self.format['verifier']['min_count']): + return False + return True + + +class NetconfCountVerifier(NetconfDefaultVerifier): + from genie.libs.sdk.triggers.blitz.rpcverify import OptFields + + @dataclass + class MyCustomReturns(OptFields): + ''' + Create a custom returns class to be used by the verifier + by adding new fields to the default returns dataclass + ''' + cli_return: dict = field(default_factory=dict) + count: int = 0 + found_items: int = 0 + + @property + def returns(self) -> List[MyCustomReturns]: + return self._returns + + @returns.setter + def returns(self, value: List[dict]) -> List[MyCustomReturns]: + ''' + Register our custom returns class + ''' + self._returns = [self.MyCustomReturns(**r) for r in value] + + def get_config_verify(self, raw_response: Any) -> bool: + # Here we have raw netconf xml response + # We are decoding it using default netconf decoder + # but you can use your own decode method + try: + decoded_response = self.decode(raw_response) + except self.DecodeError: + return False + for response in decoded_response: + for ret in self.returns: + if response[1] == ret.xpath: + ret.found_items += 1 + for ret in self.returns: + if (ret.count != ret.found_items or + ret.found_items < self.format['verifier']['min_count']): return False return True From 0a42ac92d572cc563bef69a10e3e8d86f8627aee Mon Sep 17 00:00:00 2001 From: kszmitko Date: Wed, 25 Oct 2023 13:53:34 +0200 Subject: [PATCH 2/2] Change names --- verifiers/src/yang/verifiers/__init__.py | 3 +++ verifiers/src/yang/verifiers/count_verifier.py | 18 +++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/verifiers/src/yang/verifiers/__init__.py b/verifiers/src/yang/verifiers/__init__.py index 617a476..fa459b3 100644 --- a/verifiers/src/yang/verifiers/__init__.py +++ b/verifiers/src/yang/verifiers/__init__.py @@ -12,7 +12,10 @@ __copyright__ = 'Cisco Systems, Inc.' from .base_verifier import BaseVerifier +from .count_verifier import NetconfCountVerifier, GnmiCountVerifier __all__ = ( 'BaseVerifier', + 'NetconfCountVerifier', + 'GnmiCountVerifier' ) diff --git a/verifiers/src/yang/verifiers/count_verifier.py b/verifiers/src/yang/verifiers/count_verifier.py index 4ee6707..badb9a7 100644 --- a/verifiers/src/yang/verifiers/count_verifier.py +++ b/verifiers/src/yang/verifiers/count_verifier.py @@ -9,11 +9,11 @@ from yang.verifiers.base_verifier import BaseVerifier as GnmiDefaultVerifier -class CountVerifier(GnmiDefaultVerifier): +class GnmiCountVerifier(GnmiDefaultVerifier): from genie.libs.sdk.triggers.blitz.rpcverify import OptFields @dataclass - class MyCustomReturns(OptFields): + class CustomReturns(OptFields): ''' Create a custom returns class to be used by the verifier by adding new fields to the default returns dataclass @@ -23,15 +23,15 @@ class MyCustomReturns(OptFields): found_items: int = 0 @property - def returns(self) -> List[MyCustomReturns]: + def returns(self) -> List[CustomReturns]: return self._returns @returns.setter - def returns(self, value: List[dict]) -> List[MyCustomReturns]: + def returns(self, value: List[dict]) -> List[CustomReturns]: ''' Register our custom returns class ''' - self._returns = [self.MyCustomReturns(**r) for r in value] + self._returns = [self.CustomReturns(**r) for r in value] def decode(self, response, namespace: dict = None, method: str = 'get') -> List[dict]: from genie.libs.sdk.triggers.blitz.gnmi_util import GnmiMessage @@ -71,7 +71,7 @@ class NetconfCountVerifier(NetconfDefaultVerifier): from genie.libs.sdk.triggers.blitz.rpcverify import OptFields @dataclass - class MyCustomReturns(OptFields): + class CustomReturns(OptFields): ''' Create a custom returns class to be used by the verifier by adding new fields to the default returns dataclass @@ -81,15 +81,15 @@ class MyCustomReturns(OptFields): found_items: int = 0 @property - def returns(self) -> List[MyCustomReturns]: + def returns(self) -> List[CustomReturns]: return self._returns @returns.setter - def returns(self, value: List[dict]) -> List[MyCustomReturns]: + def returns(self, value: List[dict]) -> List[CustomReturns]: ''' Register our custom returns class ''' - self._returns = [self.MyCustomReturns(**r) for r in value] + self._returns = [self.CustomReturns(**r) for r in value] def get_config_verify(self, raw_response: Any) -> bool: # Here we have raw netconf xml response