From f31930a57633066de3ea96902f6cdc58fd1682b0 Mon Sep 17 00:00:00 2001 From: Michael Johnson Date: Tue, 29 Jan 2019 17:39:58 -0800 Subject: [PATCH] Added Octavia load balancer and listener stats This patch adds Octavia (load_balancer) load balancer and listener get statistics methods. Change-Id: I69ddcece685e928cb1244483998f9be76a7ce9cf --- doc/source/user/proxies/load_balancer_v2.rst | 2 + openstack/load_balancer/v2/_proxy.py | 26 +++++++++++++ openstack/load_balancer/v2/listener.py | 26 +++++++++++++ openstack/load_balancer/v2/load_balancer.py | 26 +++++++++++++ .../load_balancer/v2/test_load_balancer.py | 18 +++++++++ .../tests/unit/load_balancer/test_listener.py | 35 +++++++++++++++++ .../unit/load_balancer/test_load_balancer.py | 39 ++++++++++++++++++- .../tests/unit/load_balancer/test_proxy.py | 18 +++++++++ ...ia-lb-listener-stats-1538cc6e4f734353.yaml | 4 ++ 9 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/add-octavia-lb-listener-stats-1538cc6e4f734353.yaml diff --git a/doc/source/user/proxies/load_balancer_v2.rst b/doc/source/user/proxies/load_balancer_v2.rst index 0ad940691..520274948 100644 --- a/doc/source/user/proxies/load_balancer_v2.rst +++ b/doc/source/user/proxies/load_balancer_v2.rst @@ -19,6 +19,7 @@ Load Balancer Operations .. automethod:: openstack.load_balancer.v2._proxy.Proxy.delete_load_balancer .. automethod:: openstack.load_balancer.v2._proxy.Proxy.find_load_balancer .. automethod:: openstack.load_balancer.v2._proxy.Proxy.get_load_balancer + .. automethod:: openstack.load_balancer.v2._proxy.Proxy.get_load_balancer_statistics .. automethod:: openstack.load_balancer.v2._proxy.Proxy.load_balancers .. automethod:: openstack.load_balancer.v2._proxy.Proxy.update_load_balancer @@ -31,6 +32,7 @@ Listener Operations .. automethod:: openstack.load_balancer.v2._proxy.Proxy.delete_listener .. automethod:: openstack.load_balancer.v2._proxy.Proxy.find_listener .. automethod:: openstack.load_balancer.v2._proxy.Proxy.get_listener + .. automethod:: openstack.load_balancer.v2._proxy.Proxy.get_listener_statistics .. automethod:: openstack.load_balancer.v2._proxy.Proxy.listeners .. automethod:: openstack.load_balancer.v2._proxy.Proxy.update_listener diff --git a/openstack/load_balancer/v2/_proxy.py b/openstack/load_balancer/v2/_proxy.py index e8ea2c892..bc0fb9034 100644 --- a/openstack/load_balancer/v2/_proxy.py +++ b/openstack/load_balancer/v2/_proxy.py @@ -50,6 +50,17 @@ class Proxy(proxy.Proxy): """ return self._get(_lb.LoadBalancer, *attrs) + def get_load_balancer_statistics(self, name_or_id): + """Get the load balancer statistics + + :param name_or_id: The name or ID of a load balancer + + :returns: One :class:`~openstack.load_balancer.v2.load_balancer. + LoadBalancerStats` + """ + return self._get(_lb.LoadBalancerStats, lb_id=name_or_id, + requires_id=False) + def load_balancers(self, **query): """Retrieve a generator of load balancers @@ -172,6 +183,21 @@ class Proxy(proxy.Proxy): """ return self._get(_listener.Listener, listener) + def get_listener_statistics(self, listener): + """Get the listener statistics + + :param listener: The value can be the ID of a listener or a + :class:`~openstack.load_balancer.v2.listener.Listener` + instance. + + :returns: One :class:`~openstack.load_balancer.v2.listener. + ListenerStats` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_listener.ListenerStats, listener_id=listener, + requires_id=False) + def listeners(self, **query): """Return a generator of listeners diff --git a/openstack/load_balancer/v2/listener.py b/openstack/load_balancer/v2/listener.py index e55bcde48..894a93523 100644 --- a/openstack/load_balancer/v2/listener.py +++ b/openstack/load_balancer/v2/listener.py @@ -89,3 +89,29 @@ class Listener(resource.Resource, resource.TagMixin): #: Time, in milliseconds, to wait for additional TCP packets for content #: inspection. timeout_tcp_inspect = resource.Body('timeout_tcp_inspect', type=int) + + +class ListenerStats(resource.Resource): + resource_key = 'stats' + base_path = '/lbaas/listeners/%(listener_id)s/stats' + + # capabilities + allow_create = False + allow_fetch = True + allow_commit = False + allow_delete = False + allow_list = False + + # Properties + #: The ID of the listener. + listener_id = resource.URI('listener_id') + #: The currently active connections. + active_connections = resource.Body('active_connections', type=int) + #: The total bytes received. + bytes_in = resource.Body('bytes_in', type=int) + #: The total bytes sent. + bytes_out = resource.Body('bytes_out', type=int) + #: The total requests that were unable to be fulfilled. + request_errors = resource.Body('request_errors', type=int) + #: The total connections handled. + total_connections = resource.Body('total_connections', type=int) diff --git a/openstack/load_balancer/v2/load_balancer.py b/openstack/load_balancer/v2/load_balancer.py index 3c8379338..9d7cc407c 100644 --- a/openstack/load_balancer/v2/load_balancer.py +++ b/openstack/load_balancer/v2/load_balancer.py @@ -87,3 +87,29 @@ class LoadBalancer(resource.Resource, resource.TagMixin): self._translate_response(response, has_body=False, error_message=error_message) return self + + +class LoadBalancerStats(resource.Resource): + resource_key = 'stats' + base_path = '/lbaas/loadbalancers/%(lb_id)s/stats' + + # capabilities + allow_create = False + allow_fetch = True + allow_commit = False + allow_delete = False + allow_list = False + + # Properties + #: The ID of the load balancer. + lb_id = resource.URI('lb_id') + #: The currently active connections. + active_connections = resource.Body('active_connections', type=int) + #: The total bytes received. + bytes_in = resource.Body('bytes_in', type=int) + #: The total bytes sent. + bytes_out = resource.Body('bytes_out', type=int) + #: The total requests that were unable to be fulfilled. + request_errors = resource.Body('request_errors', type=int) + #: The total connections handled. + total_connections = resource.Body('total_connections', type=int) diff --git a/openstack/tests/functional/load_balancer/v2/test_load_balancer.py b/openstack/tests/functional/load_balancer/v2/test_load_balancer.py index f8f30aac7..9a12c564b 100644 --- a/openstack/tests/functional/load_balancer/v2/test_load_balancer.py +++ b/openstack/tests/functional/load_balancer/v2/test_load_balancer.py @@ -200,6 +200,15 @@ class TestLoadBalancer(base.BaseFunctionalTest): self.assertEqual(self.LB_ID, test_lb.id) self.assertEqual(self.VIP_SUBNET_ID, test_lb.vip_subnet_id) + def test_lb_get_stats(self): + test_lb_stats = self.conn.load_balancer.get_load_balancer_statistics( + self.LB_ID) + self.assertEqual(0, test_lb_stats.active_connections) + self.assertEqual(0, test_lb_stats.bytes_in) + self.assertEqual(0, test_lb_stats.bytes_out) + self.assertEqual(0, test_lb_stats.request_errors) + self.assertEqual(0, test_lb_stats.total_connections) + def test_lb_list(self): names = [lb.name for lb in self.conn.load_balancer.load_balancers()] self.assertIn(self.LB_NAME, names) @@ -231,6 +240,15 @@ class TestLoadBalancer(base.BaseFunctionalTest): self.assertEqual(self.PROTOCOL, test_listener.protocol) self.assertEqual(self.PROTOCOL_PORT, test_listener.protocol_port) + def test_listener_get_stats(self): + test_listener_stats = self.conn.load_balancer.get_listener_statistics( + self.LISTENER_ID) + self.assertEqual(0, test_listener_stats.active_connections) + self.assertEqual(0, test_listener_stats.bytes_in) + self.assertEqual(0, test_listener_stats.bytes_out) + self.assertEqual(0, test_listener_stats.request_errors) + self.assertEqual(0, test_listener_stats.total_connections) + def test_listener_list(self): names = [ls.name for ls in self.conn.load_balancer.listeners()] self.assertIn(self.LISTENER_NAME, names) diff --git a/openstack/tests/unit/load_balancer/test_listener.py b/openstack/tests/unit/load_balancer/test_listener.py index 5ea719d87..a0b254116 100644 --- a/openstack/tests/unit/load_balancer/test_listener.py +++ b/openstack/tests/unit/load_balancer/test_listener.py @@ -42,6 +42,14 @@ EXAMPLE = { 'timeout_tcp_inspect': 0, } +EXAMPLE_STATS = { + 'active_connections': 1, + 'bytes_in': 2, + 'bytes_out': 3, + 'request_errors': 4, + 'total_connections': 5 +} + class TestListener(base.TestCase): @@ -124,3 +132,30 @@ class TestListener(base.TestCase): 'timeout_tcp_inspect': 'timeout_tcp_inspect', }, test_listener._query_mapping._mapping) + + +class TestListenerStats(base.TestCase): + + def test_basic(self): + test_listener = listener.ListenerStats() + self.assertEqual('stats', test_listener.resource_key) + self.assertEqual('/lbaas/listeners/%(listener_id)s/stats', + test_listener.base_path) + self.assertFalse(test_listener.allow_create) + self.assertTrue(test_listener.allow_fetch) + self.assertFalse(test_listener.allow_delete) + self.assertFalse(test_listener.allow_list) + self.assertFalse(test_listener.allow_commit) + + def test_make_it(self): + test_listener = listener.ListenerStats(**EXAMPLE_STATS) + self.assertEqual(EXAMPLE_STATS['active_connections'], + test_listener.active_connections) + self.assertEqual(EXAMPLE_STATS['bytes_in'], + test_listener.bytes_in) + self.assertEqual(EXAMPLE_STATS['bytes_out'], + test_listener.bytes_out) + self.assertEqual(EXAMPLE_STATS['request_errors'], + test_listener.request_errors) + self.assertEqual(EXAMPLE_STATS['total_connections'], + test_listener.total_connections) diff --git a/openstack/tests/unit/load_balancer/test_load_balancer.py b/openstack/tests/unit/load_balancer/test_load_balancer.py index 427ad8184..adab6706d 100644 --- a/openstack/tests/unit/load_balancer/test_load_balancer.py +++ b/openstack/tests/unit/load_balancer/test_load_balancer.py @@ -38,6 +38,14 @@ EXAMPLE = { 'vip_qos_policy_id': uuid.uuid4(), } +EXAMPLE_STATS = { + 'active_connections': 1, + 'bytes_in': 2, + 'bytes_out': 3, + 'request_errors': 4, + 'total_connections': 5 +} + class TestLoadBalancer(base.TestCase): @@ -56,7 +64,7 @@ class TestLoadBalancer(base.TestCase): def test_make_it(self): test_load_balancer = load_balancer.LoadBalancer(**EXAMPLE) self.assertTrue(test_load_balancer.is_admin_state_up) - self.assertEqual(EXAMPLE['created_at'], test_load_balancer.created_at), + self.assertEqual(EXAMPLE['created_at'], test_load_balancer.created_at) self.assertEqual(EXAMPLE['description'], test_load_balancer.description) self.assertEqual(EXAMPLE['flavor_id'], test_load_balancer.flavor_id) @@ -70,7 +78,7 @@ class TestLoadBalancer(base.TestCase): self.assertEqual(EXAMPLE['provider'], test_load_balancer.provider) self.assertEqual(EXAMPLE['provisioning_status'], test_load_balancer.provisioning_status) - self.assertEqual(EXAMPLE['updated_at'], test_load_balancer.updated_at), + self.assertEqual(EXAMPLE['updated_at'], test_load_balancer.updated_at) self.assertEqual(EXAMPLE['vip_address'], test_load_balancer.vip_address) self.assertEqual(EXAMPLE['vip_network_id'], @@ -152,3 +160,30 @@ class TestLoadBalancer(base.TestCase): error_message=None, has_body=False, ) + + +class TestLoadBalancerStats(base.TestCase): + + def test_basic(self): + test_load_balancer = load_balancer.LoadBalancerStats() + self.assertEqual('stats', test_load_balancer.resource_key) + self.assertEqual('/lbaas/loadbalancers/%(lb_id)s/stats', + test_load_balancer.base_path) + self.assertFalse(test_load_balancer.allow_create) + self.assertTrue(test_load_balancer.allow_fetch) + self.assertFalse(test_load_balancer.allow_delete) + self.assertFalse(test_load_balancer.allow_list) + self.assertFalse(test_load_balancer.allow_commit) + + def test_make_it(self): + test_load_balancer = load_balancer.LoadBalancerStats(**EXAMPLE_STATS) + self.assertEqual(EXAMPLE_STATS['active_connections'], + test_load_balancer.active_connections) + self.assertEqual(EXAMPLE_STATS['bytes_in'], + test_load_balancer.bytes_in) + self.assertEqual(EXAMPLE_STATS['bytes_out'], + test_load_balancer.bytes_out) + self.assertEqual(EXAMPLE_STATS['request_errors'], + test_load_balancer.request_errors) + self.assertEqual(EXAMPLE_STATS['total_connections'], + test_load_balancer.total_connections) diff --git a/openstack/tests/unit/load_balancer/test_proxy.py b/openstack/tests/unit/load_balancer/test_proxy.py index 94a3c07a3..a7bd1f838 100644 --- a/openstack/tests/unit/load_balancer/test_proxy.py +++ b/openstack/tests/unit/load_balancer/test_proxy.py @@ -28,6 +28,8 @@ from openstack.tests.unit import test_proxy_base class TestLoadBalancerProxy(test_proxy_base.TestProxyBase): + LB_ID = uuid.uuid4() + LISTENER_ID = uuid.uuid4() POOL_ID = uuid.uuid4() L7_POLICY_ID = uuid.uuid4() @@ -43,6 +45,14 @@ class TestLoadBalancerProxy(test_proxy_base.TestProxyBase): self.verify_get(self.proxy.get_load_balancer, lb.LoadBalancer) + def test_load_balancer_stats_get(self): + self.verify_get(self.proxy.get_load_balancer_statistics, + lb.LoadBalancerStats, + value=[self.LB_ID], + expected_args=[lb.LoadBalancerStats], + expected_kwargs={'lb_id': self.LB_ID, + 'requires_id': False}) + def test_load_balancer_create(self): self.verify_create(self.proxy.create_load_balancer, lb.LoadBalancer) @@ -95,6 +105,14 @@ class TestLoadBalancerProxy(test_proxy_base.TestProxyBase): self.verify_get(self.proxy.get_listener, listener.Listener) + def test_listener_stats_get(self): + self.verify_get(self.proxy.get_listener_statistics, + listener.ListenerStats, + value=[self.LISTENER_ID], + expected_args=[listener.ListenerStats], + expected_kwargs={'listener_id': self.LISTENER_ID, + 'requires_id': False}) + def test_listener_create(self): self.verify_create(self.proxy.create_listener, listener.Listener) diff --git a/releasenotes/notes/add-octavia-lb-listener-stats-1538cc6e4f734353.yaml b/releasenotes/notes/add-octavia-lb-listener-stats-1538cc6e4f734353.yaml new file mode 100644 index 000000000..8fb7f9f09 --- /dev/null +++ b/releasenotes/notes/add-octavia-lb-listener-stats-1538cc6e4f734353.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Added load balancer and listener get statistics methods.