Support reserve_resource in floatingip_plugin
Partially Implements: blueprint floatingip-reservation Change-Id: Ieb3e9d23f5d872552dbd7c23035587b0621ba367
This commit is contained in:
parent
ee8908cf77
commit
412787c4d0
|
@ -418,6 +418,77 @@ def host_get_all_by_queries_including_extracapabilities(queries):
|
||||||
return IMPL.host_get_all_by_queries_including_extracapabilities(queries)
|
return IMPL.host_get_all_by_queries_including_extracapabilities(queries)
|
||||||
|
|
||||||
|
|
||||||
|
# FloatingIP reservation
|
||||||
|
|
||||||
|
def fip_reservation_create(fip_reservation_values):
|
||||||
|
"""Create a floating IP reservation from the values."""
|
||||||
|
return IMPL.fip_reservation_create(fip_reservation_values)
|
||||||
|
|
||||||
|
|
||||||
|
@to_dict
|
||||||
|
def fip_reservation_get(fip_reservation_id):
|
||||||
|
"""Return specific floating IP reservation."""
|
||||||
|
return IMPL.fip_reservation_get(fip_reservation_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_reservation_update(fip_reservation_id, fip_reservation_values):
|
||||||
|
"""Update floating IP reservation."""
|
||||||
|
return IMPL.fip_reservation_update(fip_reservation_id,
|
||||||
|
fip_reservation_values)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_reservation_destroy(fip_reservation_id):
|
||||||
|
"""Delete specific floating ip reservation."""
|
||||||
|
return IMPL.fip_reservation_destroy(fip_reservation_id)
|
||||||
|
|
||||||
|
|
||||||
|
# Required FloatingIP
|
||||||
|
|
||||||
|
def required_fip_create(required_fip_values):
|
||||||
|
"""Create a required FIP address from the values."""
|
||||||
|
return IMPL.required_fip_create(required_fip_values)
|
||||||
|
|
||||||
|
|
||||||
|
@to_dict
|
||||||
|
def required_fip_get(required_fip_id):
|
||||||
|
"""Return specific required FIP."""
|
||||||
|
return IMPL.required_fip_get(required_fip_id)
|
||||||
|
|
||||||
|
|
||||||
|
def required_fip_update(required_fip_id, required_fip_values):
|
||||||
|
"""Update required FIP."""
|
||||||
|
return IMPL.required_fip_update(required_fip_id,
|
||||||
|
required_fip_values)
|
||||||
|
|
||||||
|
|
||||||
|
def required_fip_destroy(required_fip_id):
|
||||||
|
"""Delete specific required FIP."""
|
||||||
|
return IMPL.required_fip_destroy(required_fip_id)
|
||||||
|
|
||||||
|
|
||||||
|
# FloatingIP Allocation
|
||||||
|
|
||||||
|
def fip_allocation_create(allocation_values):
|
||||||
|
"""Create a floating ip allocation from the values."""
|
||||||
|
return IMPL.fip_allocation_create(allocation_values)
|
||||||
|
|
||||||
|
|
||||||
|
@to_dict
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
"""Returns all entries filtered by col=value."""
|
||||||
|
return IMPL.fip_allocation_get_all_by_values(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_destroy(allocation_id):
|
||||||
|
"""Delete specific floating ip allocation."""
|
||||||
|
IMPL.fip_allocation_destroy(allocation_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_update(allocation_id, allocation_values):
|
||||||
|
"""Update floating ip allocation."""
|
||||||
|
IMPL.fip_allocation_update(allocation_id, allocation_values)
|
||||||
|
|
||||||
|
|
||||||
# Floating ip
|
# Floating ip
|
||||||
|
|
||||||
def floatingip_create(values):
|
def floatingip_create(values):
|
||||||
|
@ -437,6 +508,12 @@ def floatingip_list():
|
||||||
return IMPL.floatingip_list()
|
return IMPL.floatingip_list()
|
||||||
|
|
||||||
|
|
||||||
|
@to_dict
|
||||||
|
def reservable_fip_get_all_by_queries(queries):
|
||||||
|
"""Returns reservable fips filtered by an array of queries."""
|
||||||
|
return IMPL.reservable_fip_get_all_by_queries(queries)
|
||||||
|
|
||||||
|
|
||||||
def floatingip_destroy(floatingip_id):
|
def floatingip_destroy(floatingip_id):
|
||||||
"""Delete specific floating ip."""
|
"""Delete specific floating ip."""
|
||||||
IMPL.floatingip_destroy(floatingip_id)
|
IMPL.floatingip_destroy(floatingip_id)
|
||||||
|
|
|
@ -830,6 +830,172 @@ def host_extra_capability_get_all_per_name(host_id, capability_name):
|
||||||
return query.filter_by(capability_name=capability_name).all()
|
return query.filter_by(capability_name=capability_name).all()
|
||||||
|
|
||||||
|
|
||||||
|
# FloatingIP reservation
|
||||||
|
|
||||||
|
def fip_reservation_create(fip_reservation_values):
|
||||||
|
values = fip_reservation_values.copy()
|
||||||
|
fip_reservation = models.FloatingIPReservation()
|
||||||
|
fip_reservation.update(values)
|
||||||
|
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
try:
|
||||||
|
fip_reservation.save(session=session)
|
||||||
|
except common_db_exc.DBDuplicateEntry as e:
|
||||||
|
# raise exception about duplicated columns (e.columns)
|
||||||
|
raise db_exc.BlazarDBDuplicateEntry(
|
||||||
|
model=fip_reservation.__class__.__name__, columns=e.columns)
|
||||||
|
|
||||||
|
return fip_reservation_get(fip_reservation.id)
|
||||||
|
|
||||||
|
|
||||||
|
def _fip_reservation_get(session, fip_reservation_id):
|
||||||
|
query = model_query(models.FloatingIPReservation, session)
|
||||||
|
return query.filter_by(id=fip_reservation_id).first()
|
||||||
|
|
||||||
|
|
||||||
|
def fip_reservation_get(fip_reservation_id):
|
||||||
|
return _fip_reservation_get(get_session(), fip_reservation_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_reservation_update(fip_reservation_id, fip_reservation_values):
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
fip_reservation = _fip_reservation_get(session, fip_reservation_id)
|
||||||
|
fip_reservation.update(fip_reservation_values)
|
||||||
|
fip_reservation.save(session=session)
|
||||||
|
|
||||||
|
return fip_reservation_get(fip_reservation_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_reservation_destroy(fip_reservation_id):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
fip_reservation = _fip_reservation_get(session, fip_reservation_id)
|
||||||
|
|
||||||
|
if not fip_reservation:
|
||||||
|
# raise not found error
|
||||||
|
raise db_exc.BlazarDBNotFound(
|
||||||
|
id=fip_reservation_id, model='FloatingIPReservation')
|
||||||
|
|
||||||
|
session.delete(fip_reservation)
|
||||||
|
|
||||||
|
|
||||||
|
# Required FIP
|
||||||
|
|
||||||
|
def required_fip_create(required_fip_values):
|
||||||
|
values = required_fip_values.copy()
|
||||||
|
required_fip = models.RequiredFloatingIP()
|
||||||
|
required_fip.update(values)
|
||||||
|
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
try:
|
||||||
|
required_fip.save(session=session)
|
||||||
|
except common_db_exc.DBDuplicateEntry as e:
|
||||||
|
# raise exception about duplicated columns (e.columns)
|
||||||
|
raise db_exc.BlazarDBDuplicateEntry(
|
||||||
|
model=required_fip.__class__.__name__, columns=e.columns)
|
||||||
|
|
||||||
|
return required_fip_get(required_fip.id)
|
||||||
|
|
||||||
|
|
||||||
|
def _required_fip_get(session, required_fip_id):
|
||||||
|
query = model_query(models.RequiredFloatingIP, session)
|
||||||
|
return query.filter_by(id=required_fip_id).first()
|
||||||
|
|
||||||
|
|
||||||
|
def required_fip_get(required_fip_id):
|
||||||
|
return _required_fip_get(get_session(), required_fip_id)
|
||||||
|
|
||||||
|
|
||||||
|
def required_fip_update(required_fip_id, required_fip_values):
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
required_fip = _required_fip_get(session, required_fip_id)
|
||||||
|
required_fip.update(required_fip_values)
|
||||||
|
required_fip.save(session=session)
|
||||||
|
|
||||||
|
return required_fip_get(required_fip_id)
|
||||||
|
|
||||||
|
|
||||||
|
def required_fip_destroy(required_fip_id):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
required_fip = _required_fip_get(session, required_fip_id)
|
||||||
|
|
||||||
|
if not required_fip:
|
||||||
|
# raise not found error
|
||||||
|
raise db_exc.BlazarDBNotFound(
|
||||||
|
id=required_fip_id, model='RequiredFloatingIP')
|
||||||
|
|
||||||
|
session.delete(required_fip)
|
||||||
|
|
||||||
|
|
||||||
|
# FloatingIP Allocation
|
||||||
|
|
||||||
|
def _fip_allocation_get(session, fip_allocation_id):
|
||||||
|
query = model_query(models.FloatingIPAllocation, session)
|
||||||
|
return query.filter_by(id=fip_allocation_id).first()
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_get(fip_allocation_id):
|
||||||
|
return _fip_allocation_get(get_session(), fip_allocation_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_create(allocation_values):
|
||||||
|
values = allocation_values.copy()
|
||||||
|
fip_allocation = models.FloatingIPAllocation()
|
||||||
|
fip_allocation.update(values)
|
||||||
|
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
try:
|
||||||
|
fip_allocation.save(session=session)
|
||||||
|
except common_db_exc.DBDuplicateEntry as e:
|
||||||
|
# raise exception about duplicated columns (e.columns)
|
||||||
|
raise db_exc.BlazarDBDuplicateEntry(
|
||||||
|
model=fip_allocation.__class__.__name__, columns=e.columns)
|
||||||
|
|
||||||
|
return fip_allocation_get(fip_allocation.id)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
"""Returns all entries filtered by col=value."""
|
||||||
|
allocation_query = model_query(models.FloatingIPAllocation, get_session())
|
||||||
|
for name, value in kwargs.items():
|
||||||
|
column = getattr(models.FloatingIPAllocation, name, None)
|
||||||
|
if column:
|
||||||
|
allocation_query = allocation_query.filter(column == value)
|
||||||
|
return allocation_query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_destroy(allocation_id):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
fip_allocation = _fip_allocation_get(session, allocation_id)
|
||||||
|
|
||||||
|
if not fip_allocation:
|
||||||
|
# raise not found error
|
||||||
|
raise db_exc.BlazarDBNotFound(
|
||||||
|
id=allocation_id, model='FloatingIPAllocation')
|
||||||
|
|
||||||
|
session.delete(fip_allocation)
|
||||||
|
|
||||||
|
|
||||||
|
def fip_allocation_update(allocation_id, allocation_values):
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
fip_allocation = _fip_allocation_get(session, allocation_id)
|
||||||
|
fip_allocation.update(allocation_values)
|
||||||
|
fip_allocation.save(session=session)
|
||||||
|
|
||||||
|
return fip_allocation_get(allocation_id)
|
||||||
|
|
||||||
|
|
||||||
# Floating IP
|
# Floating IP
|
||||||
def _floatingip_get(session, floatingip_id):
|
def _floatingip_get(session, floatingip_id):
|
||||||
query = model_query(models.FloatingIP, session)
|
query = model_query(models.FloatingIP, session)
|
||||||
|
@ -841,6 +1007,69 @@ def _floatingip_get_all(session):
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
def fip_get_all_by_queries(queries):
|
||||||
|
"""Returns Floating IPs filtered by an array of queries.
|
||||||
|
|
||||||
|
:param queries: array of queries "key op value" where op can be
|
||||||
|
http://docs.sqlalchemy.org/en/rel_0_7/core/expression_api.html
|
||||||
|
#sqlalchemy.sql.operators.ColumnOperators
|
||||||
|
|
||||||
|
"""
|
||||||
|
fips_query = model_query(models.FloatingIP, get_session())
|
||||||
|
|
||||||
|
oper = {
|
||||||
|
'<': ['lt', lambda a, b: a >= b],
|
||||||
|
'>': ['gt', lambda a, b: a <= b],
|
||||||
|
'<=': ['le', lambda a, b: a > b],
|
||||||
|
'>=': ['ge', lambda a, b: a < b],
|
||||||
|
'==': ['eq', lambda a, b: a != b],
|
||||||
|
'!=': ['ne', lambda a, b: a == b],
|
||||||
|
}
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
try:
|
||||||
|
key, op, value = query.split(' ', 2)
|
||||||
|
except ValueError:
|
||||||
|
raise db_exc.BlazarDBInvalidFilter(query_filter=query)
|
||||||
|
|
||||||
|
column = getattr(models.FloatingIP, key, None)
|
||||||
|
if column is not None:
|
||||||
|
if op == 'in':
|
||||||
|
filt = column.in_(value.split(','))
|
||||||
|
else:
|
||||||
|
if op in oper:
|
||||||
|
op = oper[op][0]
|
||||||
|
try:
|
||||||
|
attr = [e for e in ['%s', '%s_', '__%s__']
|
||||||
|
if hasattr(column, e % op)][0] % op
|
||||||
|
except IndexError:
|
||||||
|
raise db_exc.BlazarDBInvalidFilterOperator(
|
||||||
|
filter_operator=op)
|
||||||
|
|
||||||
|
if value == 'null':
|
||||||
|
value = None
|
||||||
|
|
||||||
|
filt = getattr(column, attr)(value)
|
||||||
|
|
||||||
|
fips_query = fips_query.filter(filt)
|
||||||
|
else:
|
||||||
|
raise db_exc.BlazarDBInvalidFilter(query_filter=query)
|
||||||
|
|
||||||
|
return fips_query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def reservable_fip_get_all_by_queries(queries):
|
||||||
|
"""Returns reservable fips filtered by an array of queries.
|
||||||
|
|
||||||
|
:param queries: array of queries "key op value" where op can be
|
||||||
|
http://docs.sqlalchemy.org/en/rel_0_7/core/expression_api.html
|
||||||
|
#sqlalchemy.sql.operators.ColumnOperators
|
||||||
|
|
||||||
|
"""
|
||||||
|
queries.append('reservable == 1')
|
||||||
|
return fip_get_all_by_queries(queries)
|
||||||
|
|
||||||
|
|
||||||
def floatingip_get(floatingip_id):
|
def floatingip_get(floatingip_id):
|
||||||
return _floatingip_get(get_session(), floatingip_id)
|
return _floatingip_get(get_session(), floatingip_id)
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,20 @@ def _get_leases_from_host_id(host_id, start_date, end_date):
|
||||||
yield lease
|
yield lease
|
||||||
|
|
||||||
|
|
||||||
|
def _get_leases_from_fip_id(fip_id, start_date, end_date):
|
||||||
|
session = get_session()
|
||||||
|
border0 = sa.and_(models.Lease.start_date < start_date,
|
||||||
|
models.Lease.end_date < start_date)
|
||||||
|
border1 = sa.and_(models.Lease.start_date > end_date,
|
||||||
|
models.Lease.end_date > end_date)
|
||||||
|
query = (session.query(models.Lease).join(models.Reservation)
|
||||||
|
.join(models.FloatingIPAllocation)
|
||||||
|
.filter(models.FloatingIPAllocation.floatingip_id == fip_id)
|
||||||
|
.filter(~sa.or_(border0, border1)))
|
||||||
|
for lease in query:
|
||||||
|
yield lease
|
||||||
|
|
||||||
|
|
||||||
def get_reservations_by_host_id(host_id, start_date, end_date):
|
def get_reservations_by_host_id(host_id, start_date, end_date):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
border0 = sa.and_(models.Lease.start_date < start_date,
|
border0 = sa.and_(models.Lease.start_date < start_date,
|
||||||
|
@ -115,12 +129,14 @@ def get_plugin_reservation(resource_type, resource_id):
|
||||||
raise mgr_exceptions.UnsupportedResourceType(resource_type)
|
raise mgr_exceptions.UnsupportedResourceType(resource_type)
|
||||||
|
|
||||||
|
|
||||||
def get_free_periods(resource_id, start_date, end_date, duration):
|
def get_free_periods(resource_id, start_date, end_date, duration,
|
||||||
|
resource_type='host'):
|
||||||
"""Returns a list of free periods."""
|
"""Returns a list of free periods."""
|
||||||
reserved_periods = get_reserved_periods(resource_id,
|
reserved_periods = get_reserved_periods(resource_id,
|
||||||
start_date,
|
start_date,
|
||||||
end_date,
|
end_date,
|
||||||
duration)
|
duration,
|
||||||
|
resource_type=resource_type)
|
||||||
free_periods = []
|
free_periods = []
|
||||||
previous = (start_date, start_date)
|
previous = (start_date, start_date)
|
||||||
if len(reserved_periods) >= 1:
|
if len(reserved_periods) >= 1:
|
||||||
|
@ -137,10 +153,17 @@ def get_free_periods(resource_id, start_date, end_date, duration):
|
||||||
return free_periods
|
return free_periods
|
||||||
|
|
||||||
|
|
||||||
def _get_events(host_id, start_date, end_date):
|
def _get_events(resource_id, start_date, end_date, resource_type):
|
||||||
"""Create a list of events."""
|
"""Create a list of events."""
|
||||||
events = {}
|
events = {}
|
||||||
for lease in _get_leases_from_host_id(host_id, start_date, end_date):
|
if resource_type == 'host':
|
||||||
|
leases = _get_leases_from_host_id(resource_id, start_date, end_date)
|
||||||
|
elif resource_type == 'floatingip':
|
||||||
|
leases = _get_leases_from_fip_id(resource_id, start_date, end_date)
|
||||||
|
else:
|
||||||
|
mgr_exceptions.UnsupportedResourceType(resource_type)
|
||||||
|
|
||||||
|
for lease in leases:
|
||||||
if lease.start_date < start_date:
|
if lease.start_date < start_date:
|
||||||
min_date = start_date
|
min_date = start_date
|
||||||
else:
|
else:
|
||||||
|
@ -202,26 +225,30 @@ def _merge_periods(reserved_periods, start_date, end_date, duration):
|
||||||
return merged_reserved_periods
|
return merged_reserved_periods
|
||||||
|
|
||||||
|
|
||||||
def get_reserved_periods(host_id, start_date, end_date, duration):
|
def get_reserved_periods(resource_id, start_date, end_date, duration,
|
||||||
"""Returns a list of reserved periods for a host.
|
resource_type='host'):
|
||||||
|
"""Returns a list of reserved periods for a resource.
|
||||||
|
|
||||||
The get_reserved_periods function returns a list of periods during which
|
The get_reserved_periods function returns a list of periods during which
|
||||||
the host passed as parameter is reserved. The duration parameter allows to
|
the resource passed as parameter is reserved. The duration parameter
|
||||||
choose the minimum length of time for a period to be considered free.
|
allows to choose the minimum length of time for a period to be
|
||||||
|
considered free.
|
||||||
|
|
||||||
:param host_id: the host to consider
|
:param resource_id: the resource to consider
|
||||||
:param start_date: start datetime of the entire period to consider
|
:param start_date: start datetime of the entire period to consider
|
||||||
:param end_date: end datetime of the entire period to consider
|
:param end_date: end datetime of the entire period to consider
|
||||||
:param duration: minimum length of time for a period to be considered free
|
:param duration: minimum length of time for a period to be considered free
|
||||||
:returns: the list of reserved periods for the host, expressed as a list of
|
:param resource_type: A type of resource to consider
|
||||||
two-element tuples, where the first element is the start datetime
|
:returns: the list of reserved periods for the resource, expressed as a
|
||||||
of the reserved period and the second is the end datetime
|
list of two-element tuples, where the first element is the start
|
||||||
|
datetime of the reserved period and the second is
|
||||||
|
the end datetime
|
||||||
"""
|
"""
|
||||||
capacity = 1 # The resource status is binary (free or reserved)
|
capacity = 1 # The resource status is binary (free or reserved)
|
||||||
quantity = 1 # One reservation per host at the same time
|
quantity = 1 # One reservation per host at the same time
|
||||||
if end_date - start_date < duration:
|
if end_date - start_date < duration:
|
||||||
return [(start_date, end_date)]
|
return [(start_date, end_date)]
|
||||||
events = _get_events(host_id, start_date, end_date)
|
events = _get_events(resource_id, start_date, end_date, resource_type)
|
||||||
reserved_periods = _find_reserved_periods(events, quantity, capacity)
|
reserved_periods = _find_reserved_periods(events, quantity, capacity)
|
||||||
return _merge_periods(reserved_periods, start_date, end_date, duration)
|
return _merge_periods(reserved_periods, start_date, end_date, duration)
|
||||||
|
|
||||||
|
|
|
@ -124,15 +124,18 @@ def get_plugin_reservation(resource_type, resource_id):
|
||||||
return IMPL.get_plugin_reservation(resource_type, resource_id)
|
return IMPL.get_plugin_reservation(resource_type, resource_id)
|
||||||
|
|
||||||
|
|
||||||
def get_free_periods(resource_id, start_date, end_date, duration):
|
def get_free_periods(resource_id, start_date, end_date, duration,
|
||||||
|
resource_type='host'):
|
||||||
"""Returns a list of free periods."""
|
"""Returns a list of free periods."""
|
||||||
return IMPL.get_free_periods(resource_id, start_date, end_date, duration)
|
return IMPL.get_free_periods(resource_id, start_date, end_date, duration,
|
||||||
|
resource_type=resource_type)
|
||||||
|
|
||||||
|
|
||||||
def get_reserved_periods(resource_id, start_date, end_date, duration):
|
def get_reserved_periods(resource_id, start_date, end_date, duration,
|
||||||
|
resource_type='host'):
|
||||||
"""Returns a list of reserved periods."""
|
"""Returns a list of reserved periods."""
|
||||||
return IMPL.get_reserved_periods(resource_id, start_date, end_date,
|
return IMPL.get_reserved_periods(resource_id, start_date, end_date,
|
||||||
duration)
|
duration, resource_type=resource_type)
|
||||||
|
|
||||||
|
|
||||||
def reservation_ratio(resource_id, start_date, end_date):
|
def reservation_ratio(resource_id, start_date, end_date):
|
||||||
|
|
|
@ -202,3 +202,17 @@ class FloatingIPNotFound(exceptions.NotFound):
|
||||||
class CantDeleteFloatingIP(exceptions.BlazarException):
|
class CantDeleteFloatingIP(exceptions.BlazarException):
|
||||||
code = 409
|
code = 409
|
||||||
msg_fmt = _("Can't delete floating IP %(floatingip)s. %(msg)s")
|
msg_fmt = _("Can't delete floating IP %(floatingip)s. %(msg)s")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidIPFormat(exceptions.InvalidInput):
|
||||||
|
msg_fmt = _("IP address %(ip)s is invalid form.")
|
||||||
|
|
||||||
|
|
||||||
|
class TooLongFloatingIPs(exceptions.InvalidInput):
|
||||||
|
msg_fmt = _("Invalid values for required_floatingips and amount. "
|
||||||
|
"The amount must be equal to or longer than length of "
|
||||||
|
"required_floatingips.")
|
||||||
|
|
||||||
|
|
||||||
|
class NotEnoughFloatingIPAvailable(exceptions.InvalidInput):
|
||||||
|
msg_fmt = _("Not enough floating IPs available")
|
||||||
|
|
|
@ -12,17 +12,25 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import netutils
|
||||||
|
from oslo_utils import strutils
|
||||||
|
|
||||||
from blazar.db import api as db_api
|
from blazar.db import api as db_api
|
||||||
from blazar.db import exceptions as db_ex
|
from blazar.db import exceptions as db_ex
|
||||||
|
from blazar.db import utils as db_utils
|
||||||
from blazar import exceptions
|
from blazar import exceptions
|
||||||
from blazar.manager import exceptions as manager_ex
|
from blazar.manager import exceptions as manager_ex
|
||||||
from blazar.plugins import base
|
from blazar.plugins import base
|
||||||
from blazar.plugins import floatingips as plugin
|
from blazar.plugins import floatingips as plugin
|
||||||
from blazar.utils.openstack import neutron
|
from blazar.utils.openstack import neutron
|
||||||
|
from blazar.utils import plugins as plugins_utils
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,8 +41,58 @@ class FloatingIpPlugin(base.BasePlugin):
|
||||||
title = 'Floating IP Plugin'
|
title = 'Floating IP Plugin'
|
||||||
description = 'This plugin creates and assigns floating IPs.'
|
description = 'This plugin creates and assigns floating IPs.'
|
||||||
|
|
||||||
|
def check_params(self, values):
|
||||||
|
if 'network_id' not in values:
|
||||||
|
raise manager_ex.MissingParameter(param='network_id')
|
||||||
|
|
||||||
|
if 'amount' not in values:
|
||||||
|
raise manager_ex.MissingParameter(param='amount')
|
||||||
|
|
||||||
|
if not strutils.is_int_like(values['amount']):
|
||||||
|
raise manager_ex.MalformedParameter(param='amount')
|
||||||
|
|
||||||
|
# required_floatingips param is an optional parameter
|
||||||
|
fips = values.get('required_floatingips', [])
|
||||||
|
if not isinstance(fips, list):
|
||||||
|
manager_ex.MalformedParameter(param='required_floatingips')
|
||||||
|
|
||||||
|
for ip in fips:
|
||||||
|
if not (netutils.is_valid_ipv4(ip) or netutils.is_valid_ipv6(ip)):
|
||||||
|
raise manager_ex.InvalidIPFormat(ip=ip)
|
||||||
|
|
||||||
def reserve_resource(self, reservation_id, values):
|
def reserve_resource(self, reservation_id, values):
|
||||||
raise NotImplementedError
|
"""Create floating IP reservation."""
|
||||||
|
self.check_params(values)
|
||||||
|
|
||||||
|
required_fips = values.get('required_floatingips', [])
|
||||||
|
amount = int(values['amount'])
|
||||||
|
|
||||||
|
if len(required_fips) > amount:
|
||||||
|
raise manager_ex.TooLongFloatingIPs()
|
||||||
|
|
||||||
|
floatingip_ids = self._matching_fips(values['network_id'],
|
||||||
|
required_fips,
|
||||||
|
amount,
|
||||||
|
values['start_date'],
|
||||||
|
values['end_date'])
|
||||||
|
|
||||||
|
floatingip_rsrv_values = {
|
||||||
|
'reservation_id': reservation_id,
|
||||||
|
'network_id': values['network_id'],
|
||||||
|
'amount': amount
|
||||||
|
}
|
||||||
|
|
||||||
|
fip_reservation = db_api.fip_reservation_create(floatingip_rsrv_values)
|
||||||
|
for fip_address in required_fips:
|
||||||
|
fip_address_values = {
|
||||||
|
'address': fip_address,
|
||||||
|
'floatingip_reservation_id': fip_reservation['id']
|
||||||
|
}
|
||||||
|
db_api.required_fip_create(fip_address_values)
|
||||||
|
for fip_id in floatingip_ids:
|
||||||
|
db_api.fip_allocation_create({'floatingip_id': fip_id,
|
||||||
|
'reservation_id': reservation_id})
|
||||||
|
return fip_reservation['id']
|
||||||
|
|
||||||
def on_start(self, resource_id):
|
def on_start(self, resource_id):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -42,6 +100,54 @@ class FloatingIpPlugin(base.BasePlugin):
|
||||||
def on_end(self, resource_id):
|
def on_end(self, resource_id):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _matching_fips(self, network_id, fip_addresses, amount,
|
||||||
|
start_date, end_date):
|
||||||
|
filter_array = []
|
||||||
|
start_date_with_margin = start_date - datetime.timedelta(
|
||||||
|
minutes=CONF.cleaning_time)
|
||||||
|
end_date_with_margin = end_date + datetime.timedelta(
|
||||||
|
minutes=CONF.cleaning_time)
|
||||||
|
|
||||||
|
fip_query = ["==", "$floating_network_id", network_id]
|
||||||
|
filter_array = plugins_utils.convert_requirements(fip_query)
|
||||||
|
|
||||||
|
fip_ids = []
|
||||||
|
not_allocated_fip_ids = []
|
||||||
|
allocated_fip_ids = []
|
||||||
|
for fip in db_api.reservable_fip_get_all_by_queries(filter_array):
|
||||||
|
if not db_api.fip_allocation_get_all_by_values(
|
||||||
|
floatingip_id=fip['id']):
|
||||||
|
if fip['floating_ip_address'] in fip_addresses:
|
||||||
|
fip_ids.append(fip['id'])
|
||||||
|
else:
|
||||||
|
not_allocated_fip_ids.append(fip['id'])
|
||||||
|
elif db_utils.get_free_periods(
|
||||||
|
fip['id'],
|
||||||
|
start_date_with_margin,
|
||||||
|
end_date_with_margin,
|
||||||
|
end_date_with_margin - start_date_with_margin,
|
||||||
|
resource_type='floatingip'
|
||||||
|
) == [
|
||||||
|
(start_date_with_margin, end_date_with_margin),
|
||||||
|
]:
|
||||||
|
if fip['floating_ip_address'] in fip_addresses:
|
||||||
|
fip_ids.append(fip['id'])
|
||||||
|
else:
|
||||||
|
allocated_fip_ids.append(fip['id'])
|
||||||
|
|
||||||
|
if len(fip_ids) != len(fip_addresses):
|
||||||
|
raise manager_ex.NotEnoughFloatingIPAvailable()
|
||||||
|
|
||||||
|
fip_ids += not_allocated_fip_ids
|
||||||
|
if len(fip_ids) >= amount:
|
||||||
|
return fip_ids[:amount]
|
||||||
|
|
||||||
|
fip_ids += allocated_fip_ids
|
||||||
|
if len(fip_ids) >= amount:
|
||||||
|
return fip_ids[:amount]
|
||||||
|
|
||||||
|
raise manager_ex.NotEnoughFloatingIPAvailable()
|
||||||
|
|
||||||
def validate_floatingip_params(self, values):
|
def validate_floatingip_params(self, values):
|
||||||
marshall_attributes = set(['floating_network_id',
|
marshall_attributes = set(['floating_network_id',
|
||||||
'floating_ip_address'])
|
'floating_ip_address'])
|
||||||
|
|
|
@ -12,20 +12,36 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
from blazar.db import api as db_api
|
from blazar.db import api as db_api
|
||||||
|
from blazar.db import utils as db_utils
|
||||||
from blazar.manager import exceptions as mgr_exceptions
|
from blazar.manager import exceptions as mgr_exceptions
|
||||||
|
from blazar.plugins import floatingips as plugin
|
||||||
from blazar.plugins.floatingips import floatingip_plugin
|
from blazar.plugins.floatingips import floatingip_plugin
|
||||||
from blazar import tests
|
from blazar import tests
|
||||||
from blazar.utils.openstack import exceptions as opst_exceptions
|
from blazar.utils.openstack import exceptions as opst_exceptions
|
||||||
from blazar.utils.openstack import neutron
|
from blazar.utils.openstack import neutron
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
class FloatingIpPluginTest(tests.TestCase):
|
class FloatingIpPluginTest(tests.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(FloatingIpPluginTest, self).setUp()
|
super(FloatingIpPluginTest, self).setUp()
|
||||||
|
|
||||||
|
self.cfg = cfg
|
||||||
|
|
||||||
|
# Make sure we clean up any override which could impact other tests
|
||||||
|
self.addCleanup(self.cfg.CONF.reset)
|
||||||
|
|
||||||
|
self.db_api = db_api
|
||||||
|
self.db_utils = db_utils
|
||||||
self.fip_pool = self.patch(neutron, 'FloatingIPPool')
|
self.fip_pool = self.patch(neutron, 'FloatingIPPool')
|
||||||
|
|
||||||
def test_create_floatingip(self):
|
def test_create_floatingip(self):
|
||||||
|
@ -143,3 +159,265 @@ class FloatingIpPluginTest(tests.TestCase):
|
||||||
self.assertRaises(mgr_exceptions.FloatingIPNotFound,
|
self.assertRaises(mgr_exceptions.FloatingIPNotFound,
|
||||||
fip_plugin.delete_floatingip,
|
fip_plugin.delete_floatingip,
|
||||||
'non-exists-id')
|
'non-exists-id')
|
||||||
|
|
||||||
|
def test_create_reservation_fips_available(self):
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
values = {
|
||||||
|
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||||
|
'network_id': u'f548089e-fb3e-4013-a043-c5ed809c7a67',
|
||||||
|
'start_date': datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
'end_date': datetime.datetime(2013, 12, 19, 21, 0),
|
||||||
|
'resource_type': plugin.RESOURCE_TYPE,
|
||||||
|
'amount': 2
|
||||||
|
}
|
||||||
|
matching_fips = self.patch(fip_plugin, '_matching_fips')
|
||||||
|
matching_fips.return_value = ['fip1', 'fip2']
|
||||||
|
fip_reservation_create = self.patch(self.db_api,
|
||||||
|
'fip_reservation_create')
|
||||||
|
fip_allocation_create = self.patch(
|
||||||
|
self.db_api, 'fip_allocation_create')
|
||||||
|
fip_plugin.reserve_resource(
|
||||||
|
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
values)
|
||||||
|
fip_values = {
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
'network_id': u'f548089e-fb3e-4013-a043-c5ed809c7a67',
|
||||||
|
'amount': 2
|
||||||
|
}
|
||||||
|
fip_reservation_create.assert_called_once_with(fip_values)
|
||||||
|
calls = [
|
||||||
|
mock.call(
|
||||||
|
{'floatingip_id': 'fip1',
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
}),
|
||||||
|
mock.call(
|
||||||
|
{'floatingip_id': 'fip2',
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
fip_allocation_create.assert_has_calls(calls)
|
||||||
|
|
||||||
|
def test_create_reservation_fips_with_required(self):
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
values = {
|
||||||
|
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||||
|
'network_id': u'f548089e-fb3e-4013-a043-c5ed809c7a67',
|
||||||
|
'start_date': datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
'end_date': datetime.datetime(2013, 12, 19, 21, 0),
|
||||||
|
'resource_type': plugin.RESOURCE_TYPE,
|
||||||
|
'amount': 2,
|
||||||
|
'required_floatingips': ['172.24.4.100']
|
||||||
|
}
|
||||||
|
matching_fips = self.patch(fip_plugin, '_matching_fips')
|
||||||
|
matching_fips.return_value = ['fip1', 'fip2']
|
||||||
|
fip_reservation_create = self.patch(self.db_api,
|
||||||
|
'fip_reservation_create')
|
||||||
|
fip_reservation_create.return_value = {'id': 'fip_resv_id1'}
|
||||||
|
fip_allocation_create = self.patch(
|
||||||
|
self.db_api, 'fip_allocation_create')
|
||||||
|
required_addr_create = self.patch(self.db_api, 'required_fip_create')
|
||||||
|
fip_plugin.reserve_resource(
|
||||||
|
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
values)
|
||||||
|
fip_values = {
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
'network_id': u'f548089e-fb3e-4013-a043-c5ed809c7a67',
|
||||||
|
'amount': 2
|
||||||
|
}
|
||||||
|
fip_reservation_create.assert_called_once_with(fip_values)
|
||||||
|
required_addr_create.assert_called_once_with(
|
||||||
|
{
|
||||||
|
'address': '172.24.4.100',
|
||||||
|
'floatingip_reservation_id': 'fip_resv_id1'
|
||||||
|
})
|
||||||
|
calls = [
|
||||||
|
mock.call(
|
||||||
|
{'floatingip_id': 'fip1',
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
}),
|
||||||
|
mock.call(
|
||||||
|
{'floatingip_id': 'fip2',
|
||||||
|
'reservation_id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
fip_allocation_create.assert_has_calls(calls)
|
||||||
|
|
||||||
|
def test_create_reservation_with_missing_param_network(self):
|
||||||
|
values = {
|
||||||
|
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||||
|
'amount': 2,
|
||||||
|
'start_date': datetime.datetime(2017, 3, 1, 20, 0),
|
||||||
|
'end_date': datetime.datetime(2017, 3, 2, 20, 0),
|
||||||
|
'resource_type': plugin.RESOURCE_TYPE,
|
||||||
|
}
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
self.assertRaises(
|
||||||
|
mgr_exceptions.MissingParameter,
|
||||||
|
fip_plugin.reserve_resource,
|
||||||
|
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
values)
|
||||||
|
|
||||||
|
def test_create_reservation_with_invalid_fip(self):
|
||||||
|
values = {
|
||||||
|
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||||
|
'network_id': u'a37a14f3-e3eb-4fe2-9e36-082b67f12ea0',
|
||||||
|
'amount': 2,
|
||||||
|
'required_floatingips': ['aaa.aaa.aaa.aaa'],
|
||||||
|
'start_date': datetime.datetime(2017, 3, 1, 20, 0),
|
||||||
|
'end_date': datetime.datetime(2017, 3, 2, 20, 0),
|
||||||
|
'resource_type': plugin.RESOURCE_TYPE,
|
||||||
|
}
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
self.assertRaises(
|
||||||
|
mgr_exceptions.InvalidIPFormat,
|
||||||
|
fip_plugin.reserve_resource,
|
||||||
|
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
values)
|
||||||
|
|
||||||
|
def test_create_reservation_required_bigger_than_amount(self):
|
||||||
|
values = {
|
||||||
|
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||||
|
'network_id': u'a37a14f3-e3eb-4fe2-9e36-082b67f12ea0',
|
||||||
|
'amount': 1,
|
||||||
|
'required_floatingips': ['172.24.4.100', '172.24.4.101'],
|
||||||
|
'start_date': datetime.datetime(2017, 3, 1, 20, 0),
|
||||||
|
'end_date': datetime.datetime(2017, 3, 2, 20, 0),
|
||||||
|
'resource_type': plugin.RESOURCE_TYPE,
|
||||||
|
}
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
self.assertRaises(
|
||||||
|
mgr_exceptions.TooLongFloatingIPs,
|
||||||
|
fip_plugin.reserve_resource,
|
||||||
|
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||||
|
values)
|
||||||
|
|
||||||
|
def test_matching_fips_not_allocated_fips(self):
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
if kwargs['floatingip_id'] == 'fip1':
|
||||||
|
return [{'id': 'allocation-id1'}]
|
||||||
|
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
fip_get = self.patch(self.db_api, 'reservable_fip_get_all_by_queries')
|
||||||
|
fip_get.return_value = [
|
||||||
|
{'id': 'fip1', 'floating_ip_address': '172.24.4.101'},
|
||||||
|
{'id': 'fip2', 'floating_ip_address': '172.24.4.102'},
|
||||||
|
{'id': 'fip3', 'floating_ip_address': '172.24.4.103'},
|
||||||
|
]
|
||||||
|
fip_get = self.patch(self.db_api, 'fip_allocation_get_all_by_values')
|
||||||
|
fip_get.side_effect = fip_allocation_get_all_by_values
|
||||||
|
fip_get = self.patch(self.db_utils, 'get_free_periods')
|
||||||
|
fip_get.return_value = [
|
||||||
|
(datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0)),
|
||||||
|
]
|
||||||
|
result = fip_plugin._matching_fips(
|
||||||
|
'network-id', [], 2,
|
||||||
|
datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0))
|
||||||
|
self.assertEqual(['fip2', 'fip3'], result)
|
||||||
|
|
||||||
|
def test_matching_fips_allocated_fips(self):
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
return [{'id': kwargs['floatingip_id']}]
|
||||||
|
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
fip_get = self.patch(self.db_api, 'reservable_fip_get_all_by_queries')
|
||||||
|
fip_get.return_value = [
|
||||||
|
{'id': 'fip1', 'floating_ip_address': '172.24.4.101'},
|
||||||
|
{'id': 'fip2', 'floating_ip_address': '172.24.4.102'},
|
||||||
|
{'id': 'fip3', 'floating_ip_address': '172.24.4.103'},
|
||||||
|
]
|
||||||
|
fip_get = self.patch(self.db_api, 'fip_allocation_get_all_by_values')
|
||||||
|
fip_get.side_effect = fip_allocation_get_all_by_values
|
||||||
|
fip_get = self.patch(self.db_utils, 'get_free_periods')
|
||||||
|
fip_get.return_value = [
|
||||||
|
(datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0)),
|
||||||
|
]
|
||||||
|
result = fip_plugin._matching_fips(
|
||||||
|
'network-id', [], 3,
|
||||||
|
datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0))
|
||||||
|
self.assertEqual(['fip1', 'fip2', 'fip3'], result)
|
||||||
|
|
||||||
|
def test_matching_fips_allocated_fips_with_required(self):
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
if kwargs['floatingip_id'] == 'fip1':
|
||||||
|
return [{'id': 'allocation-id1'}]
|
||||||
|
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
fip_get = self.patch(self.db_api, 'reservable_fip_get_all_by_queries')
|
||||||
|
fip_get.return_value = [
|
||||||
|
{'id': 'fip1', 'floating_ip_address': '172.24.4.101'},
|
||||||
|
{'id': 'fip2', 'floating_ip_address': '172.24.4.102'},
|
||||||
|
{'id': 'fip3', 'floating_ip_address': '172.24.4.103'},
|
||||||
|
{'id': 'fip4', 'floating_ip_address': '172.24.4.104'},
|
||||||
|
]
|
||||||
|
fip_get = self.patch(self.db_api, 'fip_allocation_get_all_by_values')
|
||||||
|
fip_get.side_effect = fip_allocation_get_all_by_values
|
||||||
|
fip_get = self.patch(self.db_utils, 'get_free_periods')
|
||||||
|
fip_get.return_value = [
|
||||||
|
(datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0)),
|
||||||
|
]
|
||||||
|
result = fip_plugin._matching_fips(
|
||||||
|
'network-id', ['172.24.4.102'], 4,
|
||||||
|
datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0))
|
||||||
|
# The order must be 1. required fips, 2. non-allocated fips,
|
||||||
|
# then 3. allocated fips
|
||||||
|
self.assertEqual(['fip2', 'fip3', 'fip4', 'fip1'], result)
|
||||||
|
|
||||||
|
def test_matching_fips_allocated_fips_with_cleaning_time(self):
|
||||||
|
def fip_allocation_get_all_by_values(**kwargs):
|
||||||
|
return [{'id': kwargs['floatingip_id']}]
|
||||||
|
|
||||||
|
self.cfg.CONF.set_override('cleaning_time', '5')
|
||||||
|
fip_get = self.patch(
|
||||||
|
self.db_api,
|
||||||
|
'reservable_fip_get_all_by_queries')
|
||||||
|
fip_get.return_value = [
|
||||||
|
{'id': 'fip1', 'floating_ip_address': '172.24.4.101'},
|
||||||
|
{'id': 'fip2', 'floating_ip_address': '172.24.4.102'},
|
||||||
|
{'id': 'fip3', 'floating_ip_address': '172.24.4.103'},
|
||||||
|
]
|
||||||
|
fip_get = self.patch(
|
||||||
|
self.db_api,
|
||||||
|
'fip_allocation_get_all_by_values')
|
||||||
|
fip_get.side_effect = fip_allocation_get_all_by_values
|
||||||
|
fip_get = self.patch(
|
||||||
|
self.db_utils,
|
||||||
|
'get_free_periods')
|
||||||
|
fip_get.return_value = [
|
||||||
|
(datetime.datetime(2013, 12, 19, 20, 0)
|
||||||
|
- datetime.timedelta(minutes=5),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0)
|
||||||
|
+ datetime.timedelta(minutes=5))
|
||||||
|
]
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
result = fip_plugin._matching_fips(
|
||||||
|
'network-id', [], 3,
|
||||||
|
datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0))
|
||||||
|
self.assertEqual(['fip1', 'fip2', 'fip3'], result)
|
||||||
|
start_mergin = (datetime.datetime(2013, 12, 19, 20, 0)
|
||||||
|
- datetime.timedelta(minutes=5))
|
||||||
|
end_mergin = (datetime.datetime(2013, 12, 19, 21, 0)
|
||||||
|
+ datetime.timedelta(minutes=5))
|
||||||
|
calls = [mock.call(fip, start_mergin, end_mergin,
|
||||||
|
end_mergin - start_mergin,
|
||||||
|
resource_type='floatingip')
|
||||||
|
for fip in ['fip1', 'fip2', 'fip3']]
|
||||||
|
fip_get.assert_has_calls(calls)
|
||||||
|
|
||||||
|
def test_matching_fips_not_matching(self):
|
||||||
|
fip_plugin = floatingip_plugin.FloatingIpPlugin()
|
||||||
|
fip_get = self.patch(
|
||||||
|
self.db_api,
|
||||||
|
'reservable_fip_get_all_by_queries')
|
||||||
|
fip_get.return_value = []
|
||||||
|
self.assertRaises(mgr_exceptions.NotEnoughFloatingIPAvailable,
|
||||||
|
fip_plugin._matching_fips,
|
||||||
|
'network-id', [], 2,
|
||||||
|
datetime.datetime(2013, 12, 19, 20, 0),
|
||||||
|
datetime.datetime(2013, 12, 19, 21, 0))
|
||||||
|
|
Loading…
Reference in New Issue