diff --git a/docs/panos-upgrade-assurance/api/firewall_proxy.md b/docs/panos-upgrade-assurance/api/firewall_proxy.md
index f2f716f..64e8153 100644
--- a/docs/panos-upgrade-assurance/api/firewall_proxy.md
+++ b/docs/panos-upgrade-assurance/api/firewall_proxy.md
@@ -547,6 +547,94 @@ __Returns__
`dict`: Routes information.
+### `FirewallProxy.get_bgp_peers`
+
+```python
+def get_bgp_peers() -> dict
+```
+
+Get information about BGP peers and their status.
+
+The actual API command is ``.
+
+In the returned `dict` the key is made of three route properties delimited with an underscore (`_`) in the following
+order:
+
+* virtual router name,
+* peer group name,
+* peer name.
+
+The key does not provide any meaningful information, it's there only to introduce uniqueness for each entry. All
+properties that make a key are also available in the value of a dictionary element.
+
+```python showLineNumbers title="Sample output"
+{
+ 'default_Peer-Group1_Peer1': {
+ '@peer': 'Peer1',
+ '@vr': 'default',
+ 'peer-group': 'Peer-Group1',
+ 'peer-router-id': '169.254.8.2',
+ 'remote-as': '64512',
+ 'status': 'Established',
+ 'status-duration': '3804',
+ 'password-set': 'no',
+ 'passive': 'no',
+ 'multi-hop-ttl': '2',
+ 'peer-address': '169.254.8.2:35355',
+ 'local-address': '169.254.8.1:179',
+ 'reflector-client': 'not-client',
+ 'same-confederation': 'no',
+ 'aggregate-confed-as': 'yes',
+ 'peering-type': 'Unspecified',
+ 'connect-retry-interval': '15',
+ 'open-delay': '0',
+ 'idle-hold': '15',
+ 'prefix-limit': '5000',
+ 'holdtime': '30',
+ 'holdtime-config': '30',
+ 'keepalive': '10',
+ 'keepalive-config': '10',
+ 'msg-update-in': '2',
+ 'msg-update-out': '1',
+ 'msg-total-in': '385',
+ 'msg-total-out': '442',
+ 'last-update-age': '3',
+ 'last-error': 'None',
+ 'status-flap-counts': '2',
+ 'established-counts': '1',
+ 'ORF-entry-received': '0',
+ 'nexthop-self': 'no',
+ 'nexthop-thirdparty': 'yes',
+ 'nexthop-peer': 'no',
+ 'config': {'remove-private-as': 'no'},
+ 'peer-capability': {
+ 'list': [
+ {'capability': 'Multiprotocol Extensions(1)', 'value': 'IPv4 Unicast'},
+ {'capability': 'Route Refresh(2)', 'value': 'yes'},
+ {'capability': '4-Byte AS Number(65)', 'value': '64512'},
+ {'capability': 'Route Refresh (Cisco)(128)', 'value': 'yes'}
+ ]
+ },
+ 'prefix-counter': {
+ 'entry': {
+ '@afi-safi': 'bgpAfiIpv4-unicast',
+ 'incoming-total': '2',
+ 'incoming-accepted': '2',
+ 'incoming-rejected': '0',
+ 'policy-rejected': '0',
+ 'outgoing-total': '0',
+ 'outgoing-advertised': '0'
+ }
+ }
+ }
+}
+```
+
+__Returns__
+
+
+`dict`: BGP peers information.
+
### `FirewallProxy.get_arp_table`
```python
diff --git a/docs/panos-upgrade-assurance/configuration_details.mdx b/docs/panos-upgrade-assurance/configuration_details.mdx
index 5cfe117..ee3f9f6 100644
--- a/docs/panos-upgrade-assurance/configuration_details.mdx
+++ b/docs/panos-upgrade-assurance/configuration_details.mdx
@@ -961,6 +961,7 @@ Following state areas are available:
snapshots_config = [
'nics',
'routes',
+ 'bgp_peers',
'license',
'arp_table',
'content_version',
@@ -979,6 +980,7 @@ snapshots_config = [
snapshots_config:
- nics
- routes
+ - bgp_peers
- license
- arp_table
- content_version
@@ -1030,6 +1032,12 @@ Takes a snapshot of the Route Table (this includes routes populated from DHCP as
**Method:** [`FirewallProxy.get_routes()`](/panos/docs/panos-upgrade-assurance/api/firewall_proxy#firewallproxyget_routes)
+### `bgp_peers`
+
+Takes a snapshot of configuration of BGP peers along with their status.
+
+**Method:** [`FirewallProxy.get_bgp_peers()`](/panos/docs/panos-upgrade-assurance/api/firewall_proxy#firewallproxyget_bgp_peers)
+
### `fib_routes`
Takes a snapshot of the Forwarding table (routes that are actually taken into forwarding decisions based on routing table).
@@ -1076,6 +1084,9 @@ reports = [
'properties': ['!flags'],
'count_change_threshold': 10
}},
+ {'bgp_peers': {
+ 'properties': ['status']
+ }},
'content_version',
{'session_stats': {
'thresholds': [
@@ -1113,6 +1124,9 @@ reports:
properties:
- "!flags"
count_change_threshold: 10
+ - bgp_peers:
+ properties:
+ - "status"
- content_version
- session_stats:
thresholds:
@@ -1409,6 +1423,58 @@ reports:
```
+### `bgp_peers`
+
+Compares configuration and the status of BGP peers.
+
+**Method:** [`SnapshotCompare.get_diff_and_threshold()`](/panos/docs/panos-upgrade-assurance/api/snapshot_compare#snapshotcompareget_diff_and_threshold)
+
+**Configuration parameters**
+
+parameter | description
+--- | ---
+`properties` | (optional) a set of properties to skip when comparing two BGP peers, all properties are checked when this parameter is skipped
+`count_change_threshold` | (optional) maximum difference percentage of changed entries in BGP peers in both snapshots, skipped when this property is not specified
+
+**Sample configuration**
+
+The following configuration compares the status of BGP peers as
+captured in snapshots.
+
+This report produces the standardized dictionary.
+
+```mdx-code-block
+
+
+```
+
+```python showLineNumbers
+reports = [
+ {
+ 'bgp_peers': {
+ 'properties': ['status']
+ }
+ }
+]
+```
+
+```mdx-code-block
+
+
+```
+
+```yaml showLineNumbers
+reports:
+ - bgp_peers:
+ properties:
+ - 'status'
+```
+
+```mdx-code-block
+
+
+```
+
### `fib_routes`
Provides a report on differences between FIB Table entries. It includes:
diff --git a/examples/low_level_methods/run_low_level_methods.py b/examples/low_level_methods/run_low_level_methods.py
index 84e95fc..198399c 100755
--- a/examples/low_level_methods/run_low_level_methods.py
+++ b/examples/low_level_methods/run_low_level_methods.py
@@ -94,6 +94,8 @@
print(f"\n routes information\n{firewall.get_routes()}")
+ print(f"\n BGP peers information\n{firewall.get_bgp_peers()}")
+
print(f"\n arp entries information\n{firewall.get_arp_table()}")
print(f"\n session information\n{firewall.get_session_stats()}")
diff --git a/examples/readiness_checks/run_readiness_snapshot.py b/examples/readiness_checks/run_readiness_snapshot.py
index ae52d51..ebc289b 100755
--- a/examples/readiness_checks/run_readiness_snapshot.py
+++ b/examples/readiness_checks/run_readiness_snapshot.py
@@ -83,6 +83,7 @@
"nics",
"routes",
"fib_routes",
+ "bgp_peers",
"license",
"arp_table",
"content_version",
diff --git a/examples/report/fw1.snapshot b/examples/report/fw1.snapshot
index 63f8496..3d11174 100644
--- a/examples/report/fw1.snapshot
+++ b/examples/report/fw1.snapshot
@@ -67,6 +67,66 @@
"route-table": "unicast"
}
},
+ "bgp_peers": {
+ "default_Peer-Group1_Peer1": {
+ "@peer": "Peer1",
+ "@vr": "default",
+ "peer-group": "Peer-Group1",
+ "peer-router-id": "169.254.8.2",
+ "remote-as": "64512",
+ "status": "Established",
+ "status-duration": "3804",
+ "password-set": "no",
+ "passive": "no",
+ "multi-hop-ttl": "2",
+ "peer-address": "169.254.8.2:35355",
+ "local-address": "169.254.8.1:179",
+ "reflector-client": "not-client",
+ "same-confederation": "no",
+ "aggregate-confed-as": "yes",
+ "peering-type": "Unspecified",
+ "connect-retry-interval": "15",
+ "open-delay": "0",
+ "idle-hold": "15",
+ "prefix-limit": "5000",
+ "holdtime": "30",
+ "holdtime-config": "30",
+ "keepalive": "10",
+ "keepalive-config": "10",
+ "msg-update-in": "2",
+ "msg-update-out": "1",
+ "msg-total-in": "385",
+ "msg-total-out": "442",
+ "last-update-age": "3",
+ "last-error": null,
+ "status-flap-counts": "2",
+ "established-counts": "1",
+ "ORF-entry-received": "0",
+ "nexthop-self": "no",
+ "nexthop-thirdparty": "yes",
+ "nexthop-peer": "no",
+ "config": {"remove-private-as": "no"},
+ "peer-capability": {
+ "list": [
+ {"capability": "Multiprotocol Extensions(1)", "value": "IPv4 Unicast"},
+ {"capability": "Route Refresh(2)", "value": "yes"},
+ {"capability": "4-Byte AS Number(65)", "value": "64512"},
+ {"capability": "Route Refresh (Cisco)(128)", "value": "yes"}
+ ]
+ },
+ "prefix-counter": {
+ "entry": {
+ "@afi-safi": "bgpAfiIpv4-unicast",
+ "incoming-total": "2",
+ "incoming-accepted": "2",
+ "incoming-rejected": "0",
+ "policy-rejected": "0",
+ "outgoing-total": "0",
+ "outgoing-advertised": "0"
+ }
+ }
+ }
+ },
"session_stats": {
"tmo-5gcdelete": "15",
"tmo-sctpshutdown": "60",
diff --git a/examples/report/fw2.snapshot b/examples/report/fw2.snapshot
index fb6c43c..68e8b2c 100644
--- a/examples/report/fw2.snapshot
+++ b/examples/report/fw2.snapshot
@@ -54,6 +54,49 @@
"route-table": "unicast"
}
},
+ "bgp_peers": {
+ "default_Peer-Group1_Peer1": {
+ "@peer": "Peer1",
+ "@vr": "default",
+ "peer-group": "Peer-Group1",
+ "peer-router-id": "169.254.8.2",
+ "remote-as": "64512",
+ "status": "Idle",
+ "status-duration": "0",
+ "password-set": "no",
+ "passive": "no",
+ "multi-hop-ttl": "2",
+ "peer-address": "169.254.8.2",
+ "local-address": "169.254.8.1",
+ "reflector-client": "not-client",
+ "same-confederation": "no",
+ "aggregate-confed-as": "yes",
+ "peering-type": "Unspecified",
+ "connect-retry-interval": "15",
+ "open-delay": "0",
+ "idle-hold": "15",
+ "prefix-limit": "5000",
+ "holdtime": "0",
+ "holdtime-config": "30",
+ "keepalive": "0",
+ "keepalive-config": "10",
+ "msg-update-in": "0",
+ "msg-update-out": "0",
+ "msg-total-in": "0",
+ "msg-total-out": "0",
+ "last-update-age": "0",
+ "last-error": null,
+ "status-flap-counts": "0",
+ "established-counts": "0",
+ "ORF-entry-received": "0",
+ "nexthop-self": "no",
+ "nexthop-thirdparty": "yes",
+ "nexthop-peer": "no",
+ "config": {"remove-private-as": "no"},
+ "peer-capability": null,
+ "prefix-counter": null
+ }
+ },
"session_stats": {
"tmo-5gcdelete": "15",
"tmo-sctpshutdown": "60",
diff --git a/examples/report/snapshot_load_compare.py b/examples/report/snapshot_load_compare.py
index 7f760de..5e0feb6 100755
--- a/examples/report/snapshot_load_compare.py
+++ b/examples/report/snapshot_load_compare.py
@@ -21,6 +21,8 @@ def load_snap(fname: str) -> dict:
{"nics": {"count_change_threshold": 10}},
{"license": {"properties": ["!serial"]}},
{"routes": {"properties": ["!flags"], "count_change_threshold": 10}},
+ {"bgp_peers": {"properties": ["status"]}},
+ "!fib_routes",
"!content_version",
{
"session_stats": {
diff --git a/panos_upgrade_assurance/check_firewall.py b/panos_upgrade_assurance/check_firewall.py
index 31061cd..43edc1c 100644
--- a/panos_upgrade_assurance/check_firewall.py
+++ b/panos_upgrade_assurance/check_firewall.py
@@ -79,6 +79,7 @@ def __init__(self, node: FirewallProxy, skip_force_locale: Optional[bool] = Fals
self._snapshot_method_mapping = {
SnapType.NICS: self._node.get_nics,
SnapType.ROUTES: self._node.get_routes,
+ SnapType.BGP_PEERS: self._node.get_bgp_peers,
SnapType.LICENSE: self._node.get_licenses,
SnapType.ARP_TABLE: self._node.get_arp_table,
SnapType.CONTENT_VERSION: self.get_content_db_version,
diff --git a/panos_upgrade_assurance/firewall_proxy.py b/panos_upgrade_assurance/firewall_proxy.py
index ef1d363..28f9cae 100644
--- a/panos_upgrade_assurance/firewall_proxy.py
+++ b/panos_upgrade_assurance/firewall_proxy.py
@@ -617,6 +617,102 @@ def get_routes(self) -> dict:
return result
+ def get_bgp_peers(self) -> dict:
+ """Get information about BGP peers and their status.
+
+ The actual API command is ``.
+
+ In the returned `dict` the key is made of three route properties delimited with an underscore (`_`) in the following
+ order:
+
+ * virtual router name,
+ * peer group name,
+ * peer name.
+
+ The key does not provide any meaningful information, it's there only to introduce uniqueness for each entry. All
+ properties that make a key are also available in the value of a dictionary element.
+
+ ```python showLineNumbers title="Sample output"
+ {
+ 'default_Peer-Group1_Peer1': {
+ '@peer': 'Peer1',
+ '@vr': 'default',
+ 'peer-group': 'Peer-Group1',
+ 'peer-router-id': '169.254.8.2',
+ 'remote-as': '64512',
+ 'status': 'Established',
+ 'status-duration': '3804',
+ 'password-set': 'no',
+ 'passive': 'no',
+ 'multi-hop-ttl': '2',
+ 'peer-address': '169.254.8.2:35355',
+ 'local-address': '169.254.8.1:179',
+ 'reflector-client': 'not-client',
+ 'same-confederation': 'no',
+ 'aggregate-confed-as': 'yes',
+ 'peering-type': 'Unspecified',
+ 'connect-retry-interval': '15',
+ 'open-delay': '0',
+ 'idle-hold': '15',
+ 'prefix-limit': '5000',
+ 'holdtime': '30',
+ 'holdtime-config': '30',
+ 'keepalive': '10',
+ 'keepalive-config': '10',
+ 'msg-update-in': '2',
+ 'msg-update-out': '1',
+ 'msg-total-in': '385',
+ 'msg-total-out': '442',
+ 'last-update-age': '3',
+ 'last-error': 'None',
+ 'status-flap-counts': '2',
+ 'established-counts': '1',
+ 'ORF-entry-received': '0',
+ 'nexthop-self': 'no',
+ 'nexthop-thirdparty': 'yes',
+ 'nexthop-peer': 'no',
+ 'config': {'remove-private-as': 'no'},
+ 'peer-capability': {
+ 'list': [
+ {'capability': 'Multiprotocol Extensions(1)', 'value': 'IPv4 Unicast'},
+ {'capability': 'Route Refresh(2)', 'value': 'yes'},
+ {'capability': '4-Byte AS Number(65)', 'value': '64512'},
+ {'capability': 'Route Refresh (Cisco)(128)', 'value': 'yes'}
+ ]
+ },
+ 'prefix-counter': {
+ 'entry': {
+ '@afi-safi': 'bgpAfiIpv4-unicast',
+ 'incoming-total': '2',
+ 'incoming-accepted': '2',
+ 'incoming-rejected': '0',
+ 'policy-rejected': '0',
+ 'outgoing-total': '0',
+ 'outgoing-advertised': '0'
+ }
+ }
+ }
+ }
+ ```
+
+ # Returns
+
+ dict: BGP peers information.
+
+ """
+
+ response = self.op_parser(cmd="show routing protocol bgp peer")
+
+ result = {}
+ if "entry" in response:
+ bgp_peers = response["entry"]
+ for peer in bgp_peers if isinstance(bgp_peers, list) else [bgp_peers]:
+ result[
+ f"{peer['@vr'].replace(' ', '-')}_{peer['peer-group'].replace(' ', '-')}_{peer['@peer'].replace(' ', '-')}"
+ ] = dict(peer)
+
+ return result
+
def get_arp_table(self) -> dict:
"""Get the currently available ARP table entries.
diff --git a/panos_upgrade_assurance/snapshot_compare.py b/panos_upgrade_assurance/snapshot_compare.py
index 6be7d2d..3936317 100644
--- a/panos_upgrade_assurance/snapshot_compare.py
+++ b/panos_upgrade_assurance/snapshot_compare.py
@@ -60,6 +60,7 @@ def __init__(
self._functions_mapping = {
SnapType.NICS: self.get_diff_and_threshold,
SnapType.ROUTES: self.get_diff_and_threshold,
+ SnapType.BGP_PEERS: self.get_diff_and_threshold,
SnapType.LICENSE: self.get_diff_and_threshold,
SnapType.ARP_TABLE: self.get_diff_and_threshold,
SnapType.CONTENT_VERSION: self.get_diff_and_threshold,
diff --git a/panos_upgrade_assurance/utils.py b/panos_upgrade_assurance/utils.py
index 71fce4d..89e56d2 100644
--- a/panos_upgrade_assurance/utils.py
+++ b/panos_upgrade_assurance/utils.py
@@ -44,6 +44,7 @@ class SnapType:
NICS = "nics"
ROUTES = "routes"
+ BGP_PEERS = "bgp_peers"
LICENSE = "license"
ARP_TABLE = "arp_table"
CONTENT_VERSION = "content_version"
diff --git a/tests/snapshots.py b/tests/snapshots.py
index 2de50aa..4a711c0 100644
--- a/tests/snapshots.py
+++ b/tests/snapshots.py
@@ -67,6 +67,66 @@
"route-table": "unicast",
},
},
+ "bgp_peers": {
+ "default_Peer-Group1_Peer1": {
+ "@peer": "Peer1",
+ "@vr": "default",
+ "peer-group": "Peer-Group1",
+ "peer-router-id": "169.254.8.2",
+ "remote-as": "64512",
+ "status": "Established",
+ "status-duration": "3804",
+ "password-set": "no",
+ "passive": "no",
+ "multi-hop-ttl": "2",
+ "peer-address": "169.254.8.2:35355",
+ "local-address": "169.254.8.1:179",
+ "reflector-client": "not-client",
+ "same-confederation": "no",
+ "aggregate-confed-as": "yes",
+ "peering-type": "Unspecified",
+ "connect-retry-interval": "15",
+ "open-delay": "0",
+ "idle-hold": "15",
+ "prefix-limit": "5000",
+ "holdtime": "30",
+ "holdtime-config": "30",
+ "keepalive": "10",
+ "keepalive-config": "10",
+ "msg-update-in": "2",
+ "msg-update-out": "1",
+ "msg-total-in": "385",
+ "msg-total-out": "442",
+ "last-update-age": "3",
+ "last-error": None,
+ "status-flap-counts": "2",
+ "established-counts": "1",
+ "ORF-entry-received": "0",
+ "nexthop-self": "no",
+ "nexthop-thirdparty": "yes",
+ "nexthop-peer": "no",
+ "config": {"remove-private-as": "no"},
+ "peer-capability": {
+ "list": [
+ {"capability": "Multiprotocol Extensions(1)", "value": "IPv4 Unicast"},
+ {"capability": "Route Refresh(2)", "value": "yes"},
+ {"capability": "4-Byte AS Number(65)", "value": "64512"},
+ {"capability": "Route Refresh (Cisco)(128)", "value": "yes"},
+ ]
+ },
+ "prefix-counter": {
+ "entry": {
+ "@afi-safi": "bgpAfiIpv4-unicast",
+ "incoming-total": "2",
+ "incoming-accepted": "2",
+ "incoming-rejected": "0",
+ "policy-rejected": "0",
+ "outgoing-total": "0",
+ "outgoing-advertised": "0",
+ }
+ },
+ }
+ },
"session_stats": {
"tmo-5gcdelete": "15",
"tmo-sctpshutdown": "60",
@@ -277,6 +337,49 @@
"route-table": "unicast",
},
},
+ "bgp_peers": {
+ "default_Peer-Group1_Peer1": {
+ "@peer": "Peer1",
+ "@vr": "default",
+ "peer-group": "Peer-Group1",
+ "peer-router-id": "169.254.8.2",
+ "remote-as": "64512",
+ "status": "Idle",
+ "status-duration": "0",
+ "password-set": "no",
+ "passive": "no",
+ "multi-hop-ttl": "2",
+ "peer-address": "169.254.8.2",
+ "local-address": "169.254.8.1",
+ "reflector-client": "not-client",
+ "same-confederation": "no",
+ "aggregate-confed-as": "yes",
+ "peering-type": "Unspecified",
+ "connect-retry-interval": "15",
+ "open-delay": "0",
+ "idle-hold": "15",
+ "prefix-limit": "5000",
+ "holdtime": "0",
+ "holdtime-config": "30",
+ "keepalive": "0",
+ "keepalive-config": "10",
+ "msg-update-in": "0",
+ "msg-update-out": "0",
+ "msg-total-in": "0",
+ "msg-total-out": "0",
+ "last-update-age": "0",
+ "last-error": None,
+ "status-flap-counts": "0",
+ "established-counts": "0",
+ "ORF-entry-received": "0",
+ "nexthop-self": "no",
+ "nexthop-thirdparty": "yes",
+ "nexthop-peer": "no",
+ "config": {"remove-private-as": "no"},
+ "peer-capability": None,
+ "prefix-counter": None,
+ }
+ },
"session_stats": {
"tmo-5gcdelete": "15",
"tmo-sctpshutdown": "60",
diff --git a/tests/test_firewall_proxy.py b/tests/test_firewall_proxy.py
index 5038fb4..409d7eb 100644
--- a/tests/test_firewall_proxy.py
+++ b/tests/test_firewall_proxy.py
@@ -562,6 +562,144 @@ def test_get_routes_nexthop_name(self, fw_proxy_mock):
},
}
+ def test_get_bgp_peers(self, fw_proxy_mock):
+ xml_text = """
+
+
+
+ Peer-Group1
+ 169.254.8.2
+ 64512
+ Established
+ 3804
+ no
+ no
+ 2
+ 169.254.8.2:35355
+ 169.254.8.1:179
+ not-client
+ no
+ yes
+ Unspecified
+ 15
+ 0
+ 15
+ 5000
+ 30
+ 30
+ 10
+ 10
+ 2
+ 1
+ 385
+ 442
+ 3
+
+ 2
+ 1
+ 0
+ no
+ yes
+ no
+
+ no
+
+
+
+ Multiprotocol Extensions(1)
+ IPv4 Unicast
+
+
+ Route Refresh(2)
+ yes
+
+
+ 4-Byte AS Number(65)
+ 64512
+
+
+ Route Refresh (Cisco)(128)
+ yes
+
+
+
+
+ 2
+ 2
+ 0
+ 0
+ 0
+ 0
+
+
+
+
+
+ """
+ raw_response = ET.fromstring(xml_text)
+ fw_proxy_mock.op.return_value = raw_response
+
+ assert fw_proxy_mock.get_bgp_peers() == {
+ "default_Peer-Group1_Peer1": {
+ "@peer": "Peer1",
+ "@vr": "default",
+ "peer-group": "Peer-Group1",
+ "peer-router-id": "169.254.8.2",
+ "remote-as": "64512",
+ "status": "Established",
+ "status-duration": "3804",
+ "password-set": "no",
+ "passive": "no",
+ "multi-hop-ttl": "2",
+ "peer-address": "169.254.8.2:35355",
+ "local-address": "169.254.8.1:179",
+ "reflector-client": "not-client",
+ "same-confederation": "no",
+ "aggregate-confed-as": "yes",
+ "peering-type": "Unspecified",
+ "connect-retry-interval": "15",
+ "open-delay": "0",
+ "idle-hold": "15",
+ "prefix-limit": "5000",
+ "holdtime": "30",
+ "holdtime-config": "30",
+ "keepalive": "10",
+ "keepalive-config": "10",
+ "msg-update-in": "2",
+ "msg-update-out": "1",
+ "msg-total-in": "385",
+ "msg-total-out": "442",
+ "last-update-age": "3",
+ "last-error": None,
+ "status-flap-counts": "2",
+ "established-counts": "1",
+ "ORF-entry-received": "0",
+ "nexthop-self": "no",
+ "nexthop-thirdparty": "yes",
+ "nexthop-peer": "no",
+ "config": {"remove-private-as": "no"},
+ "peer-capability": {
+ "list": [
+ {"capability": "Multiprotocol Extensions(1)", "value": "IPv4 Unicast"},
+ {"capability": "Route Refresh(2)", "value": "yes"},
+ {"capability": "4-Byte AS Number(65)", "value": "64512"},
+ {"capability": "Route Refresh (Cisco)(128)", "value": "yes"},
+ ]
+ },
+ "prefix-counter": {
+ "entry": {
+ "@afi-safi": "bgpAfiIpv4-unicast",
+ "incoming-total": "2",
+ "incoming-accepted": "2",
+ "incoming-rejected": "0",
+ "policy-rejected": "0",
+ "outgoing-total": "0",
+ "outgoing-advertised": "0",
+ }
+ },
+ }
+ }
+
def test_get_arp_table(self, fw_proxy_mock):
xml_text = """
diff --git a/tests/test_snapshot_compare.py b/tests/test_snapshot_compare.py
index c7d38b3..d2337ed 100644
--- a/tests/test_snapshot_compare.py
+++ b/tests/test_snapshot_compare.py
@@ -414,6 +414,30 @@ def test_get_count_change_percentage(self, thresholds, expected_result):
}
},
),
+ (
+ [{"bgp_peers": {"properties": ["status"]}}],
+ {
+ "bgp_peers": {
+ "added": {"added_keys": [], "passed": True},
+ "changed": {
+ "changed_raw": {
+ "default_Peer-Group1_Peer1": {
+ "added": {"added_keys": [], "passed": True},
+ "changed": {
+ "changed_raw": {"status": {"left_snap": "Established", "right_snap": "Idle"}},
+ "passed": False,
+ },
+ "missing": {"missing_keys": [], "passed": True},
+ "passed": False,
+ }
+ },
+ "passed": False,
+ },
+ "missing": {"missing_keys": [], "passed": True},
+ "passed": False,
+ }
+ },
+ ),
(
["arp_table"],
{