diff --git a/octaviaclient/api/constants.py b/octaviaclient/api/constants.py index 9d8464b..77f5818 100644 --- a/octaviaclient/api/constants.py +++ b/octaviaclient/api/constants.py @@ -11,54 +11,72 @@ # under the License. # +LOADBALANCER_RESOURCES = 'loadbalancers' +LISTENER_RESOURCES = 'listeners' +POOL_RESOURCES = 'pools' +MEMBER_RESOURCES = 'members' +HEALTH_MONITOR_RESOURCES = 'healthmonitors' +L7POLICY_RESOURCES = 'l7policies' +L7RULE_RESOURCES = 'rules' +QUOTA_RESOURCES = 'quotas' +AMPHORA_RESOURCES = 'amphorae' +PROVIDER_RESOURCES = 'providers' +PROVIDER_FLAVOR_CAPABILITY_RESOURCES = 'flavor_capabilities' +PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES = ( + 'availability_zone_capabilities') +FLAVOR_RESOURCES = 'flavors' +FLAVORPROFILE_RESOURCES = 'flavorprofiles' +AVAILABILITYZONE_RESOURCES = 'availability_zones' +AVAILABILITYZONEPROFILE_RESOURCES = 'availability_zone_profiles' + BASE_LBAAS_ENDPOINT = '/lbaas' BASE_OCTAVIA_ENDPOINT = '/octavia' -BASE_LOADBALANCER_URL = BASE_LBAAS_ENDPOINT + '/loadbalancers' +BASE_LOADBALANCER_URL = BASE_LBAAS_ENDPOINT + '/' + LOADBALANCER_RESOURCES BASE_SINGLE_LB_URL = BASE_LOADBALANCER_URL + '/{uuid}' BASE_LB_STATS_URL = BASE_SINGLE_LB_URL + '/stats' BASE_LOADBALANCER_STATUS_URL = BASE_SINGLE_LB_URL + '/status' BASE_LOADBALANCER_FAILOVER_URL = BASE_SINGLE_LB_URL + '/failover' -BASE_LISTENER_URL = BASE_LBAAS_ENDPOINT + '/listeners' +BASE_LISTENER_URL = BASE_LBAAS_ENDPOINT + '/' + LISTENER_RESOURCES BASE_SINGLE_LISTENER_URL = BASE_LISTENER_URL + '/{uuid}' BASE_LISTENER_STATS_URL = BASE_SINGLE_LISTENER_URL + '/stats' -BASE_POOL_URL = BASE_LBAAS_ENDPOINT + '/pools' +BASE_POOL_URL = BASE_LBAAS_ENDPOINT + '/' + POOL_RESOURCES BASE_SINGLE_POOL_URL = BASE_POOL_URL + '/{pool_id}' -BASE_MEMBER_URL = BASE_SINGLE_POOL_URL + '/members' +BASE_MEMBER_URL = BASE_SINGLE_POOL_URL + '/' + MEMBER_RESOURCES BASE_SINGLE_MEMBER_URL = BASE_MEMBER_URL + '/{member_id}' -BASE_HEALTH_MONITOR_URL = BASE_LBAAS_ENDPOINT + '/healthmonitors' +BASE_HEALTH_MONITOR_URL = BASE_LBAAS_ENDPOINT + '/' + HEALTH_MONITOR_RESOURCES BASE_SINGLE_HEALTH_MONITOR_URL = BASE_HEALTH_MONITOR_URL + '/{uuid}' -BASE_L7POLICY_URL = BASE_LBAAS_ENDPOINT + '/l7policies' +BASE_L7POLICY_URL = BASE_LBAAS_ENDPOINT + '/' + L7POLICY_RESOURCES BASE_SINGLE_L7POLICY_URL = BASE_L7POLICY_URL + '/{policy_uuid}' -BASE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules' -BASE_SINGLE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules/{rule_uuid}' +BASE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/' + L7RULE_RESOURCES +BASE_SINGLE_L7RULE_URL = BASE_L7RULE_URL + '/{rule_uuid}' -BASE_QUOTA_URL = BASE_LBAAS_ENDPOINT + '/quotas' +BASE_QUOTA_URL = BASE_LBAAS_ENDPOINT + '/' + QUOTA_RESOURCES BASE_SINGLE_QUOTA_URL = BASE_QUOTA_URL + '/{uuid}' BASE_QUOTA_DEFAULT_URL = BASE_QUOTA_URL + '/defaults' -BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/amphorae" +BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/" + AMPHORA_RESOURCES 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_URL = BASE_LBAAS_ENDPOINT + "/" + PROVIDER_RESOURCES BASE_PROVIDER_FLAVOR_CAPABILITY_URL = ( - BASE_LBAAS_ENDPOINT + "/providers/{provider}/flavor_capabilities") + BASE_PROVIDER_URL + "/{provider}/" + PROVIDER_FLAVOR_CAPABILITY_RESOURCES) BASE_PROVIDER_AVAILABILITY_ZONE_CAPABILITY_URL = ( - BASE_LBAAS_ENDPOINT + "/providers/{provider}" - "/availability_zone_capabilities" + BASE_PROVIDER_URL + "/{provider}/" + + PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES ) -BASE_FLAVOR_URL = BASE_LBAAS_ENDPOINT + "/flavors" +BASE_FLAVOR_URL = BASE_LBAAS_ENDPOINT + "/" + FLAVOR_RESOURCES BASE_SINGLE_FLAVOR_URL = BASE_FLAVOR_URL + "/{uuid}" -BASE_FLAVORPROFILE_URL = BASE_LBAAS_ENDPOINT + "/flavorprofiles" +BASE_FLAVORPROFILE_URL = BASE_LBAAS_ENDPOINT + "/" + FLAVORPROFILE_RESOURCES BASE_SINGLE_FLAVORPROFILE_URL = BASE_FLAVORPROFILE_URL + "/{uuid}" BASE_AVAILABILITYZONE_URL = BASE_LBAAS_ENDPOINT + "/availabilityzones" diff --git a/octaviaclient/api/v2/octavia.py b/octaviaclient/api/v2/octavia.py index 164375f..ce155cb 100644 --- a/octaviaclient/api/v2/octavia.py +++ b/octaviaclient/api/v2/octavia.py @@ -12,6 +12,7 @@ # """Octavia API Library""" import functools +import urllib.parse as urlparse from osc_lib.api import api from osc_lib import exceptions as osc_exc @@ -66,17 +67,39 @@ class OctaviaAPI(api.BaseAPI): _endpoint_suffix = '/v2.0' + # Make sure we are always requesting JSON responses + JSON_HEADER = {'Accept': 'application/json'} + def __init__(self, endpoint=None, **kwargs): super().__init__(endpoint=endpoint, **kwargs) self.endpoint = self.endpoint.rstrip('/') self._build_url() - # Make sure we are always requesting JSON responses - JSON_HEADER = {'Accept': 'application/json'} - self._create = functools.partial(self.create, headers=JSON_HEADER) - self._delete = functools.partial(self.delete, headers=JSON_HEADER) - self._find = functools.partial(self.find, headers=JSON_HEADER) - self._list = functools.partial(self.list, headers=JSON_HEADER) + self._create = functools.partial(self.create, headers=self.JSON_HEADER) + self._delete = functools.partial(self.delete, headers=self.JSON_HEADER) + self._find = functools.partial(self.find, headers=self.JSON_HEADER) + + def _list(self, path, **params): + get_all = params.pop('get_all', False) + if not get_all: + return self.list(path, **params, headers=self.JSON_HEADER) + + # Enable pagination for 'resources' + resource_key = params.pop('resources') + res = [] + while True: + response = self.list(path, **params, headers=self.JSON_HEADER) + res.extend(response[resource_key]) + + links = response.get("{}_links".format(resource_key), []) + for link in links: + if link.get('rel') == 'next': + query_str = urlparse.urlparse(link['href']).query + params = urlparse.parse_qs(query_str) + break + else: + break + return {resource_key: res} def _build_url(self): if not self.endpoint.endswith(self._endpoint_suffix): @@ -91,7 +114,9 @@ class OctaviaAPI(api.BaseAPI): List of load balancers """ url = const.BASE_LOADBALANCER_URL - response = self._list(url, **params) + response = self._list(url, get_all=True, + resources=const.LOADBALANCER_RESOURCES, + **params) return response @@ -203,7 +228,9 @@ class OctaviaAPI(api.BaseAPI): List of listeners """ url = const.BASE_LISTENER_URL - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.LISTENER_RESOURCES, + **kwargs) return response @@ -286,7 +313,9 @@ class OctaviaAPI(api.BaseAPI): List of pools """ url = const.BASE_POOL_URL - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.POOL_RESOURCES, + **kwargs) return response @@ -358,7 +387,9 @@ class OctaviaAPI(api.BaseAPI): Response list members """ url = const.BASE_MEMBER_URL.format(pool_id=pool_id) - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.MEMBER_RESOURCES, + **kwargs) return response @@ -441,7 +472,9 @@ class OctaviaAPI(api.BaseAPI): List of l7policies """ url = const.BASE_L7POLICY_URL - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.L7POLICY_RESOURCES, + **kwargs) return response @@ -511,7 +544,9 @@ class OctaviaAPI(api.BaseAPI): List of l7rules """ url = const.BASE_L7RULE_URL.format(policy_uuid=l7policy_id) - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.L7RULE_RESOURCES, + **kwargs) return response @@ -592,7 +627,9 @@ class OctaviaAPI(api.BaseAPI): A dict containing a list of health monitors """ url = const.BASE_HEALTH_MONITOR_URL - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.HEALTH_MONITOR_RESOURCES, + **kwargs) return response @@ -665,7 +702,9 @@ class OctaviaAPI(api.BaseAPI): A ``dict`` representing a list of quotas for the project """ url = const.BASE_QUOTA_URL - response = self._list(url, **params) + response = self._list(url, get_all=True, + resources=const.QUOTA_RESOURCES, + **params) return response @@ -746,7 +785,9 @@ class OctaviaAPI(api.BaseAPI): A ``dict`` containing a list of amphorae """ url = const.BASE_AMPHORA_URL - response = self._list(path=url, **kwargs) + response = self._list(path=url, get_all=True, + resources=const.AMPHORA_RESOURCES, + **kwargs) return response @@ -812,7 +853,8 @@ class OctaviaAPI(api.BaseAPI): A ``dict`` containing a list of provider """ url = const.BASE_PROVIDER_URL - response = self._list(path=url) + response = self._list(path=url, get_all=True, + resources=const.PROVIDER_RESOURCES) return response @@ -826,7 +868,9 @@ class OctaviaAPI(api.BaseAPI): """ url = const.BASE_PROVIDER_FLAVOR_CAPABILITY_URL.format( provider=provider) - response = self._list(url) + resources = const.PROVIDER_FLAVOR_CAPABILITY_RESOURCES + response = self._list(url, get_all=True, + resources=resources) return response @@ -840,7 +884,9 @@ class OctaviaAPI(api.BaseAPI): """ url = const.BASE_PROVIDER_AVAILABILITY_ZONE_CAPABILITY_URL.format( provider=provider) - response = self._list(url) + resources = const.PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES + response = self._list(url, get_all=True, + resources=resources) return response @@ -853,7 +899,8 @@ class OctaviaAPI(api.BaseAPI): A ``dict`` containing a list of flavor """ url = const.BASE_FLAVOR_URL - response = self._list(path=url, **kwargs) + response = self._list(path=url, get_all=True, + resources=const.FLAVOR_RESOURCES, **kwargs) return response @@ -937,7 +984,9 @@ class OctaviaAPI(api.BaseAPI): List of flavor profile """ url = const.BASE_FLAVORPROFILE_URL - response = self._list(url, **kwargs) + response = self._list(url, get_all=True, + resources=const.FLAVORPROFILE_RESOURCES, + **kwargs) return response @@ -993,7 +1042,9 @@ class OctaviaAPI(api.BaseAPI): A ``dict`` containing a list of availabilityzone """ url = const.BASE_AVAILABILITYZONE_URL - response = self._list(path=url, **kwargs) + response = self._list(path=url, get_all=True, + resources=const.AVAILABILITYZONE_RESOURCES, + **kwargs) return response @@ -1081,7 +1132,10 @@ class OctaviaAPI(api.BaseAPI): List of availabilityzone profile """ url = const.BASE_AVAILABILITYZONEPROFILE_URL - response = self._list(url, **kwargs) + resources = const.AVAILABILITYZONEPROFILE_RESOURCES + response = self._list(url, get_all=True, + resources=resources, + **kwargs) return response diff --git a/octaviaclient/tests/unit/api/test_octavia.py b/octaviaclient/tests/unit/api/test_octavia.py index 632dc52..635b336 100644 --- a/octaviaclient/tests/unit/api/test_octavia.py +++ b/octaviaclient/tests/unit/api/test_octavia.py @@ -68,10 +68,11 @@ LIST_ME_RESP = { {'name': 'mem2'}] } -LIST_L7PO_RESP = [ - {'name': 'l71'}, - {'name': 'l72'}, -] +LIST_L7PO_RESP = { + 'l7policies': + [{'name': 'l71'}, + {'name': 'l72'}] +} LIST_L7RU_RESP = { 'rules': diff --git a/releasenotes/notes/fix-cli-pagination-792ad8cd386eb0e7.yaml b/releasenotes/notes/fix-cli-pagination-792ad8cd386eb0e7.yaml new file mode 100644 index 0000000..146b04c --- /dev/null +++ b/releasenotes/notes/fix-cli-pagination-792ad8cd386eb0e7.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed some issues when the number of Octavia resources exceeded the + 'pagination_max_limit' parameter in Octavia API. The list calls now support + pagination.