1# Copyright 2012 OpenStack Foundation.
2# Copyright 2015 Hewlett-Packard Development Company, L.P.
3# Copyright 2017 FUJITSU LIMITED
4# All Rights Reserved
5#
6#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7#    not use this file except in compliance with the License. You may obtain
8#    a copy of the License at
9#
10#         http://www.apache.org/licenses/LICENSE-2.0
11#
12#    Unless required by applicable law or agreed to in writing, software
13#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15#    License for the specific language governing permissions and limitations
16#    under the License.
17#
18
19import inspect
20import itertools
21import logging
22import re
23import time
24import urllib.parse as urlparse
25
26import debtcollector.renames
27from keystoneauth1 import exceptions as ksa_exc
28import requests
29
30from neutronclient._i18n import _
31from neutronclient import client
32from neutronclient.common import exceptions
33from neutronclient.common import extension as client_extension
34from neutronclient.common import serializer
35from neutronclient.common import utils
36
37
38_logger = logging.getLogger(__name__)
39
40HEX_ELEM = '[0-9A-Fa-f]'
41UUID_PATTERN = '-'.join([HEX_ELEM + '{8}', HEX_ELEM + '{4}',
42                         HEX_ELEM + '{4}', HEX_ELEM + '{4}',
43                         HEX_ELEM + '{12}'])
44
45
46def exception_handler_v20(status_code, error_content):
47    """Exception handler for API v2.0 client.
48
49    This routine generates the appropriate Neutron exception according to
50    the contents of the response body.
51
52    :param status_code: HTTP error status code
53    :param error_content: deserialized body of error response
54    """
55    error_dict = None
56    request_ids = error_content.request_ids
57    if isinstance(error_content, dict):
58        error_dict = error_content.get('NeutronError')
59    # Find real error type
60    client_exc = None
61    if error_dict:
62        # If Neutron key is found, it will definitely contain
63        # a 'message' and 'type' keys?
64        try:
65            error_type = error_dict['type']
66            error_message = error_dict['message']
67            if error_dict['detail']:
68                error_message += "\n" + error_dict['detail']
69            # If corresponding exception is defined, use it.
70            client_exc = getattr(exceptions, '%sClient' % error_type, None)
71        except Exception:
72            error_message = "%s" % error_dict
73    else:
74        error_message = None
75        if isinstance(error_content, dict):
76            error_message = error_content.get('message')
77        if not error_message:
78            # If we end up here the exception was not a neutron error
79            error_message = "%s-%s" % (status_code, error_content)
80
81    # If an exception corresponding to the error type is not found,
82    # look up per status-code client exception.
83    if not client_exc:
84        client_exc = exceptions.HTTP_EXCEPTION_MAP.get(status_code)
85    # If there is no exception per status-code,
86    # Use NeutronClientException as fallback.
87    if not client_exc:
88        client_exc = exceptions.NeutronClientException
89
90    raise client_exc(message=error_message,
91                     status_code=status_code,
92                     request_ids=request_ids)
93
94
95class _RequestIdMixin(object):
96    """Wrapper class to expose x-openstack-request-id to the caller."""
97    def _request_ids_setup(self):
98        self._request_ids = []
99
100    @property
101    def request_ids(self):
102        return self._request_ids
103
104    def _append_request_ids(self, resp):
105        """Add request_ids as an attribute to the object
106
107        :param resp: Response object or list of Response objects
108        """
109        if isinstance(resp, list):
110            # Add list of request_ids if response is of type list.
111            for resp_obj in resp:
112                self._append_request_id(resp_obj)
113        elif resp is not None:
114            # Add request_ids if response contains single object.
115            self._append_request_id(resp)
116
117    def _append_request_id(self, resp):
118        if isinstance(resp, requests.Response):
119            # Extract 'x-openstack-request-id' from headers if
120            # response is a Response object.
121            request_id = resp.headers.get('x-openstack-request-id')
122        else:
123            # If resp is of type string.
124            request_id = resp
125        if request_id:
126            self._request_ids.append(request_id)
127
128
129class _DictWithMeta(dict, _RequestIdMixin):
130    def __init__(self, values, resp):
131        super(_DictWithMeta, self).__init__(values)
132        self._request_ids_setup()
133        self._append_request_ids(resp)
134
135
136class _TupleWithMeta(tuple, _RequestIdMixin):
137    def __new__(cls, values, resp):
138        return super(_TupleWithMeta, cls).__new__(cls, values)
139
140    def __init__(self, values, resp):
141        self._request_ids_setup()
142        self._append_request_ids(resp)
143
144
145class _StrWithMeta(str, _RequestIdMixin):
146    def __new__(cls, value, resp):
147        return super(_StrWithMeta, cls).__new__(cls, value)
148
149    def __init__(self, values, resp):
150        self._request_ids_setup()
151        self._append_request_ids(resp)
152
153
154class _GeneratorWithMeta(_RequestIdMixin):
155    def __init__(self, paginate_func, collection, path, **params):
156        self.paginate_func = paginate_func
157        self.collection = collection
158        self.path = path
159        self.params = params
160        self.generator = None
161        self._request_ids_setup()
162
163    def _paginate(self):
164        for r in self.paginate_func(
165                self.collection, self.path, **self.params):
166            yield r, r.request_ids
167
168    def __iter__(self):
169        return self
170
171    # Python 3 compatibility
172    def __next__(self):
173        return self.next()
174
175    def next(self):
176        if not self.generator:
177            self.generator = self._paginate()
178
179        try:
180            obj, req_id = next(self.generator)
181            self._append_request_ids(req_id)
182        except StopIteration:
183            raise StopIteration()
184
185        return obj
186
187
188class ClientBase(object):
189    """Client for the OpenStack Neutron v2.0 API.
190
191    :param string username: Username for authentication. (optional)
192    :param string user_id: User ID for authentication. (optional)
193    :param string password: Password for authentication. (optional)
194    :param string token: Token for authentication. (optional)
195    :param string tenant_name: DEPRECATED! Use project_name instead.
196    :param string project_name: Project name. (optional)
197    :param string tenant_id: DEPRECATED! Use project_id instead.
198    :param string project_id: Project id. (optional)
199    :param string auth_strategy: 'keystone' by default, 'noauth' for no
200                                 authentication against keystone. (optional)
201    :param string auth_url: Keystone service endpoint for authorization.
202    :param string service_type: Network service type to pull from the
203                                keystone catalog (e.g. 'network') (optional)
204    :param string endpoint_type: Network service endpoint type to pull from the
205                                 keystone catalog (e.g. 'publicURL',
206                                 'internalURL', or 'adminURL') (optional)
207    :param string region_name: Name of a region to select when choosing an
208                               endpoint from the service catalog.
209    :param string endpoint_url: A user-supplied endpoint URL for the neutron
210                            service.  Lazy-authentication is possible for API
211                            service calls if endpoint is set at
212                            instantiation.(optional)
213    :param integer timeout: Allows customization of the timeout for client
214                            http requests. (optional)
215    :param bool insecure: SSL certificate validation. (optional)
216    :param bool log_credentials: Allow for logging of passwords or not.
217                                 Defaults to False. (optional)
218    :param string ca_cert: SSL CA bundle file to use. (optional)
219    :param integer retries: How many times idempotent (GET, PUT, DELETE)
220                            requests to Neutron server should be retried if
221                            they fail (default: 0).
222    :param bool raise_errors: If True then exceptions caused by connection
223                              failure are propagated to the caller.
224                              (default: True)
225    :param session: Keystone client auth session to use. (optional)
226    :param auth: Keystone auth plugin to use. (optional)
227
228    Example::
229
230        from neutronclient.v2_0 import client
231        neutron = client.Client(username=USER,
232                                password=PASS,
233                                project_name=PROJECT_NAME,
234                                auth_url=KEYSTONE_URL)
235
236        nets = neutron.list_networks()
237        ...
238    """
239
240    # API has no way to report plurals, so we have to hard code them
241    # This variable should be overridden by a child class.
242    EXTED_PLURALS = {}
243
244    @debtcollector.renames.renamed_kwarg(
245        'tenant_id', 'project_id', replace=True)
246    def __init__(self, **kwargs):
247        """Initialize a new client for the Neutron v2.0 API."""
248        super(ClientBase, self).__init__()
249        self.retries = kwargs.pop('retries', 0)
250        self.raise_errors = kwargs.pop('raise_errors', True)
251        self.httpclient = client.construct_http_client(**kwargs)
252        self.version = '2.0'
253        self.action_prefix = "/v%s" % (self.version)
254        self.retry_interval = 1
255
256    def _handle_fault_response(self, status_code, response_body, resp):
257        # Create exception with HTTP status code and message
258        _logger.debug("Error message: %s", response_body)
259        # Add deserialized error message to exception arguments
260        try:
261            des_error_body = self.deserialize(response_body, status_code)
262        except Exception:
263            # If unable to deserialized body it is probably not a
264            # Neutron error
265            des_error_body = {'message': response_body}
266        error_body = self._convert_into_with_meta(des_error_body, resp)
267        # Raise the appropriate exception
268        exception_handler_v20(status_code, error_body)
269
270    def do_request(self, method, action, body=None, headers=None, params=None):
271        # Add format and project_id
272        action = self.action_prefix + action
273        if isinstance(params, dict) and params:
274            params = utils.safe_encode_dict(params)
275            action += '?' + urlparse.urlencode(params, doseq=1)
276
277        if body:
278            body = self.serialize(body)
279
280        resp, replybody = self.httpclient.do_request(action, method, body=body,
281                                                     headers=headers)
282
283        status_code = resp.status_code
284        if status_code in (requests.codes.ok,
285                           requests.codes.created,
286                           requests.codes.accepted,
287                           requests.codes.no_content):
288            data = self.deserialize(replybody, status_code)
289            return self._convert_into_with_meta(data, resp)
290        else:
291            if not replybody:
292                replybody = resp.reason
293            self._handle_fault_response(status_code, replybody, resp)
294
295    def get_auth_info(self):
296        return self.httpclient.get_auth_info()
297
298    def serialize(self, data):
299        """Serializes a dictionary into JSON.
300
301        A dictionary with a single key can be passed and it can contain any
302        structure.
303        """
304        if data is None:
305            return None
306        elif isinstance(data, dict):
307            return serializer.Serializer().serialize(data)
308        else:
309            raise Exception(_("Unable to serialize object of type = '%s'") %
310                            type(data))
311
312    def deserialize(self, data, status_code):
313        """Deserializes a JSON string into a dictionary."""
314        if not data:
315            return data
316        return serializer.Serializer().deserialize(
317            data)['body']
318
319    def retry_request(self, method, action, body=None,
320                      headers=None, params=None):
321        """Call do_request with the default retry configuration.
322
323        Only idempotent requests should retry failed connection attempts.
324        :raises: ConnectionFailed if the maximum # of retries is exceeded
325        """
326        max_attempts = self.retries + 1
327        for i in range(max_attempts):
328            try:
329                return self.do_request(method, action, body=body,
330                                       headers=headers, params=params)
331            except (exceptions.ConnectionFailed, ksa_exc.ConnectionError):
332                # Exception has already been logged by do_request()
333                if i < self.retries:
334                    _logger.debug('Retrying connection to Neutron service')
335                    time.sleep(self.retry_interval)
336                elif self.raise_errors:
337                    raise
338
339        if self.retries:
340            msg = (_("Failed to connect to Neutron server after %d attempts")
341                   % max_attempts)
342        else:
343            msg = _("Failed to connect Neutron server")
344
345        raise exceptions.ConnectionFailed(reason=msg)
346
347    def delete(self, action, body=None, headers=None, params=None):
348        return self.retry_request("DELETE", action, body=body,
349                                  headers=headers, params=params)
350
351    def get(self, action, body=None, headers=None, params=None):
352        return self.retry_request("GET", action, body=body,
353                                  headers=headers, params=params)
354
355    def post(self, action, body=None, headers=None, params=None):
356        # Do not retry POST requests to avoid the orphan objects problem.
357        return self.do_request("POST", action, body=body,
358                               headers=headers, params=params)
359
360    def put(self, action, body=None, headers=None, params=None):
361        return self.retry_request("PUT", action, body=body,
362                                  headers=headers, params=params)
363
364    def list(self, collection, path, retrieve_all=True, **params):
365        if retrieve_all:
366            res = []
367            request_ids = []
368            for r in self._pagination(collection, path, **params):
369                res.extend(r[collection])
370                request_ids.extend(r.request_ids)
371            return _DictWithMeta({collection: res}, request_ids)
372        else:
373            return _GeneratorWithMeta(self._pagination, collection,
374                                      path, **params)
375
376    def _pagination(self, collection, path, **params):
377        if params.get('page_reverse', False):
378            linkrel = 'previous'
379        else:
380            linkrel = 'next'
381        next = True
382        while next:
383            res = self.get(path, params=params)
384            yield res
385            next = False
386            try:
387                for link in res['%s_links' % collection]:
388                    if link['rel'] == linkrel:
389                        query_str = urlparse.urlparse(link['href']).query
390                        params = urlparse.parse_qs(query_str)
391                        next = True
392                        break
393            except KeyError:
394                break
395
396    def _convert_into_with_meta(self, item, resp):
397        if item:
398            if isinstance(item, dict):
399                return _DictWithMeta(item, resp)
400            elif isinstance(item, str):
401                return _StrWithMeta(item, resp)
402        else:
403            return _TupleWithMeta((), resp)
404
405    def get_resource_plural(self, resource):
406        for k in self.EXTED_PLURALS:
407            if self.EXTED_PLURALS[k] == resource:
408                return k
409        return resource + 's'
410
411    def find_resource_by_id(self, resource, resource_id, cmd_resource=None,
412                            parent_id=None, fields=None):
413        if not cmd_resource:
414            cmd_resource = resource
415        cmd_resource_plural = self.get_resource_plural(cmd_resource)
416        resource_plural = self.get_resource_plural(resource)
417        # TODO(amotoki): Use show_%s instead of list_%s
418        obj_lister = getattr(self, "list_%s" % cmd_resource_plural)
419        # perform search by id only if we are passing a valid UUID
420        match = re.match(UUID_PATTERN, resource_id)
421        collection = resource_plural
422        if match:
423            params = {'id': resource_id}
424            if fields:
425                params['fields'] = fields
426            if parent_id:
427                data = obj_lister(parent_id, **params)
428            else:
429                data = obj_lister(**params)
430            if data and data[collection]:
431                return data[collection][0]
432        not_found_message = (_("Unable to find %(resource)s with id "
433                               "'%(id)s'") %
434                             {'resource': resource, 'id': resource_id})
435        # 404 is raised by exceptions.NotFound to simulate serverside behavior
436        raise exceptions.NotFound(message=not_found_message)
437
438    def _find_resource_by_name(self, resource, name, project_id=None,
439                               cmd_resource=None, parent_id=None, fields=None):
440        if not cmd_resource:
441            cmd_resource = resource
442        cmd_resource_plural = self.get_resource_plural(cmd_resource)
443        resource_plural = self.get_resource_plural(resource)
444        obj_lister = getattr(self, "list_%s" % cmd_resource_plural)
445        params = {'name': name}
446        if fields:
447            params['fields'] = fields
448        if project_id:
449            params['tenant_id'] = project_id
450        if parent_id:
451            data = obj_lister(parent_id, **params)
452        else:
453            data = obj_lister(**params)
454        collection = resource_plural
455        info = data[collection]
456        if len(info) > 1:
457            raise exceptions.NeutronClientNoUniqueMatch(resource=resource,
458                                                        name=name)
459        elif len(info) == 0:
460            not_found_message = (_("Unable to find %(resource)s with name "
461                                   "'%(name)s'") %
462                                 {'resource': resource, 'name': name})
463            # 404 is raised by exceptions.NotFound
464            # to simulate serverside behavior
465            raise exceptions.NotFound(message=not_found_message)
466        else:
467            return info[0]
468
469    def find_resource(self, resource, name_or_id, project_id=None,
470                      cmd_resource=None, parent_id=None, fields=None):
471        try:
472            return self.find_resource_by_id(resource, name_or_id,
473                                            cmd_resource, parent_id, fields)
474        except exceptions.NotFound:
475            try:
476                return self._find_resource_by_name(
477                    resource, name_or_id, project_id,
478                    cmd_resource, parent_id, fields)
479            except exceptions.NotFound:
480                not_found_message = (_("Unable to find %(resource)s with name "
481                                       "or id '%(name_or_id)s'") %
482                                     {'resource': resource,
483                                      'name_or_id': name_or_id})
484                raise exceptions.NotFound(
485                    message=not_found_message)
486
487
488class Client(ClientBase):
489
490    networks_path = "/networks"
491    network_path = "/networks/%s"
492    ports_path = "/ports"
493    port_path = "/ports/%s"
494    port_bindings_path = "/ports/%s/bindings"
495    port_binding_path = "/ports/%s/bindings/%s"
496    port_binding_path_activate = "/ports/%s/bindings/%s/activate"
497    subnets_path = "/subnets"
498    subnet_path = "/subnets/%s"
499    onboard_network_subnets_path = "/subnetpools/%s/onboard_network_subnets"
500    subnetpools_path = "/subnetpools"
501    subnetpool_path = "/subnetpools/%s"
502    address_scopes_path = "/address-scopes"
503    address_scope_path = "/address-scopes/%s"
504    quotas_path = "/quotas"
505    quota_path = "/quotas/%s"
506    quota_default_path = "/quotas/%s/default"
507    quota_details_path = "/quotas/%s/details.json"
508    extensions_path = "/extensions"
509    extension_path = "/extensions/%s"
510    routers_path = "/routers"
511    router_path = "/routers/%s"
512    floatingips_path = "/floatingips"
513    floatingip_path = "/floatingips/%s"
514    security_groups_path = "/security-groups"
515    security_group_path = "/security-groups/%s"
516    security_group_rules_path = "/security-group-rules"
517    security_group_rule_path = "/security-group-rules/%s"
518    segments_path = "/segments"
519    segment_path = "/segments/%s"
520
521    sfc_flow_classifiers_path = "/sfc/flow_classifiers"
522    sfc_flow_classifier_path = "/sfc/flow_classifiers/%s"
523    sfc_port_pairs_path = "/sfc/port_pairs"
524    sfc_port_pair_path = "/sfc/port_pairs/%s"
525    sfc_port_pair_groups_path = "/sfc/port_pair_groups"
526    sfc_port_pair_group_path = "/sfc/port_pair_groups/%s"
527    sfc_port_chains_path = "/sfc/port_chains"
528    sfc_port_chain_path = "/sfc/port_chains/%s"
529    sfc_service_graphs_path = "/sfc/service_graphs"
530    sfc_service_graph_path = "/sfc/service_graphs/%s"
531
532    endpoint_groups_path = "/vpn/endpoint-groups"
533    endpoint_group_path = "/vpn/endpoint-groups/%s"
534    vpnservices_path = "/vpn/vpnservices"
535    vpnservice_path = "/vpn/vpnservices/%s"
536    ipsecpolicies_path = "/vpn/ipsecpolicies"
537    ipsecpolicy_path = "/vpn/ipsecpolicies/%s"
538    ikepolicies_path = "/vpn/ikepolicies"
539    ikepolicy_path = "/vpn/ikepolicies/%s"
540    ipsec_site_connections_path = "/vpn/ipsec-site-connections"
541    ipsec_site_connection_path = "/vpn/ipsec-site-connections/%s"
542
543    lbaas_loadbalancers_path = "/lbaas/loadbalancers"
544    lbaas_loadbalancer_path = "/lbaas/loadbalancers/%s"
545    lbaas_loadbalancer_path_stats = "/lbaas/loadbalancers/%s/stats"
546    lbaas_loadbalancer_path_status = "/lbaas/loadbalancers/%s/statuses"
547    lbaas_listeners_path = "/lbaas/listeners"
548    lbaas_listener_path = "/lbaas/listeners/%s"
549    lbaas_l7policies_path = "/lbaas/l7policies"
550    lbaas_l7policy_path = lbaas_l7policies_path + "/%s"
551    lbaas_l7rules_path = lbaas_l7policy_path + "/rules"
552    lbaas_l7rule_path = lbaas_l7rules_path + "/%s"
553    lbaas_pools_path = "/lbaas/pools"
554    lbaas_pool_path = "/lbaas/pools/%s"
555    lbaas_healthmonitors_path = "/lbaas/healthmonitors"
556    lbaas_healthmonitor_path = "/lbaas/healthmonitors/%s"
557    lbaas_members_path = lbaas_pool_path + "/members"
558    lbaas_member_path = lbaas_pool_path + "/members/%s"
559
560    vips_path = "/lb/vips"
561    vip_path = "/lb/vips/%s"
562    pools_path = "/lb/pools"
563    pool_path = "/lb/pools/%s"
564    pool_path_stats = "/lb/pools/%s/stats"
565    members_path = "/lb/members"
566    member_path = "/lb/members/%s"
567    health_monitors_path = "/lb/health_monitors"
568    health_monitor_path = "/lb/health_monitors/%s"
569    associate_pool_health_monitors_path = "/lb/pools/%s/health_monitors"
570    disassociate_pool_health_monitors_path = (
571        "/lb/pools/%(pool)s/health_monitors/%(health_monitor)s")
572    qos_queues_path = "/qos-queues"
573    qos_queue_path = "/qos-queues/%s"
574    agents_path = "/agents"
575    agent_path = "/agents/%s"
576    network_gateways_path = "/network-gateways"
577    network_gateway_path = "/network-gateways/%s"
578    gateway_devices_path = "/gateway-devices"
579    gateway_device_path = "/gateway-devices/%s"
580    service_providers_path = "/service-providers"
581    metering_labels_path = "/metering/metering-labels"
582    metering_label_path = "/metering/metering-labels/%s"
583    metering_label_rules_path = "/metering/metering-label-rules"
584    metering_label_rule_path = "/metering/metering-label-rules/%s"
585
586    DHCP_NETS = '/dhcp-networks'
587    DHCP_AGENTS = '/dhcp-agents'
588    L3_ROUTERS = '/l3-routers'
589    L3_AGENTS = '/l3-agents'
590    LOADBALANCER_POOLS = '/loadbalancer-pools'
591    LOADBALANCER_AGENT = '/loadbalancer-agent'
592    AGENT_LOADBALANCERS = '/agent-loadbalancers'
593    LOADBALANCER_HOSTING_AGENT = '/loadbalancer-hosting-agent'
594    firewall_rules_path = "/fw/firewall_rules"
595    firewall_rule_path = "/fw/firewall_rules/%s"
596    firewall_policies_path = "/fw/firewall_policies"
597    firewall_policy_path = "/fw/firewall_policies/%s"
598    firewall_policy_insert_path = "/fw/firewall_policies/%s/insert_rule"
599    firewall_policy_remove_path = "/fw/firewall_policies/%s/remove_rule"
600    firewalls_path = "/fw/firewalls"
601    firewall_path = "/fw/firewalls/%s"
602    fwaas_firewall_groups_path = "/fwaas/firewall_groups"
603    fwaas_firewall_group_path = "/fwaas/firewall_groups/%s"
604    fwaas_firewall_rules_path = "/fwaas/firewall_rules"
605    fwaas_firewall_rule_path = "/fwaas/firewall_rules/%s"
606    fwaas_firewall_policies_path = "/fwaas/firewall_policies"
607    fwaas_firewall_policy_path = "/fwaas/firewall_policies/%s"
608    fwaas_firewall_policy_insert_path = \
609        "/fwaas/firewall_policies/%s/insert_rule"
610    fwaas_firewall_policy_remove_path = \
611        "/fwaas/firewall_policies/%s/remove_rule"
612    rbac_policies_path = "/rbac-policies"
613    rbac_policy_path = "/rbac-policies/%s"
614    qos_policies_path = "/qos/policies"
615    qos_policy_path = "/qos/policies/%s"
616    qos_bandwidth_limit_rules_path = "/qos/policies/%s/bandwidth_limit_rules"
617    qos_bandwidth_limit_rule_path = "/qos/policies/%s/bandwidth_limit_rules/%s"
618    qos_dscp_marking_rules_path = "/qos/policies/%s/dscp_marking_rules"
619    qos_dscp_marking_rule_path = "/qos/policies/%s/dscp_marking_rules/%s"
620    qos_minimum_bandwidth_rules_path = \
621        "/qos/policies/%s/minimum_bandwidth_rules"
622    qos_minimum_bandwidth_rule_path = \
623        "/qos/policies/%s/minimum_bandwidth_rules/%s"
624    qos_rule_types_path = "/qos/rule-types"
625    qos_rule_type_path = "/qos/rule-types/%s"
626    flavors_path = "/flavors"
627    flavor_path = "/flavors/%s"
628    service_profiles_path = "/service_profiles"
629    service_profile_path = "/service_profiles/%s"
630    flavor_profile_bindings_path = flavor_path + service_profiles_path
631    flavor_profile_binding_path = flavor_path + service_profile_path
632    availability_zones_path = "/availability_zones"
633    auto_allocated_topology_path = "/auto-allocated-topology/%s"
634    BGP_DRINSTANCES = "/bgp-drinstances"
635    BGP_DRINSTANCE = "/bgp-drinstance/%s"
636    BGP_DRAGENTS = "/bgp-dragents"
637    BGP_DRAGENT = "/bgp-dragents/%s"
638    bgp_speakers_path = "/bgp-speakers"
639    bgp_speaker_path = "/bgp-speakers/%s"
640    bgp_peers_path = "/bgp-peers"
641    bgp_peer_path = "/bgp-peers/%s"
642    network_ip_availabilities_path = '/network-ip-availabilities'
643    network_ip_availability_path = '/network-ip-availabilities/%s'
644    tags_path = "/%s/%s/tags"
645    tag_path = "/%s/%s/tags/%s"
646    trunks_path = "/trunks"
647    trunk_path = "/trunks/%s"
648    subports_path = "/trunks/%s/get_subports"
649    subports_add_path = "/trunks/%s/add_subports"
650    subports_remove_path = "/trunks/%s/remove_subports"
651    bgpvpns_path = "/bgpvpn/bgpvpns"
652    bgpvpn_path = "/bgpvpn/bgpvpns/%s"
653    bgpvpn_network_associations_path =\
654        "/bgpvpn/bgpvpns/%s/network_associations"
655    bgpvpn_network_association_path =\
656        "/bgpvpn/bgpvpns/%s/network_associations/%s"
657    bgpvpn_router_associations_path = "/bgpvpn/bgpvpns/%s/router_associations"
658    bgpvpn_router_association_path =\
659        "/bgpvpn/bgpvpns/%s/router_associations/%s"
660    bgpvpn_port_associations_path = "/bgpvpn/bgpvpns/%s/port_associations"
661    bgpvpn_port_association_path = "/bgpvpn/bgpvpns/%s/port_associations/%s"
662    network_logs_path = "/log/logs"
663    network_log_path = "/log/logs/%s"
664    network_loggables_path = "/log/loggable-resources"
665
666    # API has no way to report plurals, so we have to hard code them
667    EXTED_PLURALS = {'routers': 'router',
668                     'floatingips': 'floatingip',
669                     'service_types': 'service_type',
670                     'service_definitions': 'service_definition',
671                     'security_groups': 'security_group',
672                     'security_group_rules': 'security_group_rule',
673                     'segments': 'segment',
674                     'ipsecpolicies': 'ipsecpolicy',
675                     'ikepolicies': 'ikepolicy',
676                     'ipsec_site_connections': 'ipsec_site_connection',
677                     'vpnservices': 'vpnservice',
678                     'endpoint_groups': 'endpoint_group',
679                     'vips': 'vip',
680                     'pools': 'pool',
681                     'members': 'member',
682                     'health_monitors': 'health_monitor',
683                     'quotas': 'quota',
684                     'service_providers': 'service_provider',
685                     'firewall_rules': 'firewall_rule',
686                     'firewall_policies': 'firewall_policy',
687                     'firewalls': 'firewall',
688                     'fwaas_firewall_rules': 'fwaas_firewall_rule',
689                     'fwaas_firewall_policies': 'fwaas_firewall_policy',
690                     'fwaas_firewall_groups': 'fwaas_firewall_group',
691                     'metering_labels': 'metering_label',
692                     'metering_label_rules': 'metering_label_rule',
693                     'loadbalancers': 'loadbalancer',
694                     'listeners': 'listener',
695                     'l7rules': 'l7rule',
696                     'l7policies': 'l7policy',
697                     'lbaas_l7policies': 'lbaas_l7policy',
698                     'lbaas_pools': 'lbaas_pool',
699                     'lbaas_healthmonitors': 'lbaas_healthmonitor',
700                     'lbaas_members': 'lbaas_member',
701                     'healthmonitors': 'healthmonitor',
702                     'rbac_policies': 'rbac_policy',
703                     'address_scopes': 'address_scope',
704                     'qos_policies': 'qos_policy',
705                     'policies': 'policy',
706                     'bandwidth_limit_rules': 'bandwidth_limit_rule',
707                     'minimum_bandwidth_rules': 'minimum_bandwidth_rule',
708                     'rules': 'rule',
709                     'dscp_marking_rules': 'dscp_marking_rule',
710                     'rule_types': 'rule_type',
711                     'flavors': 'flavor',
712                     'bgp_speakers': 'bgp_speaker',
713                     'bgp_peers': 'bgp_peer',
714                     'network_ip_availabilities': 'network_ip_availability',
715                     'trunks': 'trunk',
716                     'bgpvpns': 'bgpvpn',
717                     'network_associations': 'network_association',
718                     'router_associations': 'router_association',
719                     'port_associations': 'port_association',
720                     'flow_classifiers': 'flow_classifier',
721                     'port_pairs': 'port_pair',
722                     'port_pair_groups': 'port_pair_group',
723                     'port_chains': 'port_chain',
724                     'service_graphs': 'service_graph',
725                     'logs': 'log',
726                     'loggable_resources': 'loggable_resource',
727                     }
728
729    def list_ext(self, collection, path, retrieve_all, **_params):
730        """Client extension hook for list."""
731        return self.list(collection, path, retrieve_all, **_params)
732
733    def show_ext(self, path, id, **_params):
734        """Client extension hook for show."""
735        return self.get(path % id, params=_params)
736
737    def create_ext(self, path, body=None):
738        """Client extension hook for create."""
739        return self.post(path, body=body)
740
741    def update_ext(self, path, id, body=None):
742        """Client extension hook for update."""
743        return self.put(path % id, body=body)
744
745    def delete_ext(self, path, id):
746        """Client extension hook for delete."""
747        return self.delete(path % id)
748
749    def get_quotas_tenant(self, **_params):
750        """Fetch project info for following quota operation."""
751        return self.get(self.quota_path % 'tenant', params=_params)
752
753    def list_quotas(self, **_params):
754        """Fetch all projects' quotas."""
755        return self.get(self.quotas_path, params=_params)
756
757    @debtcollector.renames.renamed_kwarg(
758        'tenant_id', 'project_id', replace=True)
759    def show_quota(self, project_id, **_params):
760        """Fetch information of a certain project's quotas."""
761        return self.get(self.quota_path % (project_id), params=_params)
762
763    @debtcollector.renames.renamed_kwarg(
764        'tenant_id', 'project_id', replace=True)
765    def show_quota_details(self, project_id, **_params):
766        """Fetch information of a certain project's quota details."""
767        return self.get(self.quota_details_path % (project_id),
768                        params=_params)
769
770    @debtcollector.renames.renamed_kwarg(
771        'tenant_id', 'project_id', replace=True)
772    def show_quota_default(self, project_id, **_params):
773        """Fetch information of a certain project's default quotas."""
774        return self.get(self.quota_default_path % (project_id), params=_params)
775
776    @debtcollector.renames.renamed_kwarg(
777        'tenant_id', 'project_id', replace=True)
778    def update_quota(self, project_id, body=None):
779        """Update a project's quotas."""
780        return self.put(self.quota_path % (project_id), body=body)
781
782    @debtcollector.renames.renamed_kwarg(
783        'tenant_id', 'project_id', replace=True)
784    def delete_quota(self, project_id):
785        """Delete the specified project's quota values."""
786        return self.delete(self.quota_path % (project_id))
787
788    def list_extensions(self, **_params):
789        """Fetch a list of all extensions on server side."""
790        return self.get(self.extensions_path, params=_params)
791
792    def show_extension(self, ext_alias, **_params):
793        """Fetches information of a certain extension."""
794        return self.get(self.extension_path % ext_alias, params=_params)
795
796    def list_ports(self, retrieve_all=True, **_params):
797        """Fetches a list of all ports for a project."""
798        # Pass filters in "params" argument to do_request
799        return self.list('ports', self.ports_path, retrieve_all,
800                         **_params)
801
802    def show_port(self, port, **_params):
803        """Fetches information of a certain port."""
804        return self.get(self.port_path % (port), params=_params)
805
806    def create_port(self, body=None):
807        """Creates a new port."""
808        return self.post(self.ports_path, body=body)
809
810    def update_port(self, port, body=None, revision_number=None):
811        """Updates a port."""
812        return self._update_resource(self.port_path % (port), body=body,
813                                     revision_number=revision_number)
814
815    def delete_port(self, port):
816        """Deletes the specified port."""
817        return self.delete(self.port_path % (port))
818
819    def create_port_binding(self, port_id, body=None):
820        """Creates a new port binding."""
821        return self.post(self.port_bindings_path % port_id, body=body)
822
823    def delete_port_binding(self, port_id, host_id):
824        """Deletes the specified port binding."""
825        return self.delete(self.port_binding_path % (port_id, host_id))
826
827    def show_port_binding(self, port_id, host_id, **_params):
828        """Fetches information for a certain port binding."""
829        return self.get(self.port_binding_path % (port_id, host_id),
830                        params=_params)
831
832    def list_port_bindings(self, port_id, retrieve_all=True, **_params):
833        """Fetches a list of all bindings for a certain port."""
834        return self.list('port_bindings', self.port_bindings_path % port_id,
835                         retrieve_all, **_params)
836
837    def activate_port_binding(self, port_id, host_id):
838        """Activates a port binding."""
839        return self.put(self.port_binding_path_activate % (port_id, host_id))
840
841    def list_networks(self, retrieve_all=True, **_params):
842        """Fetches a list of all networks for a project."""
843        # Pass filters in "params" argument to do_request
844        return self.list('networks', self.networks_path, retrieve_all,
845                         **_params)
846
847    def show_network(self, network, **_params):
848        """Fetches information of a certain network."""
849        return self.get(self.network_path % (network), params=_params)
850
851    def create_network(self, body=None):
852        """Creates a new network."""
853        return self.post(self.networks_path, body=body)
854
855    def update_network(self, network, body=None, revision_number=None):
856        """Updates a network."""
857        return self._update_resource(self.network_path % (network), body=body,
858                                     revision_number=revision_number)
859
860    def delete_network(self, network):
861        """Deletes the specified network."""
862        return self.delete(self.network_path % (network))
863
864    def list_subnets(self, retrieve_all=True, **_params):
865        """Fetches a list of all subnets for a project."""
866        return self.list('subnets', self.subnets_path, retrieve_all,
867                         **_params)
868
869    def show_subnet(self, subnet, **_params):
870        """Fetches information of a certain subnet."""
871        return self.get(self.subnet_path % (subnet), params=_params)
872
873    def create_subnet(self, body=None):
874        """Creates a new subnet."""
875        return self.post(self.subnets_path, body=body)
876
877    def update_subnet(self, subnet, body=None, revision_number=None):
878        """Updates a subnet."""
879        return self._update_resource(self.subnet_path % (subnet), body=body,
880                                     revision_number=revision_number)
881
882    def delete_subnet(self, subnet):
883        """Deletes the specified subnet."""
884        return self.delete(self.subnet_path % (subnet))
885
886    def list_subnetpools(self, retrieve_all=True, **_params):
887        """Fetches a list of all subnetpools for a project."""
888        return self.list('subnetpools', self.subnetpools_path, retrieve_all,
889                         **_params)
890
891    def show_subnetpool(self, subnetpool, **_params):
892        """Fetches information of a certain subnetpool."""
893        return self.get(self.subnetpool_path % (subnetpool), params=_params)
894
895    def create_subnetpool(self, body=None):
896        """Creates a new subnetpool."""
897        return self.post(self.subnetpools_path, body=body)
898
899    def update_subnetpool(self, subnetpool, body=None, revision_number=None):
900        """Updates a subnetpool."""
901        return self._update_resource(self.subnetpool_path % (subnetpool),
902                                     body=body,
903                                     revision_number=revision_number)
904
905    def delete_subnetpool(self, subnetpool):
906        """Deletes the specified subnetpool."""
907        return self.delete(self.subnetpool_path % (subnetpool))
908
909    def list_routers(self, retrieve_all=True, **_params):
910        """Fetches a list of all routers for a project."""
911        # Pass filters in "params" argument to do_request
912        return self.list('routers', self.routers_path, retrieve_all,
913                         **_params)
914
915    def show_router(self, router, **_params):
916        """Fetches information of a certain router."""
917        return self.get(self.router_path % (router), params=_params)
918
919    def create_router(self, body=None):
920        """Creates a new router."""
921        return self.post(self.routers_path, body=body)
922
923    def update_router(self, router, body=None, revision_number=None):
924        """Updates a router."""
925        return self._update_resource(self.router_path % (router), body=body,
926                                     revision_number=revision_number)
927
928    def delete_router(self, router):
929        """Deletes the specified router."""
930        return self.delete(self.router_path % (router))
931
932    def list_address_scopes(self, retrieve_all=True, **_params):
933        """Fetches a list of all address scopes for a project."""
934        return self.list('address_scopes', self.address_scopes_path,
935                         retrieve_all, **_params)
936
937    def show_address_scope(self, address_scope, **_params):
938        """Fetches information of a certain address scope."""
939        return self.get(self.address_scope_path % (address_scope),
940                        params=_params)
941
942    def create_address_scope(self, body=None):
943        """Creates a new address scope."""
944        return self.post(self.address_scopes_path, body=body)
945
946    def update_address_scope(self, address_scope, body=None):
947        """Updates a address scope."""
948        return self.put(self.address_scope_path % (address_scope), body=body)
949
950    def delete_address_scope(self, address_scope):
951        """Deletes the specified address scope."""
952        return self.delete(self.address_scope_path % (address_scope))
953
954    def add_interface_router(self, router, body=None):
955        """Adds an internal network interface to the specified router."""
956        return self.put((self.router_path % router) + "/add_router_interface",
957                        body=body)
958
959    def remove_interface_router(self, router, body=None):
960        """Removes an internal network interface from the specified router."""
961        return self.put((self.router_path % router) +
962                        "/remove_router_interface", body=body)
963
964    def add_extra_routes_to_router(self, router, body=None):
965        """Adds extra routes to the specified router."""
966        return self.put((self.router_path % router) + "/add_extraroutes",
967                        body=body)
968
969    def remove_extra_routes_from_router(self, router, body=None):
970        """Removes extra routes from the specified router."""
971        return self.put((self.router_path % router) + "/remove_extraroutes",
972                        body=body)
973
974    def add_gateway_router(self, router, body=None):
975        """Adds an external network gateway to the specified router."""
976        return self.put((self.router_path % router),
977                        body={'router': {'external_gateway_info': body}})
978
979    def remove_gateway_router(self, router):
980        """Removes an external network gateway from the specified router."""
981        return self.put((self.router_path % router),
982                        body={'router': {'external_gateway_info': {}}})
983
984    def list_floatingips(self, retrieve_all=True, **_params):
985        """Fetches a list of all floatingips for a project."""
986        # Pass filters in "params" argument to do_request
987        return self.list('floatingips', self.floatingips_path, retrieve_all,
988                         **_params)
989
990    def show_floatingip(self, floatingip, **_params):
991        """Fetches information of a certain floatingip."""
992        return self.get(self.floatingip_path % (floatingip), params=_params)
993
994    def create_floatingip(self, body=None):
995        """Creates a new floatingip."""
996        return self.post(self.floatingips_path, body=body)
997
998    def update_floatingip(self, floatingip, body=None, revision_number=None):
999        """Updates a floatingip."""
1000        return self._update_resource(self.floatingip_path % (floatingip),
1001                                     body=body,
1002                                     revision_number=revision_number)
1003
1004    def delete_floatingip(self, floatingip):
1005        """Deletes the specified floatingip."""
1006        return self.delete(self.floatingip_path % (floatingip))
1007
1008    def create_security_group(self, body=None):
1009        """Creates a new security group."""
1010        return self.post(self.security_groups_path, body=body)
1011
1012    def update_security_group(self, security_group, body=None,
1013                              revision_number=None):
1014        """Updates a security group."""
1015        return self._update_resource(self.security_group_path %
1016                                     security_group, body=body,
1017                                     revision_number=revision_number)
1018
1019    def list_security_groups(self, retrieve_all=True, **_params):
1020        """Fetches a list of all security groups for a project."""
1021        return self.list('security_groups', self.security_groups_path,
1022                         retrieve_all, **_params)
1023
1024    def show_security_group(self, security_group, **_params):
1025        """Fetches information of a certain security group."""
1026        return self.get(self.security_group_path % (security_group),
1027                        params=_params)
1028
1029    def delete_security_group(self, security_group):
1030        """Deletes the specified security group."""
1031        return self.delete(self.security_group_path % (security_group))
1032
1033    def create_security_group_rule(self, body=None):
1034        """Creates a new security group rule."""
1035        return self.post(self.security_group_rules_path, body=body)
1036
1037    def delete_security_group_rule(self, security_group_rule):
1038        """Deletes the specified security group rule."""
1039        return self.delete(self.security_group_rule_path %
1040                           (security_group_rule))
1041
1042    def list_security_group_rules(self, retrieve_all=True, **_params):
1043        """Fetches a list of all security group rules for a project."""
1044        return self.list('security_group_rules',
1045                         self.security_group_rules_path,
1046                         retrieve_all, **_params)
1047
1048    def show_security_group_rule(self, security_group_rule, **_params):
1049        """Fetches information of a certain security group rule."""
1050        return self.get(self.security_group_rule_path % (security_group_rule),
1051                        params=_params)
1052
1053    def create_segment(self, body=None):
1054        """Creates a new segment."""
1055        return self.post(self.segments_path, body=body)
1056
1057    def update_segment(self, segment, body=None, revision_number=None):
1058        """Updates a segment."""
1059        return self._update_resource(self.segment_path % segment, body=body,
1060                                     revision_number=revision_number)
1061
1062    def list_segments(self, retrieve_all=True, **_params):
1063        """Fetches a list of all segments for a project."""
1064        return self.list('segments', self.segments_path, retrieve_all,
1065                         **_params)
1066
1067    def show_segment(self, segment, **_params):
1068        """Fetches information of a certain segment."""
1069        return self.get(self.segment_path % segment, params=_params)
1070
1071    def delete_segment(self, segment):
1072        """Deletes the specified segment."""
1073        return self.delete(self.segment_path % segment)
1074
1075    def list_endpoint_groups(self, retrieve_all=True, **_params):
1076        """Fetches a list of all VPN endpoint groups for a project."""
1077        return self.list('endpoint_groups', self.endpoint_groups_path,
1078                         retrieve_all, **_params)
1079
1080    def show_endpoint_group(self, endpointgroup, **_params):
1081        """Fetches information for a specific VPN endpoint group."""
1082        return self.get(self.endpoint_group_path % endpointgroup,
1083                        params=_params)
1084
1085    def create_endpoint_group(self, body=None):
1086        """Creates a new VPN endpoint group."""
1087        return self.post(self.endpoint_groups_path, body=body)
1088
1089    def update_endpoint_group(self, endpoint_group, body=None):
1090        """Updates a VPN endpoint group."""
1091        return self.put(self.endpoint_group_path % endpoint_group, body=body)
1092
1093    def delete_endpoint_group(self, endpoint_group):
1094        """Deletes the specified VPN endpoint group."""
1095        return self.delete(self.endpoint_group_path % endpoint_group)
1096
1097    def list_vpnservices(self, retrieve_all=True, **_params):
1098        """Fetches a list of all configured VPN services for a project."""
1099        return self.list('vpnservices', self.vpnservices_path, retrieve_all,
1100                         **_params)
1101
1102    def show_vpnservice(self, vpnservice, **_params):
1103        """Fetches information of a specific VPN service."""
1104        return self.get(self.vpnservice_path % (vpnservice), params=_params)
1105
1106    def create_vpnservice(self, body=None):
1107        """Creates a new VPN service."""
1108        return self.post(self.vpnservices_path, body=body)
1109
1110    def update_vpnservice(self, vpnservice, body=None):
1111        """Updates a VPN service."""
1112        return self.put(self.vpnservice_path % (vpnservice), body=body)
1113
1114    def delete_vpnservice(self, vpnservice):
1115        """Deletes the specified VPN service."""
1116        return self.delete(self.vpnservice_path % (vpnservice))
1117
1118    def list_ipsec_site_connections(self, retrieve_all=True, **_params):
1119        """Fetches all configured IPsecSiteConnections for a project."""
1120        return self.list('ipsec_site_connections',
1121                         self.ipsec_site_connections_path,
1122                         retrieve_all,
1123                         **_params)
1124
1125    def show_ipsec_site_connection(self, ipsecsite_conn, **_params):
1126        """Fetches information of a specific IPsecSiteConnection."""
1127        return self.get(
1128            self.ipsec_site_connection_path % (ipsecsite_conn), params=_params
1129        )
1130
1131    def create_ipsec_site_connection(self, body=None):
1132        """Creates a new IPsecSiteConnection."""
1133        return self.post(self.ipsec_site_connections_path, body=body)
1134
1135    def update_ipsec_site_connection(self, ipsecsite_conn, body=None):
1136        """Updates an IPsecSiteConnection."""
1137        return self.put(
1138            self.ipsec_site_connection_path % (ipsecsite_conn), body=body
1139        )
1140
1141    def delete_ipsec_site_connection(self, ipsecsite_conn):
1142        """Deletes the specified IPsecSiteConnection."""
1143        return self.delete(self.ipsec_site_connection_path % (ipsecsite_conn))
1144
1145    def list_ikepolicies(self, retrieve_all=True, **_params):
1146        """Fetches a list of all configured IKEPolicies for a project."""
1147        return self.list('ikepolicies', self.ikepolicies_path, retrieve_all,
1148                         **_params)
1149
1150    def show_ikepolicy(self, ikepolicy, **_params):
1151        """Fetches information of a specific IKEPolicy."""
1152        return self.get(self.ikepolicy_path % (ikepolicy), params=_params)
1153
1154    def create_ikepolicy(self, body=None):
1155        """Creates a new IKEPolicy."""
1156        return self.post(self.ikepolicies_path, body=body)
1157
1158    def update_ikepolicy(self, ikepolicy, body=None):
1159        """Updates an IKEPolicy."""
1160        return self.put(self.ikepolicy_path % (ikepolicy), body=body)
1161
1162    def delete_ikepolicy(self, ikepolicy):
1163        """Deletes the specified IKEPolicy."""
1164        return self.delete(self.ikepolicy_path % (ikepolicy))
1165
1166    def list_ipsecpolicies(self, retrieve_all=True, **_params):
1167        """Fetches a list of all configured IPsecPolicies for a project."""
1168        return self.list('ipsecpolicies',
1169                         self.ipsecpolicies_path,
1170                         retrieve_all,
1171                         **_params)
1172
1173    def show_ipsecpolicy(self, ipsecpolicy, **_params):
1174        """Fetches information of a specific IPsecPolicy."""
1175        return self.get(self.ipsecpolicy_path % (ipsecpolicy), params=_params)
1176
1177    def create_ipsecpolicy(self, body=None):
1178        """Creates a new IPsecPolicy."""
1179        return self.post(self.ipsecpolicies_path, body=body)
1180
1181    def update_ipsecpolicy(self, ipsecpolicy, body=None):
1182        """Updates an IPsecPolicy."""
1183        return self.put(self.ipsecpolicy_path % (ipsecpolicy), body=body)
1184
1185    def delete_ipsecpolicy(self, ipsecpolicy):
1186        """Deletes the specified IPsecPolicy."""
1187        return self.delete(self.ipsecpolicy_path % (ipsecpolicy))
1188
1189    def list_loadbalancers(self, retrieve_all=True, **_params):
1190        """Fetches a list of all loadbalancers for a project."""
1191        return self.list('loadbalancers', self.lbaas_loadbalancers_path,
1192                         retrieve_all, **_params)
1193
1194    def show_loadbalancer(self, lbaas_loadbalancer, **_params):
1195        """Fetches information for a load balancer."""
1196        return self.get(self.lbaas_loadbalancer_path % (lbaas_loadbalancer),
1197                        params=_params)
1198
1199    def create_loadbalancer(self, body=None):
1200        """Creates a new load balancer."""
1201        return self.post(self.lbaas_loadbalancers_path, body=body)
1202
1203    def update_loadbalancer(self, lbaas_loadbalancer, body=None):
1204        """Updates a load balancer."""
1205        return self.put(self.lbaas_loadbalancer_path % (lbaas_loadbalancer),
1206                        body=body)
1207
1208    def delete_loadbalancer(self, lbaas_loadbalancer):
1209        """Deletes the specified load balancer."""
1210        return self.delete(self.lbaas_loadbalancer_path %
1211                           (lbaas_loadbalancer))
1212
1213    def retrieve_loadbalancer_stats(self, loadbalancer, **_params):
1214        """Retrieves stats for a certain load balancer."""
1215        return self.get(self.lbaas_loadbalancer_path_stats % (loadbalancer),
1216                        params=_params)
1217
1218    def retrieve_loadbalancer_status(self, loadbalancer, **_params):
1219        """Retrieves status for a certain load balancer."""
1220        return self.get(self.lbaas_loadbalancer_path_status % (loadbalancer),
1221                        params=_params)
1222
1223    def list_listeners(self, retrieve_all=True, **_params):
1224        """Fetches a list of all lbaas_listeners for a project."""
1225        return self.list('listeners', self.lbaas_listeners_path,
1226                         retrieve_all, **_params)
1227
1228    def show_listener(self, lbaas_listener, **_params):
1229        """Fetches information for a lbaas_listener."""
1230        return self.get(self.lbaas_listener_path % (lbaas_listener),
1231                        params=_params)
1232
1233    def create_listener(self, body=None):
1234        """Creates a new lbaas_listener."""
1235        return self.post(self.lbaas_listeners_path, body=body)
1236
1237    def update_listener(self, lbaas_listener, body=None):
1238        """Updates a lbaas_listener."""
1239        return self.put(self.lbaas_listener_path % (lbaas_listener),
1240                        body=body)
1241
1242    def delete_listener(self, lbaas_listener):
1243        """Deletes the specified lbaas_listener."""
1244        return self.delete(self.lbaas_listener_path % (lbaas_listener))
1245
1246    def list_lbaas_l7policies(self, retrieve_all=True, **_params):
1247        """Fetches a list of all L7 policies for a listener."""
1248        return self.list('l7policies', self.lbaas_l7policies_path,
1249                         retrieve_all, **_params)
1250
1251    def show_lbaas_l7policy(self, l7policy, **_params):
1252        """Fetches information of a certain listener's L7 policy."""
1253        return self.get(self.lbaas_l7policy_path % l7policy,
1254                        params=_params)
1255
1256    def create_lbaas_l7policy(self, body=None):
1257        """Creates L7 policy for a certain listener."""
1258        return self.post(self.lbaas_l7policies_path, body=body)
1259
1260    def update_lbaas_l7policy(self, l7policy, body=None):
1261        """Updates L7 policy."""
1262        return self.put(self.lbaas_l7policy_path % l7policy,
1263                        body=body)
1264
1265    def delete_lbaas_l7policy(self, l7policy):
1266        """Deletes the specified L7 policy."""
1267        return self.delete(self.lbaas_l7policy_path % l7policy)
1268
1269    def list_lbaas_l7rules(self, l7policy, retrieve_all=True, **_params):
1270        """Fetches a list of all rules for L7 policy."""
1271        return self.list('rules', self.lbaas_l7rules_path % l7policy,
1272                         retrieve_all, **_params)
1273
1274    def show_lbaas_l7rule(self, l7rule, l7policy, **_params):
1275        """Fetches information of a certain L7 policy's rule."""
1276        return self.get(self.lbaas_l7rule_path % (l7policy, l7rule),
1277                        params=_params)
1278
1279    def create_lbaas_l7rule(self, l7policy, body=None):
1280        """Creates rule for a certain L7 policy."""
1281        return self.post(self.lbaas_l7rules_path % l7policy, body=body)
1282
1283    def update_lbaas_l7rule(self, l7rule, l7policy, body=None):
1284        """Updates L7 rule."""
1285        return self.put(self.lbaas_l7rule_path % (l7policy, l7rule),
1286                        body=body)
1287
1288    def delete_lbaas_l7rule(self, l7rule, l7policy):
1289        """Deletes the specified L7 rule."""
1290        return self.delete(self.lbaas_l7rule_path % (l7policy, l7rule))
1291
1292    def list_lbaas_pools(self, retrieve_all=True, **_params):
1293        """Fetches a list of all lbaas_pools for a project."""
1294        return self.list('pools', self.lbaas_pools_path,
1295                         retrieve_all, **_params)
1296
1297    def show_lbaas_pool(self, lbaas_pool, **_params):
1298        """Fetches information for a lbaas_pool."""
1299        return self.get(self.lbaas_pool_path % (lbaas_pool),
1300                        params=_params)
1301
1302    def create_lbaas_pool(self, body=None):
1303        """Creates a new lbaas_pool."""
1304        return self.post(self.lbaas_pools_path, body=body)
1305
1306    def update_lbaas_pool(self, lbaas_pool, body=None):
1307        """Updates a lbaas_pool."""
1308        return self.put(self.lbaas_pool_path % (lbaas_pool),
1309                        body=body)
1310
1311    def delete_lbaas_pool(self, lbaas_pool):
1312        """Deletes the specified lbaas_pool."""
1313        return self.delete(self.lbaas_pool_path % (lbaas_pool))
1314
1315    def list_lbaas_healthmonitors(self, retrieve_all=True, **_params):
1316        """Fetches a list of all lbaas_healthmonitors for a project."""
1317        return self.list('healthmonitors', self.lbaas_healthmonitors_path,
1318                         retrieve_all, **_params)
1319
1320    def show_lbaas_healthmonitor(self, lbaas_healthmonitor, **_params):
1321        """Fetches information for a lbaas_healthmonitor."""
1322        return self.get(self.lbaas_healthmonitor_path % (lbaas_healthmonitor),
1323                        params=_params)
1324
1325    def create_lbaas_healthmonitor(self, body=None):
1326        """Creates a new lbaas_healthmonitor."""
1327        return self.post(self.lbaas_healthmonitors_path, body=body)
1328
1329    def update_lbaas_healthmonitor(self, lbaas_healthmonitor, body=None):
1330        """Updates a lbaas_healthmonitor."""
1331        return self.put(self.lbaas_healthmonitor_path % (lbaas_healthmonitor),
1332                        body=body)
1333
1334    def delete_lbaas_healthmonitor(self, lbaas_healthmonitor):
1335        """Deletes the specified lbaas_healthmonitor."""
1336        return self.delete(self.lbaas_healthmonitor_path %
1337                           (lbaas_healthmonitor))
1338
1339    def list_lbaas_loadbalancers(self, retrieve_all=True, **_params):
1340        """Fetches a list of all lbaas_loadbalancers for a project."""
1341        return self.list('loadbalancers', self.lbaas_loadbalancers_path,
1342                         retrieve_all, **_params)
1343
1344    def list_lbaas_members(self, lbaas_pool, retrieve_all=True, **_params):
1345        """Fetches a list of all lbaas_members for a project."""
1346        return self.list('members', self.lbaas_members_path % lbaas_pool,
1347                         retrieve_all, **_params)
1348
1349    def show_lbaas_member(self, lbaas_member, lbaas_pool, **_params):
1350        """Fetches information of a certain lbaas_member."""
1351        return self.get(self.lbaas_member_path % (lbaas_pool, lbaas_member),
1352                        params=_params)
1353
1354    def create_lbaas_member(self, lbaas_pool, body=None):
1355        """Creates a lbaas_member."""
1356        return self.post(self.lbaas_members_path % lbaas_pool, body=body)
1357
1358    def update_lbaas_member(self, lbaas_member, lbaas_pool, body=None):
1359        """Updates a lbaas_member."""
1360        return self.put(self.lbaas_member_path % (lbaas_pool, lbaas_member),
1361                        body=body)
1362
1363    def delete_lbaas_member(self, lbaas_member, lbaas_pool):
1364        """Deletes the specified lbaas_member."""
1365        return self.delete(self.lbaas_member_path % (lbaas_pool, lbaas_member))
1366
1367    def list_vips(self, retrieve_all=True, **_params):
1368        """Fetches a list of all load balancer vips for a project."""
1369        # Pass filters in "params" argument to do_request
1370        return self.list('vips', self.vips_path, retrieve_all,
1371                         **_params)
1372
1373    def show_vip(self, vip, **_params):
1374        """Fetches information of a certain load balancer vip."""
1375        return self.get(self.vip_path % (vip), params=_params)
1376
1377    def create_vip(self, body=None):
1378        """Creates a new load balancer vip."""
1379        return self.post(self.vips_path, body=body)
1380
1381    def update_vip(self, vip, body=None):
1382        """Updates a load balancer vip."""
1383        return self.put(self.vip_path % (vip), body=body)
1384
1385    def delete_vip(self, vip):
1386        """Deletes the specified load balancer vip."""
1387        return self.delete(self.vip_path % (vip))
1388
1389    def list_pools(self, retrieve_all=True, **_params):
1390        """Fetches a list of all load balancer pools for a project."""
1391        # Pass filters in "params" argument to do_request
1392        return self.list('pools', self.pools_path, retrieve_all,
1393                         **_params)
1394
1395    def show_pool(self, pool, **_params):
1396        """Fetches information of a certain load balancer pool."""
1397        return self.get(self.pool_path % (pool), params=_params)
1398
1399    def create_pool(self, body=None):
1400        """Creates a new load balancer pool."""
1401        return self.post(self.pools_path, body=body)
1402
1403    def update_pool(self, pool, body=None):
1404        """Updates a load balancer pool."""
1405        return self.put(self.pool_path % (pool), body=body)
1406
1407    def delete_pool(self, pool):
1408        """Deletes the specified load balancer pool."""
1409        return self.delete(self.pool_path % (pool))
1410
1411    def retrieve_pool_stats(self, pool, **_params):
1412        """Retrieves stats for a certain load balancer pool."""
1413        return self.get(self.pool_path_stats % (pool), params=_params)
1414
1415    def list_members(self, retrieve_all=True, **_params):
1416        """Fetches a list of all load balancer members for a project."""
1417        # Pass filters in "params" argument to do_request
1418        return self.list('members', self.members_path, retrieve_all,
1419                         **_params)
1420
1421    def show_member(self, member, **_params):
1422        """Fetches information of a certain load balancer member."""
1423        return self.get(self.member_path % (member), params=_params)
1424
1425    def create_member(self, body=None):
1426        """Creates a new load balancer member."""
1427        return self.post(self.members_path, body=body)
1428
1429    def update_member(self, member, body=None):
1430        """Updates a load balancer member."""
1431        return self.put(self.member_path % (member), body=body)
1432
1433    def delete_member(self, member):
1434        """Deletes the specified load balancer member."""
1435        return self.delete(self.member_path % (member))
1436
1437    def list_health_monitors(self, retrieve_all=True, **_params):
1438        """Fetches a list of all load balancer health monitors for a project.
1439
1440        """
1441        # Pass filters in "params" argument to do_request
1442        return self.list('health_monitors', self.health_monitors_path,
1443                         retrieve_all, **_params)
1444
1445    def show_health_monitor(self, health_monitor, **_params):
1446        """Fetches information of a certain load balancer health monitor."""
1447        return self.get(self.health_monitor_path % (health_monitor),
1448                        params=_params)
1449
1450    def create_health_monitor(self, body=None):
1451        """Creates a new load balancer health monitor."""
1452        return self.post(self.health_monitors_path, body=body)
1453
1454    def update_health_monitor(self, health_monitor, body=None):
1455        """Updates a load balancer health monitor."""
1456        return self.put(self.health_monitor_path % (health_monitor), body=body)
1457
1458    def delete_health_monitor(self, health_monitor):
1459        """Deletes the specified load balancer health monitor."""
1460        return self.delete(self.health_monitor_path % (health_monitor))
1461
1462    def associate_health_monitor(self, pool, body):
1463        """Associate  specified load balancer health monitor and pool."""
1464        return self.post(self.associate_pool_health_monitors_path % (pool),
1465                         body=body)
1466
1467    def disassociate_health_monitor(self, pool, health_monitor):
1468        """Disassociate specified load balancer health monitor and pool."""
1469        path = (self.disassociate_pool_health_monitors_path %
1470                {'pool': pool, 'health_monitor': health_monitor})
1471        return self.delete(path)
1472
1473    def create_qos_queue(self, body=None):
1474        """Creates a new queue."""
1475        return self.post(self.qos_queues_path, body=body)
1476
1477    def list_qos_queues(self, **_params):
1478        """Fetches a list of all queues for a project."""
1479        return self.get(self.qos_queues_path, params=_params)
1480
1481    def show_qos_queue(self, queue, **_params):
1482        """Fetches information of a certain queue."""
1483        return self.get(self.qos_queue_path % (queue),
1484                        params=_params)
1485
1486    def delete_qos_queue(self, queue):
1487        """Deletes the specified queue."""
1488        return self.delete(self.qos_queue_path % (queue))
1489
1490    def list_agents(self, **_params):
1491        """Fetches agents."""
1492        # Pass filters in "params" argument to do_request
1493        return self.get(self.agents_path, params=_params)
1494
1495    def show_agent(self, agent, **_params):
1496        """Fetches information of a certain agent."""
1497        return self.get(self.agent_path % (agent), params=_params)
1498
1499    def update_agent(self, agent, body=None):
1500        """Updates an agent."""
1501        return self.put(self.agent_path % (agent), body=body)
1502
1503    def delete_agent(self, agent):
1504        """Deletes the specified agent."""
1505        return self.delete(self.agent_path % (agent))
1506
1507    def list_network_gateways(self, **_params):
1508        """Retrieve network gateways."""
1509        return self.get(self.network_gateways_path, params=_params)
1510
1511    def show_network_gateway(self, gateway_id, **_params):
1512        """Fetch a network gateway."""
1513        return self.get(self.network_gateway_path % gateway_id, params=_params)
1514
1515    def create_network_gateway(self, body=None):
1516        """Create a new network gateway."""
1517        return self.post(self.network_gateways_path, body=body)
1518
1519    def update_network_gateway(self, gateway_id, body=None):
1520        """Update a network gateway."""
1521        return self.put(self.network_gateway_path % gateway_id, body=body)
1522
1523    def delete_network_gateway(self, gateway_id):
1524        """Delete the specified network gateway."""
1525        return self.delete(self.network_gateway_path % gateway_id)
1526
1527    def connect_network_gateway(self, gateway_id, body=None):
1528        """Connect a network gateway to the specified network."""
1529        base_uri = self.network_gateway_path % gateway_id
1530        return self.put("%s/connect_network" % base_uri, body=body)
1531
1532    def disconnect_network_gateway(self, gateway_id, body=None):
1533        """Disconnect a network from the specified gateway."""
1534        base_uri = self.network_gateway_path % gateway_id
1535        return self.put("%s/disconnect_network" % base_uri, body=body)
1536
1537    def list_gateway_devices(self, **_params):
1538        """Retrieve gateway devices."""
1539        return self.get(self.gateway_devices_path, params=_params)
1540
1541    def show_gateway_device(self, gateway_device_id, **_params):
1542        """Fetch a gateway device."""
1543        return self.get(self.gateway_device_path % gateway_device_id,
1544                        params=_params)
1545
1546    def create_gateway_device(self, body=None):
1547        """Create a new gateway device."""
1548        return self.post(self.gateway_devices_path, body=body)
1549
1550    def update_gateway_device(self, gateway_device_id, body=None):
1551        """Updates a new gateway device."""
1552        return self.put(self.gateway_device_path % gateway_device_id,
1553                        body=body)
1554
1555    def delete_gateway_device(self, gateway_device_id):
1556        """Delete the specified gateway device."""
1557        return self.delete(self.gateway_device_path % gateway_device_id)
1558
1559    def list_dhcp_agent_hosting_networks(self, network, **_params):
1560        """Fetches a list of dhcp agents hosting a network."""
1561        return self.get((self.network_path + self.DHCP_AGENTS) % network,
1562                        params=_params)
1563
1564    def list_networks_on_dhcp_agent(self, dhcp_agent, **_params):
1565        """Fetches a list of networks hosted on a DHCP agent."""
1566        return self.get((self.agent_path + self.DHCP_NETS) % dhcp_agent,
1567                        params=_params)
1568
1569    def add_network_to_dhcp_agent(self, dhcp_agent, body=None):
1570        """Adds a network to dhcp agent."""
1571        return self.post((self.agent_path + self.DHCP_NETS) % dhcp_agent,
1572                         body=body)
1573
1574    def remove_network_from_dhcp_agent(self, dhcp_agent, network_id):
1575        """Remove a network from dhcp agent."""
1576        return self.delete((self.agent_path + self.DHCP_NETS + "/%s") % (
1577            dhcp_agent, network_id))
1578
1579    def list_l3_agent_hosting_routers(self, router, **_params):
1580        """Fetches a list of L3 agents hosting a router."""
1581        return self.get((self.router_path + self.L3_AGENTS) % router,
1582                        params=_params)
1583
1584    def list_routers_on_l3_agent(self, l3_agent, **_params):
1585        """Fetches a list of routers hosted on an L3 agent."""
1586        return self.get((self.agent_path + self.L3_ROUTERS) % l3_agent,
1587                        params=_params)
1588
1589    def add_router_to_l3_agent(self, l3_agent, body):
1590        """Adds a router to L3 agent."""
1591        return self.post((self.agent_path + self.L3_ROUTERS) % l3_agent,
1592                         body=body)
1593
1594    def list_dragents_hosting_bgp_speaker(self, bgp_speaker, **_params):
1595        """Fetches a list of Dynamic Routing agents hosting a BGP speaker."""
1596        return self.get((self.bgp_speaker_path + self.BGP_DRAGENTS)
1597                        % bgp_speaker, params=_params)
1598
1599    def add_bgp_speaker_to_dragent(self, bgp_dragent, body):
1600        """Adds a BGP speaker to Dynamic Routing agent."""
1601        return self.post((self.agent_path + self.BGP_DRINSTANCES)
1602                         % bgp_dragent, body=body)
1603
1604    def remove_bgp_speaker_from_dragent(self, bgp_dragent, bgpspeaker_id):
1605        """Removes a BGP speaker from Dynamic Routing agent."""
1606        return self.delete((self.agent_path + self.BGP_DRINSTANCES + "/%s")
1607                           % (bgp_dragent, bgpspeaker_id))
1608
1609    def list_bgp_speaker_on_dragent(self, bgp_dragent, **_params):
1610        """Fetches a list of BGP speakers hosted by Dynamic Routing agent."""
1611        return self.get((self.agent_path + self.BGP_DRINSTANCES)
1612                        % bgp_dragent, params=_params)
1613
1614    def list_firewall_rules(self, retrieve_all=True, **_params):
1615        """Fetches a list of all firewall rules for a project."""
1616        # Pass filters in "params" argument to do_request
1617
1618        return self.list('firewall_rules', self.firewall_rules_path,
1619                         retrieve_all, **_params)
1620
1621    def show_firewall_rule(self, firewall_rule, **_params):
1622        """Fetches information of a certain firewall rule."""
1623        return self.get(self.firewall_rule_path % (firewall_rule),
1624                        params=_params)
1625
1626    def create_firewall_rule(self, body=None):
1627        """Creates a new firewall rule."""
1628        return self.post(self.firewall_rules_path, body=body)
1629
1630    def update_firewall_rule(self, firewall_rule, body=None):
1631        """Updates a firewall rule."""
1632        return self.put(self.firewall_rule_path % (firewall_rule), body=body)
1633
1634    def delete_firewall_rule(self, firewall_rule):
1635        """Deletes the specified firewall rule."""
1636        return self.delete(self.firewall_rule_path % (firewall_rule))
1637
1638    def list_firewall_policies(self, retrieve_all=True, **_params):
1639        """Fetches a list of all firewall policies for a project."""
1640        # Pass filters in "params" argument to do_request
1641
1642        return self.list('firewall_policies', self.firewall_policies_path,
1643                         retrieve_all, **_params)
1644
1645    def show_firewall_policy(self, firewall_policy, **_params):
1646        """Fetches information of a certain firewall policy."""
1647        return self.get(self.firewall_policy_path % (firewall_policy),
1648                        params=_params)
1649
1650    def create_firewall_policy(self, body=None):
1651        """Creates a new firewall policy."""
1652        return self.post(self.firewall_policies_path, body=body)
1653
1654    def update_firewall_policy(self, firewall_policy, body=None):
1655        """Updates a firewall policy."""
1656        return self.put(self.firewall_policy_path % (firewall_policy),
1657                        body=body)
1658
1659    def delete_firewall_policy(self, firewall_policy):
1660        """Deletes the specified firewall policy."""
1661        return self.delete(self.firewall_policy_path % (firewall_policy))
1662
1663    def firewall_policy_insert_rule(self, firewall_policy, body=None):
1664        """Inserts specified rule into firewall policy."""
1665        return self.put(self.firewall_policy_insert_path % (firewall_policy),
1666                        body=body)
1667
1668    def firewall_policy_remove_rule(self, firewall_policy, body=None):
1669        """Removes specified rule from firewall policy."""
1670        return self.put(self.firewall_policy_remove_path % (firewall_policy),
1671                        body=body)
1672
1673    def list_firewalls(self, retrieve_all=True, **_params):
1674        """Fetches a list of all firewalls for a project."""
1675        # Pass filters in "params" argument to do_request
1676
1677        return self.list('firewalls', self.firewalls_path, retrieve_all,
1678                         **_params)
1679
1680    def show_firewall(self, firewall, **_params):
1681        """Fetches information of a certain firewall."""
1682        return self.get(self.firewall_path % (firewall), params=_params)
1683
1684    def create_firewall(self, body=None):
1685        """Creates a new firewall."""
1686        return self.post(self.firewalls_path, body=body)
1687
1688    def update_firewall(self, firewall, body=None):
1689        """Updates a firewall."""
1690        return self.put(self.firewall_path % (firewall), body=body)
1691
1692    def delete_firewall(self, firewall):
1693        """Deletes the specified firewall."""
1694        return self.delete(self.firewall_path % (firewall))
1695
1696    def list_fwaas_firewall_groups(self, retrieve_all=True, **_params):
1697        """Fetches a list of all firewall groups for a project"""
1698        return self.list('firewall_groups', self.fwaas_firewall_groups_path,
1699                         retrieve_all, **_params)
1700
1701    def show_fwaas_firewall_group(self, fwg, **_params):
1702        """Fetches information of a certain firewall group"""
1703        return self.get(self.fwaas_firewall_group_path % (fwg), params=_params)
1704
1705    def create_fwaas_firewall_group(self, body=None):
1706        """Creates a new firewall group"""
1707        return self.post(self.fwaas_firewall_groups_path, body=body)
1708
1709    def update_fwaas_firewall_group(self, fwg, body=None):
1710        """Updates a firewall group"""
1711        return self.put(self.fwaas_firewall_group_path % (fwg), body=body)
1712
1713    def delete_fwaas_firewall_group(self, fwg):
1714        """Deletes the specified firewall group"""
1715        return self.delete(self.fwaas_firewall_group_path % (fwg))
1716
1717    def list_fwaas_firewall_rules(self, retrieve_all=True, **_params):
1718        """Fetches a list of all firewall rules for a project"""
1719        # Pass filters in "params" argument to do_request
1720        return self.list('firewall_rules', self.fwaas_firewall_rules_path,
1721                         retrieve_all, **_params)
1722
1723    def show_fwaas_firewall_rule(self, firewall_rule, **_params):
1724        """Fetches information of a certain firewall rule"""
1725        return self.get(self.fwaas_firewall_rule_path % (firewall_rule),
1726                        params=_params)
1727
1728    def create_fwaas_firewall_rule(self, body=None):
1729        """Creates a new firewall rule"""
1730        return self.post(self.fwaas_firewall_rules_path, body=body)
1731
1732    def update_fwaas_firewall_rule(self, firewall_rule, body=None):
1733        """Updates a firewall rule"""
1734        return self.put(self.fwaas_firewall_rule_path % (firewall_rule),
1735                        body=body)
1736
1737    def delete_fwaas_firewall_rule(self, firewall_rule):
1738        """Deletes the specified firewall rule"""
1739        return self.delete(self.fwaas_firewall_rule_path % (firewall_rule))
1740
1741    def list_fwaas_firewall_policies(self, retrieve_all=True, **_params):
1742        """Fetches a list of all firewall policies for a project"""
1743        # Pass filters in "params" argument to do_request
1744
1745        return self.list('firewall_policies',
1746                         self.fwaas_firewall_policies_path,
1747                         retrieve_all, **_params)
1748
1749    def show_fwaas_firewall_policy(self, firewall_policy, **_params):
1750        """Fetches information of a certain firewall policy"""
1751        return self.get(self.fwaas_firewall_policy_path % (firewall_policy),
1752                        params=_params)
1753
1754    def create_fwaas_firewall_policy(self, body=None):
1755        """Creates a new firewall policy"""
1756        return self.post(self.fwaas_firewall_policies_path, body=body)
1757
1758    def update_fwaas_firewall_policy(self, firewall_policy, body=None):
1759        """Updates a firewall policy"""
1760        return self.put(self.fwaas_firewall_policy_path % (firewall_policy),
1761                        body=body)
1762
1763    def delete_fwaas_firewall_policy(self, firewall_policy):
1764        """Deletes the specified firewall policy"""
1765        return self.delete(self.fwaas_firewall_policy_path % (firewall_policy))
1766
1767    def insert_rule_fwaas_firewall_policy(self, firewall_policy, body=None):
1768        """Inserts specified rule into firewall policy"""
1769        return self.put((self.fwaas_firewall_policy_insert_path %
1770                        (firewall_policy)), body=body)
1771
1772    def remove_rule_fwaas_firewall_policy(self, firewall_policy, body=None):
1773        """Removes specified rule from firewall policy"""
1774        return self.put((self.fwaas_firewall_policy_remove_path %
1775                        (firewall_policy)), body=body)
1776
1777    def remove_router_from_l3_agent(self, l3_agent, router_id):
1778        """Remove a router from l3 agent."""
1779        return self.delete((self.agent_path + self.L3_ROUTERS + "/%s") % (
1780            l3_agent, router_id))
1781
1782    def get_lbaas_agent_hosting_pool(self, pool, **_params):
1783        """Fetches a loadbalancer agent hosting a pool."""
1784        return self.get((self.pool_path + self.LOADBALANCER_AGENT) % pool,
1785                        params=_params)
1786
1787    def list_pools_on_lbaas_agent(self, lbaas_agent, **_params):
1788        """Fetches a list of pools hosted by the loadbalancer agent."""
1789        return self.get((self.agent_path + self.LOADBALANCER_POOLS) %
1790                        lbaas_agent, params=_params)
1791
1792    def get_lbaas_agent_hosting_loadbalancer(self, loadbalancer, **_params):
1793        """Fetches a loadbalancer agent hosting a loadbalancer."""
1794        return self.get((self.lbaas_loadbalancer_path +
1795                         self.LOADBALANCER_HOSTING_AGENT) % loadbalancer,
1796                        params=_params)
1797
1798    def list_loadbalancers_on_lbaas_agent(self, lbaas_agent, **_params):
1799        """Fetches a list of loadbalancers hosted by the loadbalancer agent."""
1800        return self.get((self.agent_path + self.AGENT_LOADBALANCERS) %
1801                        lbaas_agent, params=_params)
1802
1803    def list_service_providers(self, retrieve_all=True, **_params):
1804        """Fetches service providers."""
1805        # Pass filters in "params" argument to do_request
1806        return self.list('service_providers', self.service_providers_path,
1807                         retrieve_all, **_params)
1808
1809    def create_metering_label(self, body=None):
1810        """Creates a metering label."""
1811        return self.post(self.metering_labels_path, body=body)
1812
1813    def delete_metering_label(self, label):
1814        """Deletes the specified metering label."""
1815        return self.delete(self.metering_label_path % (label))
1816
1817    def list_metering_labels(self, retrieve_all=True, **_params):
1818        """Fetches a list of all metering labels for a project."""
1819        return self.list('metering_labels', self.metering_labels_path,
1820                         retrieve_all, **_params)
1821
1822    def show_metering_label(self, metering_label, **_params):
1823        """Fetches information of a certain metering label."""
1824        return self.get(self.metering_label_path %
1825                        (metering_label), params=_params)
1826
1827    def create_metering_label_rule(self, body=None):
1828        """Creates a metering label rule."""
1829        return self.post(self.metering_label_rules_path, body=body)
1830
1831    def delete_metering_label_rule(self, rule):
1832        """Deletes the specified metering label rule."""
1833        return self.delete(self.metering_label_rule_path % (rule))
1834
1835    def list_metering_label_rules(self, retrieve_all=True, **_params):
1836        """Fetches a list of all metering label rules for a label."""
1837        return self.list('metering_label_rules',
1838                         self.metering_label_rules_path, retrieve_all,
1839                         **_params)
1840
1841    def show_metering_label_rule(self, metering_label_rule, **_params):
1842        """Fetches information of a certain metering label rule."""
1843        return self.get(self.metering_label_rule_path %
1844                        (metering_label_rule), params=_params)
1845
1846    def create_rbac_policy(self, body=None):
1847        """Create a new RBAC policy."""
1848        return self.post(self.rbac_policies_path, body=body)
1849
1850    def update_rbac_policy(self, rbac_policy_id, body=None):
1851        """Update a RBAC policy."""
1852        return self.put(self.rbac_policy_path % rbac_policy_id, body=body)
1853
1854    def list_rbac_policies(self, retrieve_all=True, **_params):
1855        """Fetch a list of all RBAC policies for a project."""
1856        return self.list('rbac_policies', self.rbac_policies_path,
1857                         retrieve_all, **_params)
1858
1859    def show_rbac_policy(self, rbac_policy_id, **_params):
1860        """Fetch information of a certain RBAC policy."""
1861        return self.get(self.rbac_policy_path % rbac_policy_id,
1862                        params=_params)
1863
1864    def delete_rbac_policy(self, rbac_policy_id):
1865        """Delete the specified RBAC policy."""
1866        return self.delete(self.rbac_policy_path % rbac_policy_id)
1867
1868    def list_qos_policies(self, retrieve_all=True, **_params):
1869        """Fetches a list of all qos policies for a project."""
1870        # Pass filters in "params" argument to do_request
1871        return self.list('policies', self.qos_policies_path,
1872                         retrieve_all, **_params)
1873
1874    def show_qos_policy(self, qos_policy, **_params):
1875        """Fetches information of a certain qos policy."""
1876        return self.get(self.qos_policy_path % qos_policy,
1877                        params=_params)
1878
1879    def create_qos_policy(self, body=None):
1880        """Creates a new qos policy."""
1881        return self.post(self.qos_policies_path, body=body)
1882
1883    def update_qos_policy(self, qos_policy, body=None, revision_number=None):
1884        """Updates a qos policy."""
1885        return self._update_resource(self.qos_policy_path % qos_policy,
1886                                     body=body,
1887                                     revision_number=revision_number)
1888
1889    def delete_qos_policy(self, qos_policy):
1890        """Deletes the specified qos policy."""
1891        return self.delete(self.qos_policy_path % qos_policy)
1892
1893    def list_qos_rule_types(self, retrieve_all=True, **_params):
1894        """List available qos rule types."""
1895        return self.list('rule_types', self.qos_rule_types_path,
1896                         retrieve_all, **_params)
1897
1898    def list_bandwidth_limit_rules(self, policy_id,
1899                                   retrieve_all=True, **_params):
1900        """Fetches a list of all bandwidth limit rules for the given policy."""
1901        return self.list('bandwidth_limit_rules',
1902                         self.qos_bandwidth_limit_rules_path % policy_id,
1903                         retrieve_all, **_params)
1904
1905    def show_bandwidth_limit_rule(self, rule, policy, **_params):
1906        """Fetches information of a certain bandwidth limit rule."""
1907        return self.get(self.qos_bandwidth_limit_rule_path %
1908                        (policy, rule), params=_params)
1909
1910    def create_bandwidth_limit_rule(self, policy, body=None):
1911        """Creates a new bandwidth limit rule."""
1912        return self.post(self.qos_bandwidth_limit_rules_path % policy,
1913                         body=body)
1914
1915    def update_bandwidth_limit_rule(self, rule, policy, body=None):
1916        """Updates a bandwidth limit rule."""
1917        return self.put(self.qos_bandwidth_limit_rule_path %
1918                        (policy, rule), body=body)
1919
1920    def delete_bandwidth_limit_rule(self, rule, policy):
1921        """Deletes a bandwidth limit rule."""
1922        return self.delete(self.qos_bandwidth_limit_rule_path %
1923                           (policy, rule))
1924
1925    def list_dscp_marking_rules(self, policy_id,
1926                                retrieve_all=True, **_params):
1927        """Fetches a list of all DSCP marking rules for the given policy."""
1928        return self.list('dscp_marking_rules',
1929                         self.qos_dscp_marking_rules_path % policy_id,
1930                         retrieve_all, **_params)
1931
1932    def show_dscp_marking_rule(self, rule, policy, **_params):
1933        """Shows information of a certain DSCP marking rule."""
1934        return self.get(self.qos_dscp_marking_rule_path %
1935                        (policy, rule), params=_params)
1936
1937    def create_dscp_marking_rule(self, policy, body=None):
1938        """Creates a new DSCP marking rule."""
1939        return self.post(self.qos_dscp_marking_rules_path % policy,
1940                         body=body)
1941
1942    def update_dscp_marking_rule(self, rule, policy, body=None):
1943        """Updates a DSCP marking rule."""
1944        return self.put(self.qos_dscp_marking_rule_path %
1945                        (policy, rule), body=body)
1946
1947    def delete_dscp_marking_rule(self, rule, policy):
1948        """Deletes a DSCP marking rule."""
1949        return self.delete(self.qos_dscp_marking_rule_path %
1950                           (policy, rule))
1951
1952    def list_minimum_bandwidth_rules(self, policy_id, retrieve_all=True,
1953                                     **_params):
1954        """Fetches a list of all minimum bandwidth rules for the given policy.
1955
1956        """
1957        return self.list('minimum_bandwidth_rules',
1958                         self.qos_minimum_bandwidth_rules_path %
1959                         policy_id, retrieve_all, **_params)
1960
1961    def show_minimum_bandwidth_rule(self, rule, policy, body=None):
1962        """Fetches information of a certain minimum bandwidth rule."""
1963        return self.get(self.qos_minimum_bandwidth_rule_path %
1964                        (policy, rule), body=body)
1965
1966    def create_minimum_bandwidth_rule(self, policy, body=None):
1967        """Creates a new minimum bandwidth rule."""
1968        return self.post(self.qos_minimum_bandwidth_rules_path % policy,
1969                         body=body)
1970
1971    def update_minimum_bandwidth_rule(self, rule, policy, body=None):
1972        """Updates a minimum bandwidth rule."""
1973        return self.put(self.qos_minimum_bandwidth_rule_path %
1974                        (policy, rule), body=body)
1975
1976    def delete_minimum_bandwidth_rule(self, rule, policy):
1977        """Deletes a minimum bandwidth rule."""
1978        return self.delete(self.qos_minimum_bandwidth_rule_path %
1979                           (policy, rule))
1980
1981    def create_flavor(self, body=None):
1982        """Creates a new Neutron service flavor."""
1983        return self.post(self.flavors_path, body=body)
1984
1985    def delete_flavor(self, flavor):
1986        """Deletes the specified Neutron service flavor."""
1987        return self.delete(self.flavor_path % (flavor))
1988
1989    def list_flavors(self, retrieve_all=True, **_params):
1990        """Fetches a list of all Neutron service flavors for a project."""
1991        return self.list('flavors', self.flavors_path, retrieve_all,
1992                         **_params)
1993
1994    def show_flavor(self, flavor, **_params):
1995        """Fetches information for a certain Neutron service flavor."""
1996        return self.get(self.flavor_path % (flavor), params=_params)
1997
1998    def update_flavor(self, flavor, body):
1999        """Update a Neutron service flavor."""
2000        return self.put(self.flavor_path % (flavor), body=body)
2001
2002    def associate_flavor(self, flavor, body):
2003        """Associate a Neutron service flavor with a profile."""
2004        return self.post(self.flavor_profile_bindings_path %
2005                         (flavor), body=body)
2006
2007    def disassociate_flavor(self, flavor, flavor_profile):
2008        """Disassociate a Neutron service flavor with a profile."""
2009        return self.delete(self.flavor_profile_binding_path %
2010                           (flavor, flavor_profile))
2011
2012    def create_service_profile(self, body=None):
2013        """Creates a new Neutron service flavor profile."""
2014        return self.post(self.service_profiles_path, body=body)
2015
2016    def delete_service_profile(self, flavor_profile):
2017        """Deletes the specified Neutron service flavor profile."""
2018        return self.delete(self.service_profile_path % (flavor_profile))
2019
2020    def list_service_profiles(self, retrieve_all=True, **_params):
2021        """Fetches a list of all Neutron service flavor profiles."""
2022        return self.list('service_profiles', self.service_profiles_path,
2023                         retrieve_all, **_params)
2024
2025    def show_service_profile(self, flavor_profile, **_params):
2026        """Fetches information for a certain Neutron service flavor profile."""
2027        return self.get(self.service_profile_path % (flavor_profile),
2028                        params=_params)
2029
2030    def update_service_profile(self, service_profile, body):
2031        """Update a Neutron service profile."""
2032        return self.put(self.service_profile_path % (service_profile),
2033                        body=body)
2034
2035    def list_availability_zones(self, retrieve_all=True, **_params):
2036        """Fetches a list of all availability zones."""
2037        return self.list('availability_zones', self.availability_zones_path,
2038                         retrieve_all, **_params)
2039
2040    @debtcollector.renames.renamed_kwarg(
2041        'tenant_id', 'project_id', replace=True)
2042    def get_auto_allocated_topology(self, project_id, **_params):
2043        """Fetch information about a project's auto-allocated topology."""
2044        return self.get(
2045            self.auto_allocated_topology_path % project_id,
2046            params=_params)
2047
2048    @debtcollector.renames.renamed_kwarg(
2049        'tenant_id', 'project_id', replace=True)
2050    def delete_auto_allocated_topology(self, project_id, **_params):
2051        """Delete a project's auto-allocated topology."""
2052        return self.delete(
2053            self.auto_allocated_topology_path % project_id,
2054            params=_params)
2055
2056    @debtcollector.renames.renamed_kwarg(
2057        'tenant_id', 'project_id', replace=True)
2058    def validate_auto_allocated_topology_requirements(self, project_id):
2059        """Validate requirements for getting an auto-allocated topology."""
2060        return self.get_auto_allocated_topology(project_id, fields=['dry-run'])
2061
2062    def list_bgp_speakers(self, retrieve_all=True, **_params):
2063        """Fetches a list of all BGP speakers for a project."""
2064        return self.list('bgp_speakers', self.bgp_speakers_path, retrieve_all,
2065                         **_params)
2066
2067    def show_bgp_speaker(self, bgp_speaker_id, **_params):
2068        """Fetches information of a certain BGP speaker."""
2069        return self.get(self.bgp_speaker_path % (bgp_speaker_id),
2070                        params=_params)
2071
2072    def create_bgp_speaker(self, body=None):
2073        """Creates a new BGP speaker."""
2074        return self.post(self.bgp_speakers_path, body=body)
2075
2076    def update_bgp_speaker(self, bgp_speaker_id, body=None):
2077        """Update a BGP speaker."""
2078        return self.put(self.bgp_speaker_path % bgp_speaker_id, body=body)
2079
2080    def delete_bgp_speaker(self, speaker_id):
2081        """Deletes the specified BGP speaker."""
2082        return self.delete(self.bgp_speaker_path % (speaker_id))
2083
2084    def add_peer_to_bgp_speaker(self, speaker_id, body=None):
2085        """Adds a peer to BGP speaker."""
2086        return self.put((self.bgp_speaker_path % speaker_id) +
2087                        "/add_bgp_peer", body=body)
2088
2089    def remove_peer_from_bgp_speaker(self, speaker_id, body=None):
2090        """Removes a peer from BGP speaker."""
2091        return self.put((self.bgp_speaker_path % speaker_id) +
2092                        "/remove_bgp_peer", body=body)
2093
2094    def add_network_to_bgp_speaker(self, speaker_id, body=None):
2095        """Adds a network to BGP speaker."""
2096        return self.put((self.bgp_speaker_path % speaker_id) +
2097                        "/add_gateway_network", body=body)
2098
2099    def remove_network_from_bgp_speaker(self, speaker_id, body=None):
2100        """Removes a network from BGP speaker."""
2101        return self.put((self.bgp_speaker_path % speaker_id) +
2102                        "/remove_gateway_network", body=body)
2103
2104    def list_route_advertised_from_bgp_speaker(self, speaker_id, **_params):
2105        """Fetches a list of all routes advertised by BGP speaker."""
2106        return self.get((self.bgp_speaker_path % speaker_id) +
2107                        "/get_advertised_routes", params=_params)
2108
2109    def list_bgp_peers(self, **_params):
2110        """Fetches a list of all BGP peers."""
2111        return self.get(self.bgp_peers_path, params=_params)
2112
2113    def show_bgp_peer(self, peer_id, **_params):
2114        """Fetches information of a certain BGP peer."""
2115        return self.get(self.bgp_peer_path % peer_id,
2116                        params=_params)
2117
2118    def create_bgp_peer(self, body=None):
2119        """Create a new BGP peer."""
2120        return self.post(self.bgp_peers_path, body=body)
2121
2122    def update_bgp_peer(self, bgp_peer_id, body=None):
2123        """Update a BGP peer."""
2124        return self.put(self.bgp_peer_path % bgp_peer_id, body=body)
2125
2126    def delete_bgp_peer(self, peer_id):
2127        """Deletes the specified BGP peer."""
2128        return self.delete(self.bgp_peer_path % peer_id)
2129
2130    def list_network_ip_availabilities(self, retrieve_all=True, **_params):
2131        """Fetches IP availability information for all networks"""
2132        return self.list('network_ip_availabilities',
2133                         self.network_ip_availabilities_path,
2134                         retrieve_all, **_params)
2135
2136    def show_network_ip_availability(self, network, **_params):
2137        """Fetches IP availability information for a specified network"""
2138        return self.get(self.network_ip_availability_path % (network),
2139                        params=_params)
2140
2141    def add_tag(self, resource_type, resource_id, tag, **_params):
2142        """Add a tag on the resource."""
2143        return self.put(self.tag_path % (resource_type, resource_id, tag))
2144
2145    def replace_tag(self, resource_type, resource_id, body, **_params):
2146        """Replace tags on the resource."""
2147        return self.put(self.tags_path % (resource_type, resource_id), body)
2148
2149    def remove_tag(self, resource_type, resource_id, tag, **_params):
2150        """Remove a tag on the resource."""
2151        return self.delete(self.tag_path % (resource_type, resource_id, tag))
2152
2153    def remove_tag_all(self, resource_type, resource_id, **_params):
2154        """Remove all tags on the resource."""
2155        return self.delete(self.tags_path % (resource_type, resource_id))
2156
2157    def create_trunk(self, body=None):
2158        """Create a trunk port."""
2159        return self.post(self.trunks_path, body=body)
2160
2161    def update_trunk(self, trunk, body=None, revision_number=None):
2162        """Update a trunk port."""
2163        return self._update_resource(self.trunk_path % trunk, body=body,
2164                                     revision_number=revision_number)
2165
2166    def delete_trunk(self, trunk):
2167        """Delete a trunk port."""
2168        return self.delete(self.trunk_path % (trunk))
2169
2170    def list_trunks(self, retrieve_all=True, **_params):
2171        """Fetch a list of all trunk ports."""
2172        return self.list('trunks', self.trunks_path, retrieve_all,
2173                         **_params)
2174
2175    def show_trunk(self, trunk, **_params):
2176        """Fetch information for a certain trunk port."""
2177        return self.get(self.trunk_path % (trunk), params=_params)
2178
2179    def trunk_add_subports(self, trunk, body=None):
2180        """Add specified subports to the trunk."""
2181        return self.put(self.subports_add_path % (trunk), body=body)
2182
2183    def trunk_remove_subports(self, trunk, body=None):
2184        """Removes specified subports from the trunk."""
2185        return self.put(self.subports_remove_path % (trunk), body=body)
2186
2187    def trunk_get_subports(self, trunk, **_params):
2188        """Fetch a list of all subports attached to given trunk."""
2189        return self.get(self.subports_path % (trunk), params=_params)
2190
2191    def list_bgpvpns(self, retrieve_all=True, **_params):
2192        """Fetches a list of all BGP VPNs for a project"""
2193        return self.list('bgpvpns', self.bgpvpns_path, retrieve_all, **_params)
2194
2195    def show_bgpvpn(self, bgpvpn, **_params):
2196        """Fetches information of a certain BGP VPN"""
2197        return self.get(self.bgpvpn_path % bgpvpn, params=_params)
2198
2199    def create_bgpvpn(self, body=None):
2200        """Creates a new BGP VPN"""
2201        return self.post(self.bgpvpns_path, body=body)
2202
2203    def update_bgpvpn(self, bgpvpn, body=None):
2204        """Updates a BGP VPN"""
2205        return self.put(self.bgpvpn_path % bgpvpn, body=body)
2206
2207    def delete_bgpvpn(self, bgpvpn):
2208        """Deletes the specified BGP VPN"""
2209        return self.delete(self.bgpvpn_path % bgpvpn)
2210
2211    def list_bgpvpn_network_assocs(self, bgpvpn, retrieve_all=True, **_params):
2212        """Fetches a list of network associations for a given BGP VPN."""
2213        return self.list('network_associations',
2214                         self.bgpvpn_network_associations_path % bgpvpn,
2215                         retrieve_all, **_params)
2216
2217    def show_bgpvpn_network_assoc(self, bgpvpn, net_assoc, **_params):
2218        """Fetches information of a certain BGP VPN's network association"""
2219        return self.get(
2220            self.bgpvpn_network_association_path % (bgpvpn, net_assoc),
2221            params=_params)
2222
2223    def create_bgpvpn_network_assoc(self, bgpvpn, body=None):
2224        """Creates a new BGP VPN network association"""
2225        return self.post(self.bgpvpn_network_associations_path % bgpvpn,
2226                         body=body)
2227
2228    def update_bgpvpn_network_assoc(self, bgpvpn, net_assoc, body=None):
2229        """Updates a BGP VPN network association"""
2230        return self.put(
2231            self.bgpvpn_network_association_path % (bgpvpn, net_assoc),
2232            body=body)
2233
2234    def delete_bgpvpn_network_assoc(self, bgpvpn, net_assoc):
2235        """Deletes the specified BGP VPN network association"""
2236        return self.delete(
2237            self.bgpvpn_network_association_path % (bgpvpn, net_assoc))
2238
2239    def list_bgpvpn_router_assocs(self, bgpvpn, retrieve_all=True, **_params):
2240        """Fetches a list of router associations for a given BGP VPN."""
2241        return self.list('router_associations',
2242                         self.bgpvpn_router_associations_path % bgpvpn,
2243                         retrieve_all, **_params)
2244
2245    def show_bgpvpn_router_assoc(self, bgpvpn, router_assoc, **_params):
2246        """Fetches information of a certain BGP VPN's router association"""
2247        return self.get(
2248            self.bgpvpn_router_association_path % (bgpvpn, router_assoc),
2249            params=_params)
2250
2251    def create_bgpvpn_router_assoc(self, bgpvpn, body=None):
2252        """Creates a new BGP VPN router association"""
2253        return self.post(self.bgpvpn_router_associations_path % bgpvpn,
2254                         body=body)
2255
2256    def update_bgpvpn_router_assoc(self, bgpvpn, router_assoc, body=None):
2257        """Updates a BGP VPN router association"""
2258        return self.put(
2259            self.bgpvpn_router_association_path % (bgpvpn, router_assoc),
2260            body=body)
2261
2262    def delete_bgpvpn_router_assoc(self, bgpvpn, router_assoc):
2263        """Deletes the specified BGP VPN router association"""
2264        return self.delete(
2265            self.bgpvpn_router_association_path % (bgpvpn, router_assoc))
2266
2267    def list_bgpvpn_port_assocs(self, bgpvpn, retrieve_all=True, **_params):
2268        """Fetches a list of port associations for a given BGP VPN."""
2269        return self.list('port_associations',
2270                         self.bgpvpn_port_associations_path % bgpvpn,
2271                         retrieve_all, **_params)
2272
2273    def show_bgpvpn_port_assoc(self, bgpvpn, port_assoc, **_params):
2274        """Fetches information of a certain BGP VPN's port association"""
2275        return self.get(
2276            self.bgpvpn_port_association_path % (bgpvpn, port_assoc),
2277            params=_params)
2278
2279    def create_bgpvpn_port_assoc(self, bgpvpn, body=None):
2280        """Creates a new BGP VPN port association"""
2281        return self.post(self.bgpvpn_port_associations_path % bgpvpn,
2282                         body=body)
2283
2284    def update_bgpvpn_port_assoc(self, bgpvpn, port_assoc, body=None):
2285        """Updates a BGP VPN port association"""
2286        return self.put(
2287            self.bgpvpn_port_association_path % (bgpvpn, port_assoc),
2288            body=body)
2289
2290    def delete_bgpvpn_port_assoc(self, bgpvpn, port_assoc):
2291        """Deletes the specified BGP VPN port association"""
2292        return self.delete(
2293            self.bgpvpn_port_association_path % (bgpvpn, port_assoc))
2294
2295    def create_sfc_port_pair(self, body=None):
2296        """Creates a new Port Pair."""
2297        return self.post(self.sfc_port_pairs_path, body=body)
2298
2299    def update_sfc_port_pair(self, port_pair, body=None):
2300        """Update a Port Pair."""
2301        return self.put(self.sfc_port_pair_path % port_pair, body=body)
2302
2303    def delete_sfc_port_pair(self, port_pair):
2304        """Deletes the specified Port Pair."""
2305        return self.delete(self.sfc_port_pair_path % (port_pair))
2306
2307    def list_sfc_port_pairs(self, retrieve_all=True, **_params):
2308        """Fetches a list of all Port Pairs."""
2309        return self.list('port_pairs', self.sfc_port_pairs_path, retrieve_all,
2310                         **_params)
2311
2312    def show_sfc_port_pair(self, port_pair, **_params):
2313        """Fetches information of a certain Port Pair."""
2314        return self.get(self.sfc_port_pair_path % (port_pair), params=_params)
2315
2316    def create_sfc_port_pair_group(self, body=None):
2317        """Creates a new Port Pair Group."""
2318        return self.post(self.sfc_port_pair_groups_path, body=body)
2319
2320    def update_sfc_port_pair_group(self, port_pair_group, body=None):
2321        """Update a Port Pair Group."""
2322        return self.put(self.sfc_port_pair_group_path % port_pair_group,
2323                        body=body)
2324
2325    def delete_sfc_port_pair_group(self, port_pair_group):
2326        """Deletes the specified Port Pair Group."""
2327        return self.delete(self.sfc_port_pair_group_path % (port_pair_group))
2328
2329    def list_sfc_port_pair_groups(self, retrieve_all=True, **_params):
2330        """Fetches a list of all Port Pair Groups."""
2331        return self.list('port_pair_groups', self.sfc_port_pair_groups_path,
2332                         retrieve_all, **_params)
2333
2334    def show_sfc_port_pair_group(self, port_pair_group, **_params):
2335        """Fetches information of a certain Port Pair Group."""
2336        return self.get(self.sfc_port_pair_group_path % (port_pair_group),
2337                        params=_params)
2338
2339    def create_sfc_port_chain(self, body=None):
2340        """Creates a new Port Chain."""
2341        return self.post(self.sfc_port_chains_path, body=body)
2342
2343    def update_sfc_port_chain(self, port_chain, body=None):
2344        """Update a Port Chain."""
2345        return self.put(self.sfc_port_chain_path % port_chain, body=body)
2346
2347    def delete_sfc_port_chain(self, port_chain):
2348        """Deletes the specified Port Chain."""
2349        return self.delete(self.sfc_port_chain_path % (port_chain))
2350
2351    def list_sfc_port_chains(self, retrieve_all=True, **_params):
2352        """Fetches a list of all Port Chains."""
2353        return self.list('port_chains', self.sfc_port_chains_path,
2354                         retrieve_all, **_params)
2355
2356    def show_sfc_port_chain(self, port_chain, **_params):
2357        """Fetches information of a certain Port Chain."""
2358        return self.get(self.sfc_port_chain_path % (port_chain),
2359                        params=_params)
2360
2361    def create_sfc_flow_classifier(self, body=None):
2362        """Creates a new Flow Classifier."""
2363        return self.post(self.sfc_flow_classifiers_path, body=body)
2364
2365    def update_sfc_flow_classifier(self, flow_classifier, body=None):
2366        """Update a Flow Classifier."""
2367        return self.put(self.sfc_flow_classifier_path % flow_classifier,
2368                        body=body)
2369
2370    def delete_sfc_flow_classifier(self, flow_classifier):
2371        """Deletes the specified Flow Classifier."""
2372        return self.delete(self.sfc_flow_classifier_path % (flow_classifier))
2373
2374    def list_sfc_flow_classifiers(self, retrieve_all=True, **_params):
2375        """Fetches a list of all Flow Classifiers."""
2376        return self.list('flow_classifiers', self.sfc_flow_classifiers_path,
2377                         retrieve_all, **_params)
2378
2379    def show_sfc_flow_classifier(self, flow_classifier, **_params):
2380        """Fetches information of a certain Flow Classifier."""
2381        return self.get(self.sfc_flow_classifier_path % (flow_classifier),
2382                        params=_params)
2383
2384    def create_sfc_service_graph(self, body=None):
2385        """Create the specified Service Graph."""
2386        return self.post(self.sfc_service_graphs_path, body=body)
2387
2388    def update_sfc_service_graph(self, service_graph, body=None):
2389        """Update a Service Graph."""
2390        return self.put(self.sfc_service_graph_path % service_graph,
2391                        body=body)
2392
2393    def delete_sfc_service_graph(self, service_graph):
2394        """Deletes the specified Service Graph."""
2395        return self.delete(self.sfc_service_graph_path % service_graph)
2396
2397    def list_sfc_service_graphs(self, retrieve_all=True, **_params):
2398        """Fetches a list of all Service Graphs."""
2399        return self.list('service_graphs', self.sfc_service_graphs_path,
2400                         retrieve_all, **_params)
2401
2402    def show_sfc_service_graph(self, service_graph, **_params):
2403        """Fetches information of a certain Service Graph."""
2404        return self.get(self.sfc_service_graph_path % service_graph,
2405                        params=_params)
2406
2407    def create_network_log(self, body=None):
2408        """Create a network log."""
2409        return self.post(self.network_logs_path, body=body)
2410
2411    def delete_network_log(self, net_log):
2412        """Delete a network log."""
2413        return self.delete(self.network_log_path % net_log)
2414
2415    def list_network_logs(self, retrieve_all=True, **_params):
2416        """Fetch a list of all network logs."""
2417        return self.list(
2418            'logs', self.network_logs_path, retrieve_all, **_params)
2419
2420    def show_network_log(self, net_log, **_params):
2421        """Fetch information for a certain network log."""
2422        return self.get(self.network_log_path % net_log, params=_params)
2423
2424    def update_network_log(self, net_log, body=None):
2425        """Update a network log."""
2426        return self.put(self.network_log_path % net_log, body=body)
2427
2428    def list_network_loggable_resources(self, retrieve_all=True, **_params):
2429        """Fetch a list of supported resource types for network log."""
2430        return self.list('loggable_resources', self.network_loggables_path,
2431                         retrieve_all, **_params)
2432
2433    def onboard_network_subnets(self, subnetpool, body=None):
2434        """Onboard the specified network's subnets into a subnet pool."""
2435        return self.put(self.onboard_network_subnets_path % (subnetpool),
2436                        body=body)
2437
2438    def __init__(self, **kwargs):
2439        """Initialize a new client for the Neutron v2.0 API."""
2440        super(Client, self).__init__(**kwargs)
2441        self._register_extensions(self.version)
2442
2443    def _update_resource(self, path, **kwargs):
2444        revision_number = kwargs.pop('revision_number', None)
2445        if revision_number:
2446            headers = kwargs.setdefault('headers', {})
2447            headers['If-Match'] = 'revision_number=%s' % revision_number
2448        return self.put(path, **kwargs)
2449
2450    def extend_show(self, resource_singular, path, parent_resource):
2451        def _fx(obj, **_params):
2452            return self.show_ext(path, obj, **_params)
2453
2454        def _parent_fx(obj, parent_id, **_params):
2455            return self.show_ext(path % parent_id, obj, **_params)
2456        fn = _fx if not parent_resource else _parent_fx
2457        setattr(self, "show_%s" % resource_singular, fn)
2458
2459    def extend_list(self, resource_plural, path, parent_resource):
2460        def _fx(retrieve_all=True, **_params):
2461            return self.list_ext(resource_plural, path,
2462                                 retrieve_all, **_params)
2463
2464        def _parent_fx(parent_id, retrieve_all=True, **_params):
2465            return self.list_ext(resource_plural, path % parent_id,
2466                                 retrieve_all, **_params)
2467        fn = _fx if not parent_resource else _parent_fx
2468        setattr(self, "list_%s" % resource_plural, fn)
2469
2470    def extend_create(self, resource_singular, path, parent_resource):
2471        def _fx(body=None):
2472            return self.create_ext(path, body)
2473
2474        def _parent_fx(parent_id, body=None):
2475            return self.create_ext(path % parent_id, body)
2476        fn = _fx if not parent_resource else _parent_fx
2477        setattr(self, "create_%s" % resource_singular, fn)
2478
2479    def extend_delete(self, resource_singular, path, parent_resource):
2480        def _fx(obj):
2481            return self.delete_ext(path, obj)
2482
2483        def _parent_fx(obj, parent_id):
2484            return self.delete_ext(path % parent_id, obj)
2485        fn = _fx if not parent_resource else _parent_fx
2486        setattr(self, "delete_%s" % resource_singular, fn)
2487
2488    def extend_update(self, resource_singular, path, parent_resource):
2489        def _fx(obj, body=None):
2490            return self.update_ext(path, obj, body)
2491
2492        def _parent_fx(obj, parent_id, body=None):
2493            return self.update_ext(path % parent_id, obj, body)
2494        fn = _fx if not parent_resource else _parent_fx
2495        setattr(self, "update_%s" % resource_singular, fn)
2496
2497    def _extend_client_with_module(self, module, version):
2498        classes = inspect.getmembers(module, inspect.isclass)
2499        for cls_name, cls in classes:
2500            if hasattr(cls, 'versions'):
2501                if version not in cls.versions:
2502                    continue
2503            parent_resource = getattr(cls, 'parent_resource', None)
2504            if issubclass(cls, client_extension.ClientExtensionList):
2505                self.extend_list(cls.resource_plural, cls.object_path,
2506                                 parent_resource)
2507            elif issubclass(cls, client_extension.ClientExtensionCreate):
2508                self.extend_create(cls.resource, cls.object_path,
2509                                   parent_resource)
2510            elif issubclass(cls, client_extension.ClientExtensionUpdate):
2511                self.extend_update(cls.resource, cls.resource_path,
2512                                   parent_resource)
2513            elif issubclass(cls, client_extension.ClientExtensionDelete):
2514                self.extend_delete(cls.resource, cls.resource_path,
2515                                   parent_resource)
2516            elif issubclass(cls, client_extension.ClientExtensionShow):
2517                self.extend_show(cls.resource, cls.resource_path,
2518                                 parent_resource)
2519            elif issubclass(cls, client_extension.NeutronClientExtension):
2520                setattr(self, "%s_path" % cls.resource_plural,
2521                        cls.object_path)
2522                setattr(self, "%s_path" % cls.resource, cls.resource_path)
2523                self.EXTED_PLURALS.update({cls.resource_plural: cls.resource})
2524
2525    def _register_extensions(self, version):
2526        for name, module in itertools.chain(
2527                client_extension._discover_via_entry_points()):
2528            self._extend_client_with_module(module, version)
2529