1 # Copyright 2015 OpenStack LLC.
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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
16 from oslo_db import exception as db_exc
17 from oslo_utils import uuidutils
18 from sqlalchemy.orm import exc as orm_exc
20 from neutron.ipam.drivers.neutrondb_ipam import db_models
21 from neutron.ipam import exceptions as ipam_exc
23 # Database operations for Neutron's DB-backed IPAM driver
26 class IpamSubnetManager(object):
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()
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
39 return self._neutron_subnet_id
41 def create(self, session):
42 """Create database models for an IPAM subnet.
44 This method creates a subnet resource for the IPAM driver and
45 associates it with its neutron identifier, if specified.
47 :param session: database sesssion.
48 :returns: the idenfier of created IPAM subnet
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
59 def delete(cls, session, neutron_subnet_id):
60 """Delete IPAM subnet.
62 IPAM subnet no longer has foreign key to neutron subnet,
63 so need to perform delete manually
65 :param session: database sesssion
66 :param neutron_subnet_id: neutron subnet id associated with ipam subnet
68 return session.query(db_models.IpamSubnet).filter_by(
69 neutron_subnet_id=neutron_subnet_id).delete()
71 def create_pool(self, session, pool_start, pool_end):
72 """Create an allocation pool and availability ranges for the subnet.
74 This method does not perform any validation on parameters; it simply
75 persist data on the database.
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.
81 ip_pool = db_models.IpamAllocationPool(
82 ipam_subnet_id=self._ipam_subnet_id,
86 ip_range = db_models.IpamAvailabilityRange(
87 allocation_pool=ip_pool,
93 def delete_allocation_pools(self, session):
94 """Remove all allocation pools for the current subnet.
96 :param session: database session
98 session.query(db_models.IpamAllocationPool).filter_by(
99 ipam_subnet_id=self._ipam_subnet_id).delete()
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)
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)
113 def get_first_range(self, session):
114 """Return the first availability range for the subnet
116 :param session: database session
117 :return: first available range as instance of
118 neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
120 return self._range_query(session).first()
122 def list_ranges_by_subnet_id(self, session):
123 """Return availability ranges for a given ipam subnet
125 :param session: database session
126 :return: list of availability ranges as instances of
127 neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAvailabilityRange
129 return self._range_query(session)
131 def list_ranges_by_allocation_pool(self, session, allocation_pool_id):
132 """Return availability ranges for a given pool.
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
139 return session.query(
140 db_models.IpamAvailabilityRange).join(
141 db_models.IpamAllocationPool).filter_by(
142 id=allocation_pool_id)
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.
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
155 opts['first_ip'] = str(first_ip)
157 opts['last_ip'] = str(last_ip)
159 raise ipam_exc.IpamAvailabilityRangeNoChanges()
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)
169 def delete_range(self, session, db_range):
170 """Return count of deleted ranges
172 :param session: database session
173 :param db_range: IpamAvailabilityRange db object
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)
184 def create_range(self, session, allocation_pool_id,
185 range_start, range_end):
186 """Create an availability range for a given pool.
188 This method does not perform any validation on parameters; it simply
189 persist data on the database.
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
198 new_ip_range = db_models.IpamAvailabilityRange(
199 allocation_pool_id=allocation_pool_id,
200 first_ip=range_start,
202 session.add(new_ip_range)
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()
214 def list_allocations(self, session, status='ALLOCATED'):
215 """Return current allocations for the subnet.
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
222 return session.query(
223 db_models.IpamAllocation).filter_by(
224 ipam_subnet_id=self._ipam_subnet_id,
227 def create_allocation(self, session, ip_address,
229 """Create an IP allocation entry.
231 :param session: database session
232 :param ip_address: the IP address to allocate
233 :param status: IP allocation status
235 ip_request = db_models.IpamAllocation(
236 ip_address=ip_address,
238 ipam_subnet_id=self._ipam_subnet_id)
239 session.add(ip_request)
241 def delete_allocation(self, session, ip_address):
242 """Remove an IP allocation for this subnet.
244 :param session: database session
245 :param ip_address: IP address for which the allocation entry should
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)