Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / ipam / drivers / neutrondb_ipam / db_api.py
1 # Copyright 2015 OpenStack LLC.
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 from oslo_db import exception as db_exc
17 from oslo_utils import uuidutils
18 from sqlalchemy.orm import exc as orm_exc
19
20 from neutron.ipam.drivers.neutrondb_ipam import db_models
21 from neutron.ipam import exceptions as ipam_exc
22
23 # Database operations for Neutron's DB-backed IPAM driver
24
25
26 class IpamSubnetManager(object):
27
28     @classmethod
29     def load_by_neutron_subnet_id(cls, session, neutron_subnet_id):
30         return session.query(db_models.IpamSubnet).filter_by(
31             neutron_subnet_id=neutron_subnet_id).first()
32
33     def __init__(self, ipam_subnet_id, neutron_subnet_id):
34         self._ipam_subnet_id = ipam_subnet_id
35         self._neutron_subnet_id = neutron_subnet_id
36
37     @property
38     def neutron_id(self):
39         return self._neutron_subnet_id
40
41     def create(self, session):
42         """Create database models for an IPAM subnet.
43
44         This method creates a subnet resource for the IPAM driver and
45         associates it with its neutron identifier, if specified.
46
47         :param session: database sesssion.
48         :returns: the idenfier of created IPAM subnet
49         """
50         if not self._ipam_subnet_id:
51             self._ipam_subnet_id = uuidutils.generate_uuid()
52         ipam_subnet = db_models.IpamSubnet(
53             id=self._ipam_subnet_id,
54             neutron_subnet_id=self._neutron_subnet_id)
55         session.add(ipam_subnet)
56         return self._ipam_subnet_id
57
58     @classmethod
59     def delete(cls, session, neutron_subnet_id):
60         """Delete IPAM subnet.
61
62         IPAM subnet no longer has foreign key to neutron subnet,
63         so need to perform delete manually
64
65         :param session: database sesssion
66         :param neutron_subnet_id: neutron subnet id associated with ipam subnet
67         """
68         return session.query(db_models.IpamSubnet).filter_by(
69             neutron_subnet_id=neutron_subnet_id).delete()
70
71     def create_pool(self, session, pool_start, pool_end):
72         """Create an allocation pool and availability ranges for the subnet.
73
74         This method does not perform any validation on parameters; it simply
75         persist data on the database.
76
77         :param pool_start: string expressing the start of the pool
78         :param pool_end: string expressing the end of the pool
79         :return: the newly created pool object.
80         """
81         ip_pool = db_models.IpamAllocationPool(
82             ipam_subnet_id=self._ipam_subnet_id,
83             first_ip=pool_start,
84             last_ip=pool_end)
85         session.add(ip_pool)
86         ip_range = db_models.IpamAvailabilityRange(
87             allocation_pool=ip_pool,
88             first_ip=pool_start,
89             last_ip=pool_end)
90         session.add(ip_range)
91         return ip_pool
92
93     def delete_allocation_pools(self, session):
94         """Remove all allocation pools for the current subnet.
95
96         :param session: database session
97         """
98         session.query(db_models.IpamAllocationPool).filter_by(
99             ipam_subnet_id=self._ipam_subnet_id).delete()
100
101     def list_pools(self, session):
102         """Return pools for the current subnet."""
103         return session.query(
104             db_models.IpamAllocationPool).filter_by(
105             ipam_subnet_id=self._ipam_subnet_id)
106
107     def _range_query(self, session):
108         return session.query(
109             db_models.IpamAvailabilityRange).join(
110             db_models.IpamAllocationPool).filter_by(
111             ipam_subnet_id=self._ipam_subnet_id)
112
113     def get_first_range(self, session):
114         """Return the first availability range for the subnet
115
116         :param session: database session
117         :return: first available range as instance of
118             neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
119         """
120         return self._range_query(session).first()
121
122     def list_ranges_by_subnet_id(self, session):
123         """Return availability ranges for a given ipam subnet
124
125         :param session: database session
126         :return: list of availability ranges as instances of
127             neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
128         """
129         return self._range_query(session)
130
131     def list_ranges_by_allocation_pool(self, session, allocation_pool_id):
132         """Return availability ranges for a given pool.
133
134         :param session: database session
135         :param allocation_pool_id: allocation pool identifier
136         :return: list of availability ranges as instances of
137             neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
138         """
139         return session.query(
140             db_models.IpamAvailabilityRange).join(
141             db_models.IpamAllocationPool).filter_by(
142             id=allocation_pool_id)
143
144     def update_range(self, session, db_range, first_ip=None, last_ip=None):
145         """Updates db_range to have new first_ip and last_ip.
146
147         :param session: database session
148         :param db_range: IpamAvailabilityRange db object
149         :param first_ip: first ip address in range
150         :param last_ip: last ip address in range
151         :return: count of updated rows
152         """
153         opts = {}
154         if first_ip:
155             opts['first_ip'] = str(first_ip)
156         if last_ip:
157             opts['last_ip'] = str(last_ip)
158         if not opts:
159             raise ipam_exc.IpamAvailabilityRangeNoChanges()
160         try:
161             return session.query(
162                 db_models.IpamAvailabilityRange).filter_by(
163                 allocation_pool_id=db_range.allocation_pool_id).filter_by(
164                 first_ip=db_range.first_ip).filter_by(
165                 last_ip=db_range.last_ip).update(opts)
166         except orm_exc.ObjectDeletedError:
167             raise db_exc.RetryRequest(ipam_exc.IPAllocationFailed)
168
169     def delete_range(self, session, db_range):
170         """Return count of deleted ranges
171
172         :param session: database session
173         :param db_range: IpamAvailabilityRange db object
174         """
175         try:
176             return session.query(
177                 db_models.IpamAvailabilityRange).filter_by(
178                 allocation_pool_id=db_range.allocation_pool_id).filter_by(
179                 first_ip=db_range.first_ip).filter_by(
180                 last_ip=db_range.last_ip).delete()
181         except orm_exc.ObjectDeletedError:
182             raise db_exc.RetryRequest(ipam_exc.IPAllocationFailed)
183
184     def create_range(self, session, allocation_pool_id,
185                      range_start, range_end):
186         """Create an availability range for a given pool.
187
188         This method does not perform any validation on parameters; it simply
189         persist data on the database.
190
191         :param session: database session
192         :param allocation_pool_id: allocation pool identifier
193         :param range_start: first ip address in the range
194         :param range_end: last ip address in the range
195         :return: the newly created availability range as an instance of
196             neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
197         """
198         new_ip_range = db_models.IpamAvailabilityRange(
199             allocation_pool_id=allocation_pool_id,
200             first_ip=range_start,
201             last_ip=range_end)
202         session.add(new_ip_range)
203         return new_ip_range
204
205     def check_unique_allocation(self, session, ip_address):
206         """Validate that the IP address on the subnet is not in use."""
207         iprequest = session.query(db_models.IpamAllocation).filter_by(
208             ipam_subnet_id=self._ipam_subnet_id, status='ALLOCATED',
209             ip_address=ip_address).first()
210         if iprequest:
211             return False
212         return True
213
214     def list_allocations(self, session, status='ALLOCATED'):
215         """Return current allocations for the subnet.
216
217         :param session: database session
218         :param status: IP allocation status
219         :returns: a list of IP allocation as instance of
220             neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAllocation
221         """
222         return session.query(
223             db_models.IpamAllocation).filter_by(
224             ipam_subnet_id=self._ipam_subnet_id,
225             status=status)
226
227     def create_allocation(self, session, ip_address,
228                           status='ALLOCATED'):
229         """Create an IP allocation entry.
230
231         :param session: database session
232         :param ip_address: the IP address to allocate
233         :param status: IP allocation status
234         """
235         ip_request = db_models.IpamAllocation(
236             ip_address=ip_address,
237             status=status,
238             ipam_subnet_id=self._ipam_subnet_id)
239         session.add(ip_request)
240
241     def delete_allocation(self, session, ip_address):
242         """Remove an IP allocation for this subnet.
243
244         :param session: database session
245         :param ip_address: IP address for which the allocation entry should
246             be removed.
247         """
248         return session.query(db_models.IpamAllocation).filter_by(
249             ip_address=ip_address,
250             ipam_subnet_id=self._ipam_subnet_id).delete(
251                 synchronize_session=False)