Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / db / db_base_plugin_common.py
1 # Copyright (c) 2015 OpenStack Foundation.
2 # All Rights Reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15
16 import functools
17
18 from oslo_config import cfg
19 from oslo_log import log as logging
20 from sqlalchemy.orm import exc
21
22 from neutron.api.v2 import attributes
23 from neutron.common import constants
24 from neutron.common import exceptions as n_exc
25 from neutron.common import utils
26 from neutron.db import common_db_mixin
27 from neutron.db import models_v2
28
29 LOG = logging.getLogger(__name__)
30
31
32 def convert_result_to_dict(f):
33     @functools.wraps(f)
34     def inner(*args, **kwargs):
35         result = f(*args, **kwargs)
36
37         if result is None:
38             return None
39         elif isinstance(result, list):
40             return [r.to_dict() for r in result]
41         else:
42             return result.to_dict()
43     return inner
44
45
46 def filter_fields(f):
47     @functools.wraps(f)
48     def inner_filter(*args, **kwargs):
49         result = f(*args, **kwargs)
50         fields = kwargs.get('fields')
51         if not fields:
52             try:
53                 pos = f.__code__.co_varnames.index('fields')
54                 fields = args[pos]
55             except (IndexError, ValueError):
56                 return result
57
58         do_filter = lambda d: {k: v for k, v in d.items() if k in fields}
59         if isinstance(result, list):
60             return [do_filter(obj) for obj in result]
61         else:
62             return do_filter(result)
63     return inner_filter
64
65
66 class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
67     """Stores getters and helper methods for db_base_plugin_v2
68
69     All private getters and simple helpers like _make_*_dict were moved from
70     db_base_plugin_v2.
71     More complicated logic and public methods left in db_base_plugin_v2.
72     Main purpose of this class is to make getters accessible for Ipam
73     backends.
74     """
75
76     @staticmethod
77     def _generate_mac():
78         return utils.get_random_mac(cfg.CONF.base_mac.split(':'))
79
80     @staticmethod
81     def _delete_ip_allocation(context, network_id, subnet_id, ip_address):
82
83         # Delete the IP address from the IPAllocate table
84         LOG.debug("Delete allocated IP %(ip_address)s "
85                   "(%(network_id)s/%(subnet_id)s)",
86                   {'ip_address': ip_address,
87                    'network_id': network_id,
88                    'subnet_id': subnet_id})
89         context.session.query(models_v2.IPAllocation).filter_by(
90             network_id=network_id,
91             ip_address=ip_address,
92             subnet_id=subnet_id).delete()
93
94     @staticmethod
95     def _store_ip_allocation(context, ip_address, network_id, subnet_id,
96                              port_id):
97         LOG.debug("Allocated IP %(ip_address)s "
98                   "(%(network_id)s/%(subnet_id)s/%(port_id)s)",
99                   {'ip_address': ip_address,
100                    'network_id': network_id,
101                    'subnet_id': subnet_id,
102                    'port_id': port_id})
103         allocated = models_v2.IPAllocation(
104             network_id=network_id,
105             port_id=port_id,
106             ip_address=ip_address,
107             subnet_id=subnet_id
108         )
109         context.session.add(allocated)
110
111     def _make_subnet_dict(self, subnet, fields=None, context=None):
112         res = {'id': subnet['id'],
113                'name': subnet['name'],
114                'tenant_id': subnet['tenant_id'],
115                'network_id': subnet['network_id'],
116                'ip_version': subnet['ip_version'],
117                'cidr': subnet['cidr'],
118                'subnetpool_id': subnet.get('subnetpool_id'),
119                'allocation_pools': [{'start': pool['first_ip'],
120                                      'end': pool['last_ip']}
121                                     for pool in subnet['allocation_pools']],
122                'gateway_ip': subnet['gateway_ip'],
123                'enable_dhcp': subnet['enable_dhcp'],
124                'ipv6_ra_mode': subnet['ipv6_ra_mode'],
125                'ipv6_address_mode': subnet['ipv6_address_mode'],
126                'dns_nameservers': [dns['address']
127                                    for dns in subnet['dns_nameservers']],
128                'host_routes': [{'destination': route['destination'],
129                                 'nexthop': route['nexthop']}
130                                for route in subnet['routes']],
131                }
132         # The shared attribute for a subnet is the same as its parent network
133         res['shared'] = self._is_network_shared(context, subnet.networks)
134         # Call auxiliary extend functions, if any
135         self._apply_dict_extend_functions(attributes.SUBNETS, res, subnet)
136         return self._fields(res, fields)
137
138     def _make_subnetpool_dict(self, subnetpool, fields=None):
139         default_prefixlen = str(subnetpool['default_prefixlen'])
140         min_prefixlen = str(subnetpool['min_prefixlen'])
141         max_prefixlen = str(subnetpool['max_prefixlen'])
142         res = {'id': subnetpool['id'],
143                'name': subnetpool['name'],
144                'tenant_id': subnetpool['tenant_id'],
145                'default_prefixlen': default_prefixlen,
146                'min_prefixlen': min_prefixlen,
147                'max_prefixlen': max_prefixlen,
148                'is_default': subnetpool['is_default'],
149                'shared': subnetpool['shared'],
150                'prefixes': [prefix['cidr']
151                             for prefix in subnetpool['prefixes']],
152                'ip_version': subnetpool['ip_version'],
153                'default_quota': subnetpool['default_quota'],
154                'address_scope_id': subnetpool['address_scope_id']}
155         return self._fields(res, fields)
156
157     def _make_port_dict(self, port, fields=None,
158                         process_extensions=True):
159         res = {"id": port["id"],
160                'name': port['name'],
161                "network_id": port["network_id"],
162                'tenant_id': port['tenant_id'],
163                "mac_address": port["mac_address"],
164                "admin_state_up": port["admin_state_up"],
165                "status": port["status"],
166                "fixed_ips": [{'subnet_id': ip["subnet_id"],
167                               'ip_address': ip["ip_address"]}
168                              for ip in port["fixed_ips"]],
169                "device_id": port["device_id"],
170                "device_owner": port["device_owner"]}
171         if "dns_name" in port:
172             res["dns_name"] = port["dns_name"]
173         if "dns_assignment" in port:
174             res["dns_assignment"] = [{"ip_address": a["ip_address"],
175                                       "hostname": a["hostname"],
176                                       "fqdn": a["fqdn"]}
177                                      for a in port["dns_assignment"]]
178         # Call auxiliary extend functions, if any
179         if process_extensions:
180             self._apply_dict_extend_functions(
181                 attributes.PORTS, res, port)
182         return self._fields(res, fields)
183
184     def _get_network(self, context, id):
185         try:
186             network = self._get_by_id(context, models_v2.Network, id)
187         except exc.NoResultFound:
188             raise n_exc.NetworkNotFound(net_id=id)
189         return network
190
191     def _get_subnet(self, context, id):
192         try:
193             subnet = self._get_by_id(context, models_v2.Subnet, id)
194         except exc.NoResultFound:
195             raise n_exc.SubnetNotFound(subnet_id=id)
196         return subnet
197
198     def _get_subnetpool(self, context, id):
199         try:
200             return self._get_by_id(context, models_v2.SubnetPool, id)
201         except exc.NoResultFound:
202             raise n_exc.SubnetPoolNotFound(subnetpool_id=id)
203
204     def _get_all_subnetpools(self, context):
205         # NOTE(tidwellr): see note in _get_all_subnets()
206         return context.session.query(models_v2.SubnetPool).all()
207
208     def _get_subnetpools_by_address_scope_id(self, context, address_scope_id):
209         # NOTE(vikram.choudhary): see note in _get_all_subnets()
210         subnetpool_qry = context.session.query(models_v2.SubnetPool)
211         return subnetpool_qry.filter_by(
212             address_scope_id=address_scope_id).all()
213
214     def _get_port(self, context, id):
215         try:
216             port = self._get_by_id(context, models_v2.Port, id)
217         except exc.NoResultFound:
218             raise n_exc.PortNotFound(port_id=id)
219         return port
220
221     def _get_dns_by_subnet(self, context, subnet_id):
222         dns_qry = context.session.query(models_v2.DNSNameServer)
223         return dns_qry.filter_by(subnet_id=subnet_id).order_by(
224             models_v2.DNSNameServer.order).all()
225
226     def _get_route_by_subnet(self, context, subnet_id):
227         route_qry = context.session.query(models_v2.SubnetRoute)
228         return route_qry.filter_by(subnet_id=subnet_id).all()
229
230     def _get_router_gw_ports_by_network(self, context, network_id):
231         port_qry = context.session.query(models_v2.Port)
232         return port_qry.filter_by(network_id=network_id,
233                 device_owner=constants.DEVICE_OWNER_ROUTER_GW).all()
234
235     def _get_subnets_by_network(self, context, network_id):
236         subnet_qry = context.session.query(models_v2.Subnet)
237         return subnet_qry.filter_by(network_id=network_id).all()
238
239     def _get_subnets_by_subnetpool(self, context, subnetpool_id):
240         subnet_qry = context.session.query(models_v2.Subnet)
241         return subnet_qry.filter_by(subnetpool_id=subnetpool_id).all()
242
243     def _get_all_subnets(self, context):
244         # NOTE(salvatore-orlando): This query might end up putting
245         # a lot of stress on the db. Consider adding a cache layer
246         return context.session.query(models_v2.Subnet).all()
247
248     def _get_subnets(self, context, filters=None, fields=None,
249                      sorts=None, limit=None, marker=None,
250                      page_reverse=False):
251         marker_obj = self._get_marker_obj(context, 'subnet', limit, marker)
252         make_subnet_dict = functools.partial(self._make_subnet_dict,
253                                              context=context)
254         return self._get_collection(context, models_v2.Subnet,
255                                     make_subnet_dict,
256                                     filters=filters, fields=fields,
257                                     sorts=sorts,
258                                     limit=limit,
259                                     marker_obj=marker_obj,
260                                     page_reverse=page_reverse)
261
262     def _make_network_dict(self, network, fields=None,
263                            process_extensions=True, context=None):
264         res = {'id': network['id'],
265                'name': network['name'],
266                'tenant_id': network['tenant_id'],
267                'admin_state_up': network['admin_state_up'],
268                'mtu': network.get('mtu', constants.DEFAULT_NETWORK_MTU),
269                'status': network['status'],
270                'subnets': [subnet['id']
271                            for subnet in network['subnets']]}
272         res['shared'] = self._is_network_shared(context, network)
273         # Call auxiliary extend functions, if any
274         if process_extensions:
275             self._apply_dict_extend_functions(
276                 attributes.NETWORKS, res, network)
277         return self._fields(res, fields)
278
279     def _is_network_shared(self, context, network):
280         # The shared attribute for a network now reflects if the network
281         # is shared to the calling tenant via an RBAC entry.
282         matches = ('*',) + ((context.tenant_id,) if context else ())
283         for entry in network.rbac_entries:
284             if (entry.action == 'access_as_shared' and
285                     entry.target_tenant in matches):
286                 return True
287         return False
288
289     def _make_subnet_args(self, detail, subnet, subnetpool_id):
290         gateway_ip = str(detail.gateway_ip) if detail.gateway_ip else None
291         args = {'tenant_id': detail.tenant_id,
292                 'id': detail.subnet_id,
293                 'name': subnet['name'],
294                 'network_id': subnet['network_id'],
295                 'ip_version': subnet['ip_version'],
296                 'cidr': str(detail.subnet_cidr),
297                 'subnetpool_id': subnetpool_id,
298                 'enable_dhcp': subnet['enable_dhcp'],
299                 'gateway_ip': gateway_ip}
300         if subnet['ip_version'] == 6 and subnet['enable_dhcp']:
301             if attributes.is_attr_set(subnet['ipv6_ra_mode']):
302                 args['ipv6_ra_mode'] = subnet['ipv6_ra_mode']
303             if attributes.is_attr_set(subnet['ipv6_address_mode']):
304                 args['ipv6_address_mode'] = subnet['ipv6_address_mode']
305         return args
306
307     def _make_fixed_ip_dict(self, ips):
308         # Excludes from dict all keys except subnet_id and ip_address
309         return [{'subnet_id': ip["subnet_id"],
310                  'ip_address': ip["ip_address"]}
311                 for ip in ips]