Codebase list python-octaviaclient / bae65b4
Merge tag '2.3.1' into debian/wallaby python-octaviaclient 2.3.1 release meta:version: 2.3.1 meta:diff-start: - meta:series: wallaby meta:release-type: release meta:pypi: yes meta:first: no meta:release:Author: Gregory Thiemonge <gthiemon@redhat.com> meta:release:Commit: Gregory Thiemonge <gthiemon@redhat.com> meta:release:Change-Id: Icb8280040a88e6d2f98669295bc97de7aa056e08 meta:release:Code-Review+2: Thierry Carrez <thierry@openstack.org> meta:release:Code-Review+2: Elod Illes <elod.illes@est.tech> meta:release:Workflow+1: Elod Illes <elod.illes@est.tech> Michal Arbet 2 years ago
17 changed file(s) with 213 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
11 host=review.opendev.org
22 port=29418
33 project=openstack/python-octaviaclient.git
4 defaultbranch=stable/wallaby
1010 # under the License.
1111 #
1212
13 LOADBALANCER_RESOURCES = 'loadbalancers'
14 LISTENER_RESOURCES = 'listeners'
15 POOL_RESOURCES = 'pools'
16 MEMBER_RESOURCES = 'members'
17 HEALTH_MONITOR_RESOURCES = 'healthmonitors'
18 L7POLICY_RESOURCES = 'l7policies'
19 L7RULE_RESOURCES = 'rules'
20 QUOTA_RESOURCES = 'quotas'
21 AMPHORA_RESOURCES = 'amphorae'
22 PROVIDER_RESOURCES = 'providers'
23 PROVIDER_FLAVOR_CAPABILITY_RESOURCES = 'flavor_capabilities'
24 PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES = (
25 'availability_zone_capabilities')
26 FLAVOR_RESOURCES = 'flavors'
27 FLAVORPROFILE_RESOURCES = 'flavorprofiles'
28 AVAILABILITYZONE_RESOURCES = 'availability_zones'
29 AVAILABILITYZONEPROFILE_RESOURCES = 'availability_zone_profiles'
30
1331 BASE_LBAAS_ENDPOINT = '/lbaas'
1432 BASE_OCTAVIA_ENDPOINT = '/octavia'
1533
16 BASE_LOADBALANCER_URL = BASE_LBAAS_ENDPOINT + '/loadbalancers'
34 BASE_LOADBALANCER_URL = BASE_LBAAS_ENDPOINT + '/' + LOADBALANCER_RESOURCES
1735 BASE_SINGLE_LB_URL = BASE_LOADBALANCER_URL + '/{uuid}'
1836 BASE_LB_STATS_URL = BASE_SINGLE_LB_URL + '/stats'
1937 BASE_LOADBALANCER_STATUS_URL = BASE_SINGLE_LB_URL + '/status'
2038 BASE_LOADBALANCER_FAILOVER_URL = BASE_SINGLE_LB_URL + '/failover'
2139
22 BASE_LISTENER_URL = BASE_LBAAS_ENDPOINT + '/listeners'
40 BASE_LISTENER_URL = BASE_LBAAS_ENDPOINT + '/' + LISTENER_RESOURCES
2341 BASE_SINGLE_LISTENER_URL = BASE_LISTENER_URL + '/{uuid}'
2442 BASE_LISTENER_STATS_URL = BASE_SINGLE_LISTENER_URL + '/stats'
2543
26 BASE_POOL_URL = BASE_LBAAS_ENDPOINT + '/pools'
44 BASE_POOL_URL = BASE_LBAAS_ENDPOINT + '/' + POOL_RESOURCES
2745 BASE_SINGLE_POOL_URL = BASE_POOL_URL + '/{pool_id}'
2846
29 BASE_MEMBER_URL = BASE_SINGLE_POOL_URL + '/members'
47 BASE_MEMBER_URL = BASE_SINGLE_POOL_URL + '/' + MEMBER_RESOURCES
3048 BASE_SINGLE_MEMBER_URL = BASE_MEMBER_URL + '/{member_id}'
3149
32 BASE_HEALTH_MONITOR_URL = BASE_LBAAS_ENDPOINT + '/healthmonitors'
50 BASE_HEALTH_MONITOR_URL = BASE_LBAAS_ENDPOINT + '/' + HEALTH_MONITOR_RESOURCES
3351 BASE_SINGLE_HEALTH_MONITOR_URL = BASE_HEALTH_MONITOR_URL + '/{uuid}'
3452
35 BASE_L7POLICY_URL = BASE_LBAAS_ENDPOINT + '/l7policies'
53 BASE_L7POLICY_URL = BASE_LBAAS_ENDPOINT + '/' + L7POLICY_RESOURCES
3654 BASE_SINGLE_L7POLICY_URL = BASE_L7POLICY_URL + '/{policy_uuid}'
37 BASE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules'
38 BASE_SINGLE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules/{rule_uuid}'
55 BASE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/' + L7RULE_RESOURCES
56 BASE_SINGLE_L7RULE_URL = BASE_L7RULE_URL + '/{rule_uuid}'
3957
40 BASE_QUOTA_URL = BASE_LBAAS_ENDPOINT + '/quotas'
58 BASE_QUOTA_URL = BASE_LBAAS_ENDPOINT + '/' + QUOTA_RESOURCES
4159 BASE_SINGLE_QUOTA_URL = BASE_QUOTA_URL + '/{uuid}'
4260 BASE_QUOTA_DEFAULT_URL = BASE_QUOTA_URL + '/defaults'
4361
44 BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/amphorae"
62 BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/" + AMPHORA_RESOURCES
4563 BASE_SINGLE_AMPHORA_URL = BASE_AMPHORA_URL + "/{uuid}"
4664 BASE_AMPHORA_CONFIGURE_URL = BASE_SINGLE_AMPHORA_URL + '/config'
4765 BASE_AMPHORA_FAILOVER_URL = BASE_SINGLE_AMPHORA_URL + '/failover'
4866 BASE_AMPHORA_STATS_URL = BASE_SINGLE_AMPHORA_URL + '/stats'
4967
50 BASE_PROVIDER_URL = BASE_LBAAS_ENDPOINT + "/providers"
68 BASE_PROVIDER_URL = BASE_LBAAS_ENDPOINT + "/" + PROVIDER_RESOURCES
5169 BASE_PROVIDER_FLAVOR_CAPABILITY_URL = (
52 BASE_LBAAS_ENDPOINT + "/providers/{provider}/flavor_capabilities")
70 BASE_PROVIDER_URL + "/{provider}/" + PROVIDER_FLAVOR_CAPABILITY_RESOURCES)
5371 BASE_PROVIDER_AVAILABILITY_ZONE_CAPABILITY_URL = (
54 BASE_LBAAS_ENDPOINT + "/providers/{provider}"
55 "/availability_zone_capabilities"
72 BASE_PROVIDER_URL + "/{provider}/" +
73 PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES
5674 )
5775
58 BASE_FLAVOR_URL = BASE_LBAAS_ENDPOINT + "/flavors"
76 BASE_FLAVOR_URL = BASE_LBAAS_ENDPOINT + "/" + FLAVOR_RESOURCES
5977 BASE_SINGLE_FLAVOR_URL = BASE_FLAVOR_URL + "/{uuid}"
60 BASE_FLAVORPROFILE_URL = BASE_LBAAS_ENDPOINT + "/flavorprofiles"
78 BASE_FLAVORPROFILE_URL = BASE_LBAAS_ENDPOINT + "/" + FLAVORPROFILE_RESOURCES
6179 BASE_SINGLE_FLAVORPROFILE_URL = BASE_FLAVORPROFILE_URL + "/{uuid}"
6280
6381 BASE_AVAILABILITYZONE_URL = BASE_LBAAS_ENDPOINT + "/availabilityzones"
1111 #
1212 """Octavia API Library"""
1313 import functools
14 import urllib.parse as urlparse
1415
1516 from osc_lib.api import api
1617 from osc_lib import exceptions as osc_exc
6566
6667 _endpoint_suffix = '/v2.0'
6768
69 # Make sure we are always requesting JSON responses
70 JSON_HEADER = {'Accept': 'application/json'}
71
6872 def __init__(self, endpoint=None, **kwargs):
6973 super().__init__(endpoint=endpoint, **kwargs)
7074 self.endpoint = self.endpoint.rstrip('/')
7175 self._build_url()
7276
73 # Make sure we are always requesting JSON responses
74 JSON_HEADER = {'Accept': 'application/json'}
75 self._create = functools.partial(self.create, headers=JSON_HEADER)
76 self._delete = functools.partial(self.delete, headers=JSON_HEADER)
77 self._find = functools.partial(self.find, headers=JSON_HEADER)
78 self._list = functools.partial(self.list, headers=JSON_HEADER)
77 self._create = functools.partial(self.create, headers=self.JSON_HEADER)
78 self._delete = functools.partial(self.delete, headers=self.JSON_HEADER)
79 self._find = functools.partial(self.find, headers=self.JSON_HEADER)
80
81 def _list(self, path, **params):
82 get_all = params.pop('get_all', False)
83 if not get_all:
84 return self.list(path, **params, headers=self.JSON_HEADER)
85
86 # Enable pagination for 'resources'
87 resource_key = params.pop('resources')
88 res = []
89 while True:
90 response = self.list(path, **params, headers=self.JSON_HEADER)
91 res.extend(response[resource_key])
92
93 links = response.get("{}_links".format(resource_key), [])
94 for link in links:
95 if link.get('rel') == 'next':
96 query_str = urlparse.urlparse(link['href']).query
97 params = urlparse.parse_qs(query_str)
98 break
99 else:
100 break
101 return {resource_key: res}
79102
80103 def _build_url(self):
81104 if not self.endpoint.endswith(self._endpoint_suffix):
91114 List of load balancers
92115 """
93116 url = const.BASE_LOADBALANCER_URL
94 response = self._list(url, **params)
117 response = self._list(url, get_all=True,
118 resources=const.LOADBALANCER_RESOURCES,
119 **params)
95120
96121 return response
97122
206231 List of listeners
207232 """
208233 url = const.BASE_LISTENER_URL
209 response = self._list(url, **kwargs)
234 response = self._list(url, get_all=True,
235 resources=const.LISTENER_RESOURCES,
236 **kwargs)
210237
211238 return response
212239
291318 List of pools
292319 """
293320 url = const.BASE_POOL_URL
294 response = self._list(url, **kwargs)
321 response = self._list(url, get_all=True,
322 resources=const.POOL_RESOURCES,
323 **kwargs)
295324
296325 return response
297326
364393 Response list members
365394 """
366395 url = const.BASE_MEMBER_URL.format(pool_id=pool_id)
367 response = self._list(url, **kwargs)
396 response = self._list(url, get_all=True,
397 resources=const.MEMBER_RESOURCES,
398 **kwargs)
368399
369400 return response
370401
448479 List of l7policies
449480 """
450481 url = const.BASE_L7POLICY_URL
451 response = self._list(url, **kwargs)
482 response = self._list(url, get_all=True,
483 resources=const.L7POLICY_RESOURCES,
484 **kwargs)
452485
453486 return response
454487
519552 List of l7rules
520553 """
521554 url = const.BASE_L7RULE_URL.format(policy_uuid=l7policy_id)
522 response = self._list(url, **kwargs)
555 response = self._list(url, get_all=True,
556 resources=const.L7RULE_RESOURCES,
557 **kwargs)
523558
524559 return response
525560
601636 A dict containing a list of health monitors
602637 """
603638 url = const.BASE_HEALTH_MONITOR_URL
604 response = self._list(url, **kwargs)
639 response = self._list(url, get_all=True,
640 resources=const.HEALTH_MONITOR_RESOURCES,
641 **kwargs)
605642
606643 return response
607644
675712 A ``dict`` representing a list of quotas for the project
676713 """
677714 url = const.BASE_QUOTA_URL
678 response = self._list(url, **params)
715 response = self._list(url, get_all=True,
716 resources=const.QUOTA_RESOURCES,
717 **params)
679718
680719 return response
681720
758797 A ``dict`` containing a list of amphorae
759798 """
760799 url = const.BASE_AMPHORA_URL
761 response = self._list(path=url, **kwargs)
800 response = self._list(path=url, get_all=True,
801 resources=const.AMPHORA_RESOURCES,
802 **kwargs)
762803
763804 return response
764805
826867 A ``dict`` containing a list of provider
827868 """
828869 url = const.BASE_PROVIDER_URL
829 response = self._list(path=url)
870 response = self._list(path=url, get_all=True,
871 resources=const.PROVIDER_RESOURCES)
830872
831873 return response
832874
841883 """
842884 url = const.BASE_PROVIDER_FLAVOR_CAPABILITY_URL.format(
843885 provider=provider)
844 response = self._list(url)
886 resources = const.PROVIDER_FLAVOR_CAPABILITY_RESOURCES
887 response = self._list(url, get_all=True,
888 resources=resources)
845889
846890 return response
847891
856900 """
857901 url = const.BASE_PROVIDER_AVAILABILITY_ZONE_CAPABILITY_URL.format(
858902 provider=provider)
859 response = self._list(url)
903 resources = const.PROVIDER_AVAILABILITY_ZONE_CAPABILITY_RESOURCES
904 response = self._list(url, get_all=True,
905 resources=resources)
860906
861907 return response
862908
870916 A ``dict`` containing a list of flavor
871917 """
872918 url = const.BASE_FLAVOR_URL
873 response = self._list(path=url, **kwargs)
919 response = self._list(path=url, get_all=True,
920 resources=const.FLAVOR_RESOURCES, **kwargs)
874921
875922 return response
876923
9551002 List of flavor profile
9561003 """
9571004 url = const.BASE_FLAVORPROFILE_URL
958 response = self._list(url, **kwargs)
1005 response = self._list(url, get_all=True,
1006 resources=const.FLAVORPROFILE_RESOURCES,
1007 **kwargs)
9591008
9601009 return response
9611010
10131062 A ``dict`` containing a list of availabilityzone
10141063 """
10151064 url = const.BASE_AVAILABILITYZONE_URL
1016 response = self._list(path=url, **kwargs)
1065 response = self._list(path=url, get_all=True,
1066 resources=const.AVAILABILITYZONE_RESOURCES,
1067 **kwargs)
10171068
10181069 return response
10191070
11021153 List of availabilityzone profile
11031154 """
11041155 url = const.BASE_AVAILABILITYZONEPROFILE_URL
1105 response = self._list(url, **kwargs)
1156 resources = const.AVAILABILITYZONEPROFILE_RESOURCES
1157 response = self._list(url, get_all=True,
1158 resources=resources,
1159 **kwargs)
11061160
11071161 return response
11081162
1515 from openstackclient.identity import common as identity_common
1616 from osc_lib import exceptions as osc_exc
1717 from osc_lib import utils
18 from oslo_utils import uuidutils
1819
1920 from octaviaclient.api import exceptions
2021 from octaviaclient.osc.v2 import constants
6162 return res
6263
6364
65 def _find_resource(list_funct, resource_name, root_tag, name, parent=None):
66 """Search for a resource by name and ID.
67
68 This function will search for a resource by both the name and ID,
69 returning the resource once it finds a match. If no match is found,
70 an exception will be raised.
71
72 :param list_funct: The resource list method to call during searches.
73 :param resource_name: The name of the resource type we are searching for.
74 :param root_tag: The root tag of the resource returned from the API.
75 :param name: The value we are searching for, a resource name or ID.
76 :param parent: The parent resource ID, when required.
77 :return: The resource found for the name or ID.
78 :raises osc_exc.CommandError: If more than one match or none are found.
79 """
80 if parent:
81 parent_args = [parent]
82 else:
83 parent_args = []
84 # Optimize the API call order if we got a UUID-like name or not
85 if uuidutils.is_uuid_like(name):
86 # Try by ID first
87 resource = list_funct(*parent_args, id=name)[root_tag]
88 if len(resource) == 1:
89 return resource[0]
90
91 # Try by name next
92 resource = list_funct(*parent_args, name=name)[root_tag]
93 if len(resource) == 1:
94 return resource[0]
95 if len(resource) > 1:
96 msg = ("{0} {1} found with name or ID of {2}. Please try "
97 "again with UUID".format(len(resource), resource_name,
98 name))
99 raise osc_exc.CommandError(msg)
100 else:
101 # Try by name first
102 resource = list_funct(*parent_args, name=name)[root_tag]
103 if len(resource) == 1:
104 return resource[0]
105 if len(resource) > 1:
106 msg = ("{0} {1} found with name or ID of {2}. Please try "
107 "again with UUID".format(len(resource), resource_name,
108 name))
109 raise osc_exc.CommandError(msg)
110
111 # Try by ID next
112 resource = list_funct(*parent_args, id=name)[root_tag]
113 if len(resource) == 1:
114 return resource[0]
115
116 # We didn't find what we were looking for, raise a consistent error.
117 msg = "Unable to locate {0} in {1}".format(name, resource_name)
118 raise osc_exc.CommandError(msg)
119
120
64121 def get_resource_id(resource, resource_name, name):
65122 """Converts a resource name into a UUID for consumption for the API
66123
93150 ).id
94151 return project_id
95152 return 'non-uuid'
153
96154 if resource_name == 'members':
97 names = [re for re in resource(name['pool_id'])['members']
98 if re.get('id') == name['member_id'] or
99 re.get('name') == name['member_id']]
100 name = name['member_id']
101 if len(names) > 1:
102 msg = ("{0} {1} found with name or ID of {2}. Please try "
103 "again with UUID".format(len(names), resource_name,
104 name))
105 raise osc_exc.CommandError(msg)
106 return names[0].get('id')
155 member = _find_resource(resource, resource_name, 'members',
156 name['member_id'], parent=name['pool_id'])
157 return member.get('id')
158
107159 if resource_name == 'l7rules':
108 names = [re for re in resource(name['l7policy_id'])['rules']
109 if re.get('id') == name['l7rule_id']]
110 name = name['l7rule_id']
111 return names[0].get('id')
112 names = [re for re in resource()[resource_name]
113 if re.get('name') == name or re.get('id') == name]
114 if len(names) > 1:
115 msg = ("{0} {1} found with name or ID of {2}. Please try "
116 "again with UUID".format(len(names), resource_name,
117 name))
118 raise osc_exc.CommandError(msg)
119 return names[0].get(primary_key)
160 l7rule = _find_resource(resource, resource_name, 'rules',
161 name['l7rule_id'],
162 parent=name['l7policy_id'])
163 return l7rule.get('id')
164
165 resource = _find_resource(resource, resource_name, resource_name, name)
166 return resource.get(primary_key)
120167
121168 except IndexError as e:
122169 msg = "Unable to locate {0} in {1}".format(name, resource_name)
6767 {'name': 'mem2'}]
6868 }
6969
70 LIST_L7PO_RESP = [
71 {'name': 'l71'},
72 {'name': 'l72'},
73 ]
70 LIST_L7PO_RESP = {
71 'l7policies':
72 [{'name': 'l71'},
73 {'name': 'l72'}]
74 }
7475
7576 LIST_L7RU_RESP = {
7677 'rules':
9393 verifylist = [
9494 ('availabilityzone', 'unknown_availabilityzone')
9595 ]
96 self.api_mock.availabilityzone_list.return_value = {
97 'availability_zones': []}
9698 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
9799 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
98100 parsed_args)
9898 verifylist = [
9999 ('availabilityzoneprofile', 'unknown_availabilityzoneprofile')
100100 ]
101 self.api_mock.availabilityzoneprofile_list.return_value = {
102 'availability_zone_profiles': []}
101103 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
102104 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
103105 parsed_args)
9191 verifylist = [
9292 ('flavor', 'unknown_flavor')
9393 ]
94 self.api_mock.flavor_list.return_value = {'flavors': []}
9495 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
9596 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
9697 parsed_args)
9393 verifylist = [
9494 ('flavorprofile', 'unknown_flavorprofile')
9595 ]
96 self.api_mock.flavorprofile_list.return_value = {
97 'flavorprofiles': []}
9698 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
9799 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
98100 parsed_args)
156156 verifylist = [
157157 ('health_monitor', 'unknown_hm')
158158 ]
159 self.api_mock.health_monitor_list.return_value = {
160 'healthmonitors': []}
159161 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
160162 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
161163 parsed_args)
172172 verifylist = [
173173 ('l7policy', 'unknown_policy')
174174 ]
175 self.api_mock.l7policy_list.return_value = {'l7policies': []}
175176 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
176177 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
177178 parsed_args)
161161 verifylist = [
162162 ('listener', 'unknown_lb')
163163 ]
164 self.api_mock.listener_list.return_value = {'listeners': []}
164165 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
165166 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
166167 parsed_args)
304304 verifylist = [
305305 ('loadbalancer', 'unknown_lb')
306306 ]
307 self.api_mock.load_balancer_list.return_value = {
308 'loadbalancers': []}
307309 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
308310 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
309311 parsed_args)
154154 verifylist = [
155155 ('pool', 'unknown_pool')
156156 ]
157 self.api_mock.pool_list.return_value = {'pools': []}
157158 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
158159 self.assertRaises(exceptions.CommandError, self.cmd.take_action,
159160 parsed_args)
0 ---
1 fixes:
2 - |
3 Improved the client performance when using a name instead of the
4 resource ID.
0 ---
1 fixes:
2 - |
3 Fixed some issues when the number of Octavia resources exceeded the
4 'pagination_max_limit' parameter in Octavia API. The list calls now support
5 pagination.
1414 VIRTUAL_ENV={envdir}
1515 PYTHONWARNINGS=default::DeprecationWarning
1616 deps =
17 -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
17 -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/wallaby}
1818 -r{toxinidir}/test-requirements.txt
1919 commands =
2020 find . -type f -name "*.pyc" -delete
5454
5555 [testenv:docs]
5656 deps =
57 -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
57 -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/wallaby}
5858 -r{toxinidir}/doc/requirements.txt
5959 commands =
6060 rm -rf doc/build/html
7272
7373 [testenv:releasenotes]
7474 deps =
75 -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
75 -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/wallaby}
7676 -r{toxinidir}/doc/requirements.txt
7777 commands =
7878 rm -rf releasenotes/build