diff --git a/octaviaclient/api/constants.py b/octaviaclient/api/constants.py index dd9a706..9d8464b 100644 --- a/octaviaclient/api/constants.py +++ b/octaviaclient/api/constants.py @@ -46,6 +46,7 @@ BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/amphorae" BASE_SINGLE_AMPHORA_URL = BASE_AMPHORA_URL + "/{uuid}" BASE_AMPHORA_CONFIGURE_URL = BASE_SINGLE_AMPHORA_URL + '/config' BASE_AMPHORA_FAILOVER_URL = BASE_SINGLE_AMPHORA_URL + '/failover' +BASE_AMPHORA_STATS_URL = BASE_SINGLE_AMPHORA_URL + '/stats' BASE_PROVIDER_URL = BASE_LBAAS_ENDPOINT + "/providers" BASE_PROVIDER_FLAVOR_CAPABILITY_URL = ( diff --git a/octaviaclient/api/v2/octavia.py b/octaviaclient/api/v2/octavia.py index d9abe06..2e31a2e 100644 --- a/octaviaclient/api/v2/octavia.py +++ b/octaviaclient/api/v2/octavia.py @@ -778,6 +778,19 @@ class OctaviaAPI(api.BaseAPI): return response + def amphora_stats_show(self, amphora_id, **kwargs): + """Show the current statistics for an amphora + + :param string amphora_id: + ID of the amphora to show + :return: + A ``list`` of ``dict`` of the specified amphora's statistics + """ + url = const.BASE_AMPHORA_STATS_URL.format(uuid=amphora_id) + response = self._list(path=url, **kwargs) + + return response + def provider_list(self): """List all providers diff --git a/octaviaclient/osc/v2/amphora.py b/octaviaclient/osc/v2/amphora.py index 0f5d3e8..a0fb7d8 100644 --- a/octaviaclient/osc/v2/amphora.py +++ b/octaviaclient/osc/v2/amphora.py @@ -194,3 +194,51 @@ class FailoverAmphora(command.Command): amphora_show), res_id=amp_id ) + + +class ShowAmphoraStats(command.ShowOne): + """Shows the current statistics for an amphora.""" + + def get_parser(self, prog_name): + parser = super(ShowAmphoraStats, self).get_parser(prog_name) + + parser.add_argument( + '--listener', + metavar='', + help='Filter by listener (name or ID)', + ) + parser.add_argument( + 'amphora_id', + metavar='', + help='UUID of the amphora' + ) + + return parser + + def take_action(self, parsed_args): + rows = const.LOAD_BALANCER_STATS_ROWS + + listener_id = None + + if parsed_args.listener is not None: + attrs = v2_utils.get_listener_attrs( + self.app.client_manager, + parsed_args) + listener_id = attrs.pop('listener_id') + + data = self.app.client_manager.load_balancer.amphora_stats_show( + amphora_id=parsed_args.amphora_id + ) + + total_stats = { + key: 0 + for key in rows + } + for stats in data['amphora_stats']: + if listener_id is None or listener_id == stats['listener_id']: + for key in stats: + if key in rows: + total_stats[key] += stats[key] + + return (rows, (utils.get_dict_properties( + total_stats, rows, formatters={}))) diff --git a/octaviaclient/tests/unit/api/test_octavia.py b/octaviaclient/tests/unit/api/test_octavia.py index 827826d..c7a2951 100644 --- a/octaviaclient/tests/unit/api/test_octavia.py +++ b/octaviaclient/tests/unit/api/test_octavia.py @@ -154,6 +154,7 @@ SINGLE_HM_UPDATE = {'healthmonitor': {'admin_state_up': False}} SINGLE_QT_RESP = {'quota': {'pool': -1}} SINGLE_QT_UPDATE = {'quota': {'pool': -1}} SINGLB_AMP_RESP = {'amphora': {'id': FAKE_AMP}} +SINGLE_AMP_STATS_RESP = {'bytes_in': '0'} SINGLE_PROVIDER_CAPABILITY_RESP = { 'flavor_capabilities': @@ -968,6 +969,16 @@ class TestLoadBalancer(TestOctaviaClient): self.api.amphora_configure, FAKE_AMP) + def test_stats_show_amphora(self): + self.requests_mock.register_uri( + 'GET', + FAKE_OCTAVIA_URL + 'amphorae/' + FAKE_AMP + '/stats', + json=SINGLE_AMP_STATS_RESP, + status_code=200 + ) + ret = self.api.amphora_stats_show(FAKE_AMP) + self.assertEqual(SINGLE_AMP_STATS_RESP, ret) + def test_failover_amphora(self): self.requests_mock.register_uri( 'PUT', diff --git a/octaviaclient/tests/unit/osc/v2/test_amphora.py b/octaviaclient/tests/unit/osc/v2/test_amphora.py index abf2f8a..ffdb933 100644 --- a/octaviaclient/tests/unit/osc/v2/test_amphora.py +++ b/octaviaclient/tests/unit/osc/v2/test_amphora.py @@ -14,6 +14,7 @@ import copy from unittest import mock import osc_lib.tests.utils as osc_test_utils +from oslo_utils import uuidutils from octaviaclient.osc.v2 import amphora from octaviaclient.osc.v2 import constants @@ -212,3 +213,59 @@ class TestAmphoraFailover(TestAmphora): res_id=self._amp.id, sleep_time=mock.ANY, status_field='provisioning_status') + + +class TestAmphoraStatsShow(TestAmphora): + + def setUp(self): + super(TestAmphoraStatsShow, self).setUp() + # map fake listener_id to fake bytes_in counter + self.stats = { + uuidutils.generate_uuid(): 12, + uuidutils.generate_uuid(): 34, + } + amphora_stats_info = [ + {'listener_id': k, 'bytes_in': self.stats[k]} + for k in self.stats] + + self.api_mock.amphora_stats_show.return_value = { + 'amphora_stats': amphora_stats_info} + lb_client = self.app.client_manager + lb_client.load_balancer = self.api_mock + self.cmd = amphora.ShowAmphoraStats(self.app, None) + + def test_amphora_stats_show(self): + arglist = [self._amp.id] + verifylist = [ + ('amphora_id', self._amp.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.amphora_stats_show.assert_called_with( + amphora_id=self._amp.id) + + column_idx = columns.index('bytes_in') + total_bytes_in = sum(self.stats.values()) + self.assertEqual(data[column_idx], total_bytes_in) + + @mock.patch('octaviaclient.osc.v2.utils.get_listener_attrs') + def test_amphora_stats_show_with_listener_id(self, + mock_get_listener_attrs): + listener_id = list(self.stats)[0] + arglist = ['--listener', listener_id, self._amp.id] + verifylist = [ + ('amphora_id', self._amp.id), + ] + mock_get_listener_attrs.return_value = { + 'listener_id': listener_id + } + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.amphora_stats_show.assert_called_with( + amphora_id=self._amp.id) + + column_idx = columns.index('bytes_in') + bytes_in = self.stats[listener_id] + self.assertEqual(data[column_idx], bytes_in) diff --git a/releasenotes/notes/add-amphora-stats-show-48bc0fadf08f1057.yaml b/releasenotes/notes/add-amphora-stats-show-48bc0fadf08f1057.yaml new file mode 100644 index 0000000..7c9cb7c --- /dev/null +++ b/releasenotes/notes/add-amphora-stats-show-48bc0fadf08f1057.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Adds support for querying the amphora statistics. diff --git a/setup.cfg b/setup.cfg index 57db9c8..4dd06e2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -85,6 +85,7 @@ openstack.load_balancer.v2 = loadbalancer_amphora_show = octaviaclient.osc.v2.amphora:ShowAmphora loadbalancer_amphora_configure = octaviaclient.osc.v2.amphora:ConfigureAmphora loadbalancer_amphora_failover = octaviaclient.osc.v2.amphora:FailoverAmphora + loadbalancer_amphora_stats_show = octaviaclient.osc.v2.amphora:ShowAmphoraStats loadbalancer_provider_list = octaviaclient.osc.v2.provider:ListProvider loadbalancer_provider_capability_list = octaviaclient.osc.v2.provider:ListProviderCapability loadbalancer_flavorprofile_create = octaviaclient.osc.v2.flavorprofile:CreateFlavorProfile