From 7589305a582ecfddddbbe677b7f1b8ea374e7f21 Mon Sep 17 00:00:00 2001 From: Alexandru Coman Date: Mon, 13 Feb 2017 15:16:25 +0200 Subject: [PATCH] Add support for BGP routers --- hnv/client.py | 343 ++++++++++++++++++++++ hnv/tests/fake/fake_response.py | 8 + hnv/tests/fake/response/bgp_peers.json | 205 +++++++++++++ hnv/tests/fake/response/bgp_routers.json | 351 +++++++++++++++++++++++ hnv/tests/test_client.py | 15 + 5 files changed, 922 insertions(+) create mode 100644 hnv/tests/fake/response/bgp_peers.json create mode 100644 hnv/tests/fake/response/bgp_routers.json diff --git a/hnv/client.py b/hnv/client.py index 443f8b3..a6f479d 100644 --- a/hnv/client.py +++ b/hnv/client.py @@ -2545,3 +2545,346 @@ class LoadBalancers(_BaseHNVModel): properties["probes"] = probes return super(LoadBalancers, cls).from_raw_data(raw_data) + + +class _BGPPeersStatistics(model.Model): + + """Base model for BGP peers statistics submodels.""" + + last_sent = model.Field( + name="last_sent", key="lastsent", + is_property=False, is_required=False, is_read_only=True) + """Last sent timestamp.""" + + last_received = model.Field( + name="last_received", key="lastReceived", + is_property=False, is_required=False, is_read_only=True) + """Last received timestamp.""" + + sent_count = model.Field( + name="sent_count", key="sentCount", + is_property=False, is_required=False, is_read_only=True) + """Sent count.""" + + received_count = model.Field( + name="received_count", key="receivedCount", + is_property=False, is_required=False, is_read_only=True) + """Received count.""" + + +class OpenMessageStatistics(_BGPPeersStatistics): + + """Model for open message statistics.""" + + pass + + +class NotificationMessageStatistics(_BGPPeersStatistics): + + """Model for notification message statistics.""" + + pass + + +class KeepAliveMessageStatistics(_BGPPeersStatistics): + + """Model for keep alive message statistics.""" + + pass + + +class RouteRefreshMessageStatistics(_BGPPeersStatistics): + + """Model for route regresh message statistics.""" + + pass + + +class UpdateMessageStatistics(_BGPPeersStatistics): + + """Model for update message statistics.""" + + pass + + +class _StatisticsRoute(model.Model): + + """Base model for IPV4 and IPV6 route statistics.""" + + update_sent_count = model.Field( + name="update_sent_count", key="updateSentCount", + is_property=False, is_required=False, is_read_only=True) + """Route update sent count.""" + + update_received_count = model.Field( + name="update_received_count", key="updateReceivedCount", + is_property=False, is_required=False, is_read_only=True) + """Route update received count.""" + + withdrawl_sent_count = model.Field( + name="withdraw_sent_count", key="withdrawlSentCount", + is_property=False, is_required=False, is_read_only=True) + """Route withdrawal sent count.""" + + withdrawl_received_count = model.Field( + name="withdraw_received_count", key="withdrawlReceivedCount", + is_property=False, is_required=False, is_read_only=True) + """Route withdrawal received count.""" + + +class IPV4Route(_StatisticsRoute): + + """Stats for IPv4 routes.""" + + pass + + +class IPV6Route(_StatisticsRoute): + + """Stats for IPv6 routes.""" + + pass + + +class BGPPeersStatistics(model.Model): + + """Provides statistics for this peer.""" + + tcp_connection_established = model.Field( + name="tcp_connection_established", key="tcpConnectionEstablished", + is_property=False, is_required=False, is_read_only=True) + """Timestamp of TCP connection establishment for BGP.""" + + tcp_connection_closed = model.Field( + name="tcp_connection_closed", key="tcpConnectionClosed", + is_property=False, is_required=False, is_read_only=True) + """Timestamp of TCP connection closed for BGP.""" + + open_message_stats = model.Field( + name="open_message_stats", key="openMessageStats", + is_property=False, is_required=False, is_read_only=True) + """Instance of OpenMessageStatistics.""" + + notification_message_stats = model.Field( + name="notification_message_stats", key="notificationMessageStats", + is_property=False, is_required=False, is_read_only=True) + """Instance of NotificationMessageStatistics.""" + + keep_alive_message_stats = model.Field( + name="keep_alive_message_stats", key="keepAliveMessageStats", + is_property=False, is_required=False, is_read_only=True) + """Instance of KeepAliveMessageStatistics.""" + + route_refresh_message_stats = model.Field( + name="route_refresh_message_stats", key="routeRefreshMessageStats", + is_property=False, is_required=False, is_read_only=True) + """Instance of RouteRefreshMessageStatistics.""" + + update_message_stats = model.Field( + name="update_message_stats", key="updateMessageStats", + is_property=False, is_required=False, is_read_only=True) + """Instance of UpdateMessageStatistics.""" + + ipv4_route_stats = model.Field( + name="ipv4_route_stats", key="ipv4Route", + is_property=False, is_required=False, is_read_only=True) + """Stats for IPv4 routes.""" + + ipv6_route_stats = model.Field( + name="ipv6_route_stats", key="ipv6Route", + is_property=False, is_required=False, is_read_only=True) + """Stats for IPv6 routes.""" + + last_updated = model.Field( + name="last_updated", key="lastUpdated", + is_property=False, is_required=False, is_read_only=True) + """Time stamp when the stats were last updated.""" + + @classmethod + def from_raw_data(cls, raw_data): + """Create a new model using raw API response.""" + + # pylint: disable=redefined-variable-type + + raw_content = raw_data.get("updateMessageStats", None) + if raw_content is not None: + statistics = UpdateMessageStatistics.from_raw_data(raw_content) + raw_data["updateMessageStats"] = statistics + + raw_content = raw_data.get("routeRefreshMessageStats", None) + if raw_content is not None: + statistics = RouteRefreshMessageStatistics.from_raw_data( + raw_content) + raw_data["routeRefreshMessageStats"] = statistics + + raw_content = raw_data.get("keepAliveMessageStats", None) + if raw_content is not None: + statistics = KeepAliveMessageStatistics.from_raw_data(raw_content) + raw_data["keepAliveMessageStats"] = statistics + + raw_content = raw_data.get("notificationMessageStats", None) + if raw_content is not None: + statistics = NotificationMessageStatistics.from_raw_data( + raw_content) + raw_data["notificationMessageStats"] = statistics + + raw_content = raw_data.get("openMessageStats", None) + if raw_content is not None: + statistics = OpenMessageStatistics.from_raw_data(raw_content) + raw_data["openMessageStats"] = statistics + + raw_content = raw_data.get("ipv4Route", None) + if raw_content is not None: + statistics = IPV4Route.from_raw_data(raw_content) + raw_data["ipv4Route"] = statistics + + raw_content = raw_data.get("ipv6Route", None) + if raw_content is not None: + statistics = IPV6Route.from_raw_data(raw_content) + raw_data["ipv6Route"] = statistics + + return super(BGPPeersStatistics, cls).from_raw_data(raw_data) + + +class BGPPeers(_BaseHNVModel): + + """Model for BGP peers. + + This resource configures BGP peers of the virtualGateways resource. + The peer is identified by remoteRouterId and asNumber. A VRF context + can be specified on devices that support VRF. The routeMapIn and + routeMapOut properties can specify a policy map that controls the + route updates that are associated with the BGP peer. + """ + + _endpoint = ("/networking/v1/virtualGateways/{grandparent_id}" + "/bgpRouters/{parent_id}/bgpPeers/{resource_id}") + + parent_id = model.Field( + name="parent_id", key="parentResourceID", + is_property=False, is_required=False, is_read_only=True) + """The parent resource ID field contains the resource ID that is + associated with network objects that are ancestors of the necessary + resource. + """ + + grandparent_id = model.Field( + name="grandparent_id", key="grandParentResourceID", + is_property=False, is_required=False, is_read_only=True) + """The grand parent resource ID field contains the resource ID that + is associated with network objects that are ancestors of the parent + of the necessary resource.""" + + connection_state = model.Field( + name="connection_state", key="connectionState", + is_required=False, is_read_only=True) + """Status of BGP peering for this peer. Possible values are `Connected` and + `Disconnected`.""" + + asn_number = model.Field(name="asn_number", key="asNumber", + is_required=False, is_read_only=True) + """Indicates the ASN number of the BGP Peer.""" + + ext_asn_number = model.Field(name="ext_asn_number", key="extAsNumber", + is_required=False, is_read_only=False) + """Indicates Extended ASN number of the BGP Peer in XX.YY format.""" + + peer_ip_address = model.Field(name="peer_ip_address", key="peerIpAddress", + is_required=False, is_read_only=False) + """IP address of the peer.""" + + statistics = model.Field(name="statistics", key="statistics", + is_required=False, is_read_only=True) + """Provides statistics for this peer.""" + + policy_map_out = model.Field(name="policy_map_out", key="policyMapOut", + is_required=False, is_read_only=False) + """Reference to the policy map object that is used to filter + the routing updates sent to the peer.""" + + policy_map_in = model.Field(name="policy_map_in", key="policyMapIn", + is_required=False, is_read_only=False) + """Reference to the policy map object that is used to filter + routing updates received from the peer.""" + + is_generated = model.Field(name="is_generated", key="isGenerated", + is_required=False, is_read_only=True) + """This flag is set to `True` for iBGP peers.""" + + @classmethod + def from_raw_data(cls, raw_data): + """Create a new model using raw API response.""" + properties = raw_data.get("properties", {}) + + raw_content = properties.get("statistics", None) + if raw_content is not None: + statistics = BGPPeersStatistics.from_raw_data(raw_content) + properties["statistics"] = statistics + + super(BGPPeers, cls).from_raw_data(raw_data) + + +class BGPRouters(_BaseHNVModel): + + """Model for BGP routers. + + The BGP Router resource contains the configuration needed for the Border + Gateway Protocol (BGP) router in the virtual gateway to connect to BGP + routers outside the virtual network in order to exchange routing + information. + """ + + _endpoint = ("/networking/v1/virtualGateways/{parent_id}" + "/bgpRouters/{resource_id}") + + parent_id = model.Field(name="parent_id", + key="parentResourceID", + is_property=False, is_required=True, + is_read_only=True) + """The parent resource ID field contains the resource ID that is + associated with network objects that are ancestors of the necessary + resource. + """ + + require_igp_sync = model.Field( + name="require_igp_sync", key="requireIgpSync", + is_required=True, is_read_only=False) + + is_enabled = model.Field(name="is_enabled", key="isEnabled", + is_required=True, is_read_only=False) + + is_generated = model.Field(name="is_generated", key="isGenerated", + is_required=False, is_read_only=True) + """If this BGP router is automatically enabled, without making any REST + calls then isGenerated is set to `True`.""" + + ext_as_number = model.Field(name="ext_as_number", key="extAsNumber", + is_required=False, is_read_only=False) + """Extended (4-byte) ASN of the local BGP Router in XX.YY format.""" + + router_id = model.Field(name="router_id", key="routerId", + is_required=False, is_read_only=False) + """Indicates Router ID.""" + + router_ip = model.Field( + name="router_ip", key="routerIP", + is_required=False, is_read_only=False) + """Indicates IP addresses to which BGP peering can be established.""" + + bgp_peers = model.Field(name="bgp_peers", key="bgpPeers", + is_required=False, is_read_only=False) + """Collection of BGP peers associated with the BGP Routers resource.""" + + @classmethod + def from_raw_data(cls, raw_data): + """Create a new model using raw API response.""" + properties = raw_data.get("properties", {}) + + bgp_peers = [] + for raw_content in properties.get("bgpPeers", []): + raw_content["parentResourceID"] = raw_data["resourceId"] + raw_content["grandParentResourceID"] = raw_data["parentResourceID"] + bgp_peers.append(BGPPeers.from_raw_data(raw_content)) + properties["bgpPeers"] = bgp_peers + + return super(BGPRouters, cls).from_raw_data(raw_data) diff --git a/hnv/tests/fake/fake_response.py b/hnv/tests/fake/fake_response.py index 44431e8..c957f33 100644 --- a/hnv/tests/fake/fake_response.py +++ b/hnv/tests/fake/fake_response.py @@ -117,3 +117,11 @@ class FakeResponse(object): def load_balancers(self): """Fake GET(all) response for load balancers.""" return self._load_resource("load_balancers.json") + + def bgp_peers(self): + """Fake GET(all) response for BGP peers.""" + return self._load_resource("bgp_peers.json") + + def bgp_routers(self): + """Fake GET(all) response for BGP routers.""" + return self._load_resource("bgp_routers.json") diff --git a/hnv/tests/fake/response/bgp_peers.json b/hnv/tests/fake/response/bgp_peers.json new file mode 100644 index 0000000..e9867d0 --- /dev/null +++ b/hnv/tests/fake/response/bgp_peers.json @@ -0,0 +1,205 @@ +{ + "value": [ + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer1", + "resourceId": "Peer1", + "etag": "W/\"6b3cec3d-d04b-4e4b-828b-355cd29d7ece\"", + "instanceId": "6f6a0c77-3830-4884-9b22-833f58f13e02", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.1.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:11:33.395-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:11:39.7306466Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer2", + "resourceId": "Peer2", + "etag": "W/\"6b3cec3d-d04b-4e4b-828b-355cd29d7ece\"", + "instanceId": "6dfc12fb-484a-4771-98f9-6c1d4ffbaa1a", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.2.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:11:33.41-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:11:39.7306466Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer3", + "resourceId": "Peer3", + "etag": "W/\"6b3cec3d-d04b-4e4b-828b-355cd29d7ece\"", + "instanceId": "d6bc7e33-4ac9-4f74-a3f2-81c39eb2a85d", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.3.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:11:33.425-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:11:39.7306466Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer1", + "resourceId": "Peer1", + "etag": "W/\"6b3cec3d-d04b-4e4b-828b-355cd29d7ece\"", + "instanceId": "6f6a0c77-3830-4884-9b22-833f58f13e02", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.1.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:11:33.395-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:11:39.7306466Z" + }, + "isGenerated": false + } + } + ], + "nextLink": "" +} diff --git a/hnv/tests/fake/response/bgp_routers.json b/hnv/tests/fake/response/bgp_routers.json new file mode 100644 index 0000000..1defb42 --- /dev/null +++ b/hnv/tests/fake/response/bgp_routers.json @@ -0,0 +1,351 @@ +{ + "value": [ + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1", + "resourceId": "router1", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "dc972df1-cce2-44b7-a0e4-df6f882b101a", + "properties": { + "provisioningState": "Succeeded", + "isEnabled": true, + "requireIgpSync": true, + "extAsNumber": "0.3458", + "routerId": "10.2.2.2", + "routerIP": [ + "10.2.2.2" + ], + "isGenerated": false, + "bgpPeers": [ + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer1", + "resourceId": "Peer1", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "cb4a4eba-9716-4d22-bd51-50998181e3a8", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.1.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:01:03.186-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:01:33.2899007Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer2", + "resourceId": "Peer2", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "d85b9574-8d53-4b70-8b4b-4053eaeeba60", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.2.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:01:21.091-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:01:33.2899007Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer3", + "resourceId": "Peer3", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "3b7e4db3-c415-4b06-8d0a-b2138142a8ff", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.3.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T22:01:27.67-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T05:01:33.2899007Z" + }, + "isGenerated": false + } + } + ], + "configurationState": { + "status": "Success", + "lastUpdatedTime": "2016-06-15T21:34:32.1843967-07:00" + } + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1", + "resourceId": "router1", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "dc972df1-cce2-44b7-a0e4-df6f882b101a", + "properties": { + "provisioningState": "Succeeded", + "isEnabled": true, + "requireIgpSync": true, + "extAsNumber": "0.3458", + "routerId": "10.2.2.2", + "routerIP": [ + "10.2.2.2" + ], + "isGenerated": false, + "bgpPeers": [ + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer1", + "resourceId": "Peer1", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "cb4a4eba-9716-4d22-bd51-50998181e3a8", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.1.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T21:56:27.063-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T04:56:29.6397721Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer2", + "resourceId": "Peer2", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "d85b9574-8d53-4b70-8b4b-4053eaeeba60", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.2.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T21:56:12.053-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T04:56:29.6397721Z" + }, + "isGenerated": false + } + }, + { + "resourceRef": "/VirtualGateways/VirtualGateway_1/BgpRouters/router1/BgpPeers/Peer3", + "resourceId": "Peer3", + "etag": "W/\"5fb62acf-04c7-4071-9f06-c89ea8b0b1b0\"", + "instanceId": "3b7e4db3-c415-4b06-8d0a-b2138142a8ff", + "properties": { + "provisioningState": "Succeeded", + "asNumber": "1236", + "extAsNumber": "0.1236", + "peerIpAddress": "40.1.3.4", + "connectionState": "Disconnected", + "statistics": { + "tcpConnectionClosed": "2016-06-15T21:56:14.232-07:00", + "openMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "notificationMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "keepAliveMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "routeRefreshMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "updateMessageStats": { + "sentCount": 0, + "receivedCount": 0 + }, + "ipv4Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "ipv6Route": { + "updateSentCount": 0, + "updateReceivedCount": 0, + "withdrawlSentCount": 0, + "withdrawlReceivedCount": 0 + }, + "lastUpdated": "2016-06-16T04:56:29.6397721Z" + }, + "isGenerated": false + } + } + ], + "configurationState": { + "status": "Success", + "lastUpdatedTime": "2016-06-15T21:34:32.1843967-07:00" + } + } + } + ], + "nextLink": "" +} diff --git a/hnv/tests/test_client.py b/hnv/tests/test_client.py index 9dc819d..8cef072 100644 --- a/hnv/tests/test_client.py +++ b/hnv/tests/test_client.py @@ -368,3 +368,18 @@ class TestClient(unittest.TestCase): for raw_data in resources.get("value", []): self._test_get_resource(model=client.LoadBalancers, raw_data=raw_data) + + def test_bgp_peers(self): + resources = self._response.bgp_peers() + for raw_data in resources.get("value", []): + raw_data["parentResourceID"] = "fake-parent-id" + raw_data["grandParentResourceID"] = "fake-grandparent-id" + self._test_get_resource(model=client.BGPPeers, + raw_data=raw_data) + + def test_bgp_routers(self): + resources = self._response.bgp_routers() + for raw_data in resources.get("value", []): + raw_data["parentResourceID"] = "fake-parent-id" + self._test_get_resource(model=client.BGPRouters, + raw_data=raw_data)