diff --git a/doc/source/data/lbaas.csv b/doc/source/data/lbaas.csv index c093dbb..34f50d9 100644 --- a/doc/source/data/lbaas.csv +++ b/doc/source/data/lbaas.csv @@ -13,11 +13,11 @@ lbaas-l7rule-delete,,LBaaS v2 Delete a given L7 rule. lbaas-l7rule-list,,LBaaS v2 List L7 rules that belong to a given L7 policy. lbaas-l7rule-show,,LBaaS v2 Show information of a given rule. lbaas-l7rule-update,,LBaaS v2 Update a given L7 rule. -lbaas-listener-create,,LBaaS v2 Create a listener. -lbaas-listener-delete,,LBaaS v2 Delete a given listener. -lbaas-listener-list,,LBaaS v2 List listeners that belong to a given tenant. -lbaas-listener-show,,LBaaS v2 Show information of a given listener. -lbaas-listener-update,,LBaaS v2 Update a given listener. +lbaas-listener-create,loadbalancer listener create,LBaaS v2 Create a listener. +lbaas-listener-delete,loadbalancer listener delete,LBaaS v2 Delete a given listener. +lbaas-listener-list,loadbalancer listener list,LBaaS v2 List listeners that belong to a given tenant. +lbaas-listener-show,loadbalancer listener show,LBaaS v2 Show information of a given listener. +lbaas-listener-update,loadbalancer listener set,LBaaS v2 Update a given listener. lbaas-loadbalancer-create,loadbalancer create,LBaaS v2 Create a loadbalancer. lbaas-loadbalancer-delete,loadbalancer delete,LBaaS v2 Delete a given loadbalancer. lbaas-loadbalancer-list,loadbalancer list,LBaaS v2 List loadbalancers that belong to a given tenant. diff --git a/doc/source/usage/osc/v2/load-balancer.rst b/doc/source/usage/osc/v2/load-balancer.rst index dd0b1a5..7161fa8 100644 --- a/doc/source/usage/osc/v2/load-balancer.rst +++ b/doc/source/usage/osc/v2/load-balancer.rst @@ -156,3 +156,195 @@ Delete a load balancer .. option:: --cascade Cascade the delete to all child elements of the load balancer. + + +======== +listener +======== + +loadbalancer listener list +-------------------------- + +List listeners + +.. program:: loadbalancer listener list +.. code:: bash + + openstack loadbalancer listener list + [--name ] + [--enable | --disable] + [--project ] + +.. option:: --name + + List listeners by listener name. + +.. option:: --enable + + List enabled listeners. + +.. option:: --disable + + List disabled listeners. + +.. option:: --project + + List listeners by project ID. + +loadbalancer listener show +-------------------------- + +Show the details of a single listener + +.. program:: loadbalancer listener show +.. code:: bash + + openstack loadbalancer listener show + + +.. _loadbalancer_listener_show-listener: +.. describe:: + + Name or UUID of the listener + +loadbalancer listener create +---------------------------- + +Create a listener + +.. program:: loadbalancer listener create +.. code:: bash + + openstack loadbalancer listener create + [--description ] + --protocol + [--connection-limit ] + [--default-pool ] + [--default-tls-container-ref ] + [--sni-container-refs [ [ ...]]] + [--insert-headers ] + --protocol-port + [--enable | --disable] + + +.. option:: --name + + Set listener name. + +.. option:: --description + + Set the description of this listener. + +.. option:: --protocol + + The protocol for the listener + +.. option:: --connection-limit + + The maximum number of connections permitted for this listener. + +.. option:: --default-pool + + The name or ID of the pool used by the listener if no L7 policies match. + +.. option:: --default-tls-container-ref + + The URI to the key manager service secrets container containing the certificate and key for TERMINATED_TLS listeners. + +.. option:: --sni-container-refs [ [ ...]] + + A list of URIs to the key manager service secrets containers containing the certificates and keys for TERMINATED_TLS the listener using Server Name Indication. + +.. option:: --insert-headers + + A dictionary of optional headers to insert into the request before it is sent to the backend member. + +.. option:: --protocol-port + + Set the protocol port number for the listener. + +.. option:: --enable + + Enable listener (default). + +.. option:: --disable + + Disable listener. + +loadbalancer listener set +------------------------- + +Update a listener + +.. program:: loadbalancer listener set +.. code:: bash + + openstack loadbalancer listener set + [--name ] + [--description ] + [--protocol ] + [--connection-limit ] + [--default-pool ] + [--default-tls-container-ref ] + [---sni-container-refs [ [ ...]]] + [--insert-headers ] + [--enable | --disable] + + +.. _loadbalancer_listener_set-listener: +.. describe:: + + Listener to modify (name or ID). + +.. option:: --name + + Set listener name. + +.. option:: --description + + Set the description of this listener. + +.. option:: --connection-limit + + The maximum number of connections permitted for this listener. + Default value is -1 which represents infinite connections. + +.. option:: --default-pool + + The ID of the pool used by the listener if no L7 policies match. + +.. option:: --default-tls-container-ref + + The URI to the key manager service secrets container containing the certificate and key for TERMINATED_TLS listeners. + +.. option:: ---sni-container-refs [ [ ...]] + + A list of URIs to the key manager service secrets containers containing the certificates and keys for TERMINATED_TLS the listener using Server Name Indication. + +.. option:: --insert-headers + + A dictionary of optional headers to insert into the request before it is sent to the backend member. + +.. option:: --enable + + Enable listener. + +.. option:: --disable + + Disable listener. + +loadbalancer listener delete +---------------------------- + +Delete a listener + +.. program:: loadbalancer listener delete +.. code:: bash + + openstack loadbalancer listener delete + + +.. _loadbalancer_listener_delete-listener: +.. describe:: + + Listener to delete (name or ID). diff --git a/octaviaclient/api/load_balancer_v2.py b/octaviaclient/api/load_balancer_v2.py index ecf853b..1845a00 100644 --- a/octaviaclient/api/load_balancer_v2.py +++ b/octaviaclient/api/load_balancer_v2.py @@ -38,7 +38,7 @@ class APIv2(api.BaseAPI): :param params: Parameters to filter on (not implemented) :return: - List of load balancers and their settings + List of load balancers """ url = const.BASE_LOADBALANCER_URL load_balancer_list = self.list(url, **params) @@ -82,9 +82,9 @@ class APIv2(api.BaseAPI): Response Code from the API """ url = const.BASE_SINGLE_LB_URL.format(uuid=lb_id) - load_balancer = self.delete(url, params=params) + response = self.delete(url, params=params) - return load_balancer + return response def load_balancer_set(self, lb_id, **params): """Update a load balancer's settings @@ -94,9 +94,74 @@ class APIv2(api.BaseAPI): :param params: A dict of arguments to update a loadbalancer :return: - A dict of the updated load balancer's settings + Response Code from API """ url = const.BASE_SINGLE_LB_URL.format(uuid=lb_id) - load_balancer = self.create(url, method='PUT', **params) + response = self.create(url, method='PUT', **params) - return load_balancer + return response + + def listener_list(self, **kwargs): + """List all listeners + + :param kwargs: + Parameters to filter on (not implemented) + :return: + List of listeners + """ + url = const.BASE_LISTENER_URL + listener_list = self.list(url, **kwargs) + + return listener_list + + def listener_show(self, listener_id): + """Show a listener + + :param string listener_id: + :return: + A dict of the specified listener's settings + """ + listener = self.find(path=const.BASE_LISTENER_URL, value=listener_id) + + return listener + + def listener_create(self, **kwargs): + """Create a listener + + :param kwargs: + Parameters to create a listener with (expects json=) + :return: + A dict of the created listener's settings + """ + url = const.BASE_LISTENER_URL + listener = self.create(url, **kwargs) + + return listener + + def listener_delete(self, listener_id): + """Delete a listener + + :param stirng listener_id: + ID of of listener to delete + :return: + Response Code from the API + """ + url = const.BASE_SINGLE_LISTENER_URL.format(uuid=listener_id) + response = self.delete(url) + + return response + + def listener_set(self, listener_id, **kwargs): + """Update a listener's settings + + :param string listener_id: + ID of the listener to update + :param kwargs: + A dict of arguments to update a listener + :return: + A dict of the updated listener's settings + """ + url = const.BASE_SINGLE_LISTENER_URL.format(uuid=listener_id) + response = self.create(url, method='PUT', **kwargs) + + return response diff --git a/octaviaclient/osc/plugin.py b/octaviaclient/osc/plugin.py index f939096..8760f50 100644 --- a/octaviaclient/osc/plugin.py +++ b/octaviaclient/osc/plugin.py @@ -40,7 +40,6 @@ def make_client(instance): service_type='load-balancer', endpoint=endpoint, ) - return client diff --git a/octaviaclient/osc/v2/constants.py b/octaviaclient/osc/v2/constants.py index 3c595f2..49979df 100644 --- a/octaviaclient/osc/v2/constants.py +++ b/octaviaclient/osc/v2/constants.py @@ -37,3 +37,32 @@ LOAD_BALANCER_COLUMNS = ( 'vip_address', 'provisioning_status', 'provider') + +LISTENER_ROWS = ( + 'admin_state_up', + 'connection_limit', + 'created_at', + 'default_pool_id', + 'default_tls_container_ref', + 'description', + 'id', + 'insert_headers', + 'l7policies', + 'loadbalancers', + 'name', + 'operating_status', + 'project_id', + 'protocol', + 'protocol_port', + 'provisioning_status', + 'sni_container_refs', + 'updated_at') + +LISTENER_COLUMNS = ( + 'id', + 'default_pool_id', + 'name', + 'project_id', + 'protocol', + 'protocol_port', + 'admin_state_up') diff --git a/octaviaclient/osc/v2/listener.py b/octaviaclient/osc/v2/listener.py new file mode 100644 index 0000000..1196835 --- /dev/null +++ b/octaviaclient/osc/v2/listener.py @@ -0,0 +1,308 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Listener action implementation""" + + +from cliff import lister +import json +from osc_lib.command import command +from osc_lib import utils + +from octaviaclient.osc.v2 import constants as const +from octaviaclient.osc.v2 import utils as v2_utils + + +class CreateListener(command.ShowOne): + """Create a listener""" + + def get_parser(self, prog_name): + parser = super(CreateListener, self).get_parser(prog_name) + + parser.add_argument( + 'loadbalancer', + metavar='', + help="Load balancer for the listener (name or ID)" + ) + parser.add_argument( + '--name', + metavar='', + help="Set listener name" + ) + parser.add_argument( + '--description', + metavar='', + help="Description of this listener" + ) + parser.add_argument( + '--protocol', + metavar='', + choices=['TCP', 'HTTP', 'HTTPS', 'TERMINATED_HTTPS'], + required=True, + help="The protocol for the listener" + ) + parser.add_argument( + '--connection-limit', + type=int, + metavar='', + help="The maximum number of connections permitted for this " + "listener." + ) + parser.add_argument( + '--default-pool', + metavar='', + help="The ID of the pool used by the listener if no L7 policies " + "match." + ) + parser.add_argument( + '--default-tls-container-ref', + metavar='', + help="The URI to the key manager service secrets container " + "containing the certificate and key for TERMINATED_TLS " + "listeners." + ) + parser.add_argument( + '--sni-container-refs', + metavar='', + nargs='*', + help="A list of URIs to the key manager service secrets " + "containers containing the certificates and keys for " + "TERMINATED_TLS the listener using Server Name Indication." + ) + parser.add_argument( + '--insert-headers', + metavar='', + nargs='*', + type=json.loads, + help="A dictionary of optional headers to insert into the request " + "before it is sent to the backend member." + ) + parser.add_argument( + '--protocol-port', + metavar='', + required=True, + help="The protocol port number for the listener" + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + action='store_true', + default=True, + help="Enable listener (default)" + ) + admin_group.add_argument( + '--disable', + action='store_true', + default=None, + help="Disable listener" + ) + + return parser + + def take_action(self, parsed_args): + rows = const.LISTENER_ROWS + attrs = v2_utils.get_listener_attrs(self.app.client_manager, + parsed_args) + body = {"listener": attrs} + data = self.app.client_manager.load_balancer.listener_create( + json=body) + formatters = {'loadbalancers': v2_utils.format_list, + 'pools': v2_utils.format_list, + 'l7policies': v2_utils.format_list} + + return (rows, + (utils.get_dict_properties(data['listener'], + rows, + formatters=formatters))) + + +class DeleteListener(command.Command): + """Delete a listener""" + + def get_parser(self, prog_name): + parser = super(DeleteListener, self).get_parser(prog_name) + + parser.add_argument( + 'listener', + metavar="", + help="Listener to delete (name or ID)" + ) + + return parser + + def take_action(self, parsed_args): + attrs = v2_utils.get_listener_attrs(self.app.client_manager, + parsed_args) + + listener_id = attrs.pop('listener_id') + + self.app.client_manager.load_balancer.listener_delete( + listener_id=listener_id) + + +class ListListener(lister.Lister): + """List listeners""" + + def get_parser(self, prog_name): + parser = super(ListListener, self).get_parser(prog_name) + + # Filtering will soon be implemented to allow this + parser.add_argument( + '--name', + metavar='', + help="List listeners by listener name" + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + action='store_true', + default=None, + help="List enabled listeners" + ) + admin_group.add_argument( + '--disable', + action='store_true', + default=None, + help="List disabled listeners" + ) + parser.add_argument( + '--project', + metavar='', + help="List listeners by project ID" + ) + return parser + + def take_action(self, parsed_args): + columns = const.LISTENER_COLUMNS + attrs = v2_utils.get_listener_attrs(self.app.client_manager, + parsed_args) + data = self.app.client_manager.load_balancer.listener_list(**attrs) + formatters = {'loadbalancers': v2_utils.format_list} + return (columns, + (utils.get_dict_properties(s, columns, formatters=formatters) + for s in data['listeners'])) + + +class ShowListener(command.ShowOne): + """Show the details of a single listener""" + + def get_parser(self, prog_name): + parser = super(ShowListener, self).get_parser(prog_name) + + parser.add_argument( + 'listener', + metavar='', + help='UUID of the listener' + ) + + return parser + + def take_action(self, parsed_args): + rows = const.LISTENER_ROWS + 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.listener_show( + listener_id=listener_id, + ) + formatters = {'loadbalancers': v2_utils.format_list, + 'pools': v2_utils.format_list, + 'l7policies': v2_utils.format_list} + + return (rows, + (utils.get_dict_properties(data, rows, formatters=formatters))) + + +class SetListener(command.Command): + """Update a listener""" + + def get_parser(self, prog_name): + parser = super(SetListener, self).get_parser(prog_name) + + parser.add_argument( + 'listener', + metavar="", + help="Listener to modify (name or ID)" + ) + parser.add_argument( + '--name', + metavar='', + help="Set listener name" + ) + parser.add_argument( + '--description', + metavar='', + help="Description of this listener" + ) + parser.add_argument( + '--connection-limit', + metavar='', + help="The maximum number of connections permitted for this " + "listener. Default value is -1 which represents infinite " + "connections." + ) + parser.add_argument( + '--default-pool', + metavar='', + help="The ID of the pool used by the listener if no L7 policies " + "match." + ) + parser.add_argument( + '--default-tls-container-ref', + metavar='', + help="The URI to the key manager service secrets container " + "containing the certificate and key for TERMINATED_TLS" + "listeners." + ) + parser.add_argument( + '---sni-container-refs', + metavar='', + nargs='*', + help="A list of URIs to the key manager service secrets " + "containers containing the certificates and keys for " + "TERMINATED_TLS the listener using Server Name Indication." + ) + parser.add_argument( + '--insert-headers', + metavar='', + help="A dictionary of optional headers to insert into the request " + "before it is sent to the backend member." + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + action='store_true', + default=None, + help="Enable listener" + ) + admin_group.add_argument( + '--disable', + action='store_true', + default=None, + help="Disable listener" + ) + + return parser + + def take_action(self, parsed_args): + attrs = v2_utils.get_listener_attrs(self.app.client_manager, + parsed_args) + + listener_id = attrs.pop('listener_id') + + body = {'listener': attrs} + + self.app.client_manager.load_balancer.listener_set( + listener_id, json=body) diff --git a/octaviaclient/osc/v2/load_balancer.py b/octaviaclient/osc/v2/load_balancer.py index 2479d15..b127311 100644 --- a/octaviaclient/osc/v2/load_balancer.py +++ b/octaviaclient/osc/v2/load_balancer.py @@ -95,8 +95,9 @@ class CreateLoadBalancer(command.ShowOne): 'l7policies': v2_utils.format_list } - return (rows, (utils.get_dict_properties( - data['loadbalancer'], rows, formatters=formatters))) + return (rows, + (utils.get_dict_properties( + data['loadbalancer'], rows, formatters=formatters))) class DeleteLoadBalancer(command.Command): diff --git a/octaviaclient/osc/v2/utils.py b/octaviaclient/osc/v2/utils.py index fa6b347..a69f769 100644 --- a/octaviaclient/osc/v2/utils.py +++ b/octaviaclient/osc/v2/utils.py @@ -111,7 +111,41 @@ def check_loadbalancer_attrs(attrs): raise exceptions.CommandError(msg) -def format_headers(headers): +def get_listener_attrs(client_manager, parsed_args): + attr_map = { + 'name': ('name', str), + 'description': ('description', str), + 'protocol': ('protocol', str), + 'listener': ( + 'listener_id', + 'listeners', + client_manager.load_balancer.listener_list + ), + 'loadbalancer': ( + 'loadbalancer_id', + 'loadbalancers', + client_manager.load_balancer.load_balancer_list + ), + 'connection_limit': ('connection_limit', str), + 'protocol_port': ('protocol_port', int), + 'default_pool': ('default_pool_id', str), + 'project': ( + 'project_id', + 'project', + client_manager.identity + ), + 'enable': ('admin_state_up', lambda x: True), + 'disable': ('admin_state_up', lambda x: False), + 'insert_headers': ('insert_headers', _format_headers) + } + + _attrs = vars(parsed_args) + attrs = _map_attrs(_attrs, attr_map) + + return attrs + + +def _format_headers(headers): formatted_headers = {} headers = headers.split(',') for header in headers: diff --git a/octaviaclient/tests/fakes.py b/octaviaclient/tests/fakes.py index f28f910..b718561 100644 --- a/octaviaclient/tests/fakes.py +++ b/octaviaclient/tests/fakes.py @@ -140,6 +140,7 @@ class FakeClientManager(object): self.auth_ref = None self.auth_plugin_name = None self.network_endpoint_enabled = True + self.neutronclient = mock.MagicMock() def get_configuration(self): return { diff --git a/octaviaclient/tests/unit/api/test_load_balancer.py b/octaviaclient/tests/unit/api/test_load_balancer.py index b40531f..fe9ed8e 100644 --- a/octaviaclient/tests/unit/api/test_load_balancer.py +++ b/octaviaclient/tests/unit/api/test_load_balancer.py @@ -25,6 +25,7 @@ FAKE_AUTH = '11223344556677889900' FAKE_URL = 'http://example.com/v2.0/lbaas/' FAKE_LB = uuidutils.generate_uuid() +FAKE_LI = uuidutils.generate_uuid() LIST_LB_RESP = { 'loadbalancers': @@ -32,10 +33,18 @@ LIST_LB_RESP = { {'name': 'lb2'}] } +LIST_LI_RESP = { + 'listeners': + [{'name': 'lb1'}, + {'name': 'lb2'}] +} + SINGLE_LB_RESP = {'loadbalancer': {'id': FAKE_LB, 'name': 'lb1'}} SINGLE_LB_UPDATE = {"loadbalancer": {"admin_state_up": False}} -SINGLE_LB_UPDATE_INVALID = {"loadbalancer": {"id": 'invalid_param'}} + +SINGLE_LI_RESP = {'listener': {'id': FAKE_LI, 'name': 'li1'}} +SINGLE_LI_UPDATE = {"listener": {"admin_state_up": False}} class TestLoadBalancerv2(utils.TestCase): @@ -97,3 +106,52 @@ class TestLoadBalancer(TestLoadBalancerv2): ) ret = self.api.load_balancer_delete(FAKE_LB) self.assertEqual(200, ret.status_code) + + def test_list_listeners_no_options(self): + self.requests_mock.register_uri( + 'GET', + FAKE_URL + 'listeners', + json=LIST_LI_RESP, + status_code=200, + ) + ret = self.api.listener_list() + self.assertEqual(LIST_LI_RESP, ret) + + def test_show_listener(self): + self.requests_mock.register_uri( + 'GET', + FAKE_URL + 'listeners/' + FAKE_LI, + json=SINGLE_LI_RESP, + status_code=200 + ) + ret = self.api.listener_show(FAKE_LI) + self.assertEqual(SINGLE_LI_RESP['listener'], ret) + + def test_create_listener(self): + self.requests_mock.register_uri( + 'POST', + FAKE_URL + 'listeners', + json=SINGLE_LI_RESP, + status_code=200 + ) + ret = self.api.listener_create(json=SINGLE_LI_RESP) + self.assertEqual(SINGLE_LI_RESP, ret) + + def test_set_listeners(self): + self.requests_mock.register_uri( + 'PUT', + FAKE_URL + 'listeners/' + FAKE_LI, + json=SINGLE_LI_UPDATE, + status_code=200 + ) + ret = self.api.listener_set(FAKE_LI, json=SINGLE_LI_UPDATE) + self.assertEqual(SINGLE_LI_UPDATE, ret) + + def test_delete_listener(self): + self.requests_mock.register_uri( + 'DELETE', + FAKE_URL + 'listeners/' + FAKE_LI, + status_code=200 + ) + ret = self.api.listener_delete(FAKE_LI) + self.assertEqual(200, ret.status_code) diff --git a/octaviaclient/tests/unit/osc/v2/fakes.py b/octaviaclient/tests/unit/osc/v2/fakes.py index ccf9d56..1ee143a 100644 --- a/octaviaclient/tests/unit/osc/v2/fakes.py +++ b/octaviaclient/tests/unit/osc/v2/fakes.py @@ -41,7 +41,6 @@ class TestLoadBalancerv2(utils.TestCommand): def setUp(self): super(TestLoadBalancerv2, self).setUp() - self.app.client_manager.load_balancer = FakeLoadBalancerv2Client( endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, @@ -80,3 +79,31 @@ class FakeLoadBalancer(object): loaded=True) return lb + + +class FakeListener(object): + """Fake one or more listeners.""" + + @staticmethod + def create_one_listener(attrs=None): + attrs = attrs or {} + + li_info = { + 'id': str(uuid.uuid4()), + 'name': 'li-name-' + uuid.uuid4().hex, + 'project_id': uuid.uuid4().hex, + 'protocol': 'HTTP', + 'protocol_port': 80, + 'provisioning_status': 'ACTIVE', + 'default_pool_id': None, + 'connection_limit': 10, + 'admin_state_up': True, + } + + li_info.update(attrs) + + li = fakes.FakeResource( + info=copy.deepcopy(li_info), + loaded=True) + + return li diff --git a/octaviaclient/tests/unit/osc/v2/test_listener.py b/octaviaclient/tests/unit/osc/v2/test_listener.py new file mode 100644 index 0000000..c969f16 --- /dev/null +++ b/octaviaclient/tests/unit/osc/v2/test_listener.py @@ -0,0 +1,209 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import copy +import mock + +from osc_lib import exceptions + +from octaviaclient.osc.v2 import listener as listener +from octaviaclient.tests.unit.osc.v2 import fakes as li_fakes + +AUTH_TOKEN = "foobar" +AUTH_URL = "http://192.0.2.2" + + +class TestListener(li_fakes.TestLoadBalancerv2): + + _li = li_fakes.FakeListener.create_one_listener() + + columns = ( + 'id', + 'default_pool_id', + 'name', + 'project_id', + 'protocol', + 'protocol_port', + 'admin_state_up') + + datalist = ( + ( + _li.id, + _li.default_pool_id, + _li.name, + _li.project_id, + _li.protocol, + _li.protocol_port, + _li.admin_state_up + ), + ) + + info = { + 'listeners': + [{ + 'id': _li.id, + 'name': _li.name, + 'project_id': _li.project_id, + 'loadbalancers': None, + 'provisioning_status': _li.provisioning_status, + 'default_pool_id': _li.default_pool_id, + 'connection_limit': _li.connection_limit, + 'protocol': _li.protocol, + 'protocol_port': _li.protocol_port, + 'admin_state_up': _li.admin_state_up + }] + } + + li_info = copy.deepcopy(info) + + def setUp(self): + super(TestListener, self).setUp() + self.li_mock = self.app.client_manager.load_balancer.load_balancers + self.li_mock.reset_mock() + + self.api_mock = mock.Mock() + self.api_mock.listener_list.return_value = self.li_info + lb_client = self.app.client_manager + lb_client.load_balancer = self.api_mock + + +class TestListenerList(TestListener): + + def setUp(self): + super(TestListenerList, self).setUp() + self.cmd = listener.ListListener(self.app, None) + + def test_listener_list_no_options(self): + arglist = [] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.api_mock.listener_list.assert_called_with() + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) + + def test_listener_list_with_options(self): + arglist = ['--name', 'rainbarrel'] + verifylist = [('name', 'rainbarrel')] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.listener_list.assert_called_with(name='rainbarrel') + + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) + + +class TestListenerDelete(TestListener): + + def setUp(self): + super(TestListenerDelete, self).setUp() + self.cmd = listener.DeleteListener(self.app, None) + + def test_listener_delete(self): + arglist = [self._li.id] + verifylist = [ + ('listener', self._li.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.api_mock.listener_delete.assert_called_with( + listener_id=self._li.id) + + def test_listener_delete_failure(self): + arglist = ['unknown_lb'] + verifylist = [ + ('listener', 'unknown_lb') + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, self.cmd.take_action, + parsed_args) + self.assertNotCalled(self.api_mock.listener_delete) + + +class TestListenerCreate(TestListener): + + def setUp(self): + super(TestListenerCreate, self).setUp() + self.api_mock = mock.Mock() + self.api_mock.listener_create.return_value = { + 'listener': self.li_info} + lb_client = self.app.client_manager + lb_client.load_balancer = self.api_mock + + self.cmd = listener.CreateListener(self.app, None) + + @mock.patch('octaviaclient.osc.v2.utils.get_listener_attrs') + def test_listener_create(self, mock_client): + mock_client.return_value = self.li_info + arglist = ['mock_lb_id', + '--name', self._li.name, + '--protocol', 'HTTP', + '--protocol-port', '80'] + verifylist = [ + ('loadbalancer', 'mock_lb_id'), + ('name', self._li.name), + ('protocol', 'HTTP'), + ('protocol_port', '80') + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.api_mock.listener_create.assert_called_with( + json={'listener': self.li_info}) + + +class TestListenerShow(TestListener): + + def setUp(self): + super(TestListenerShow, self).setUp() + self.api_mock = mock.Mock() + self.api_mock.listener_list.return_value = self.li_info + self.api_mock.listener_show.return_value = { + 'listener': self.li_info['listeners'][0]} + lb_client = self.app.client_manager + lb_client.load_balancer = self.api_mock + + self.cmd = listener.ShowListener(self.app, None) + + def test_listener_show(self): + arglist = [self._li.id] + verifylist = [ + ('listener', self._li.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.api_mock.listener_show.assert_called_with(listener_id=self._li.id) + + +class TestListenerSet(TestListener): + + def setUp(self): + super(TestListenerSet, self).setUp() + self.cmd = listener.SetListener(self.app, None) + + def test_listener_set(self): + arglist = [self._li.id, '--name', 'new_name'] + verifylist = [ + ('listener', self._li.id), + ('name', 'new_name') + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.api_mock.listener_set.assert_called_with( + self._li.id, json={'listener': {'name': 'new_name'}}) diff --git a/octaviaclient/tests/unit/osc/v2/test_load_balancer.py b/octaviaclient/tests/unit/osc/v2/test_load_balancer.py index 6b33859..4b38dd8 100644 --- a/octaviaclient/tests/unit/osc/v2/test_load_balancer.py +++ b/octaviaclient/tests/unit/osc/v2/test_load_balancer.py @@ -185,6 +185,7 @@ class TestLoadBalancerShow(TestLoadBalancer): class TestLoadBalancerSet(TestLoadBalancer): + def setUp(self): super(TestLoadBalancerSet, self).setUp() self.cmd = load_balancer.SetLoadBalancer(self.app, None) diff --git a/setup.cfg b/setup.cfg index 10b7641..6db6978 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,11 @@ openstack.load_balancer.v2 = loadbalancer_show = octaviaclient.osc.v2.load_balancer:ShowLoadBalancer loadbalancer_delete = octaviaclient.osc.v2.load_balancer:DeleteLoadBalancer loadbalancer_set = octaviaclient.osc.v2.load_balancer:SetLoadBalancer + loadbalancer_listener_create = octaviaclient.osc.v2.listener:CreateListener + loadbalancer_listener_list = octaviaclient.osc.v2.listener:ListListener + loadbalancer_listener_show = octaviaclient.osc.v2.listener:ShowListener + loadbalancer_listener_delete = octaviaclient.osc.v2.listener:DeleteListener + loadbalancer_listener_set = octaviaclient.osc.v2.listener:SetListener [build_sphinx] source-dir = doc/source