Support on_start and on_end method in FloatingIPPlugin class

Partially Implements: blueprint floatingip-reservation
Change-Id: I8628a567a431d21e92fc94987ecd49497618ddfb
This commit is contained in:
Masahito Muroi 2019-01-23 17:44:25 +09:00
parent 412787c4d0
commit 9e963f838f
4 changed files with 212 additions and 9 deletions

View File

@ -19,6 +19,7 @@ from oslo_log import log as logging
from oslo_utils import netutils
from oslo_utils import strutils
from blazar import context
from blazar.db import api as db_api
from blazar.db import exceptions as db_ex
from blazar.db import utils as db_utils
@ -95,10 +96,27 @@ class FloatingIpPlugin(base.BasePlugin):
return fip_reservation['id']
def on_start(self, resource_id):
raise NotImplementedError
fip_reservation = db_api.fip_reservation_get(resource_id)
allocations = db_api.fip_allocation_get_all_by_values(
reservation_id=fip_reservation['reservation_id'])
ctx = context.current()
fip_pool = neutron.FloatingIPPool(fip_reservation['network_id'])
for alloc in allocations:
fip = db_api.floatingip_get(alloc['floatingip_id'])
fip_pool.create_reserved_floatingip(
fip['subnet_id'], fip['floating_ip_address'],
ctx.project_id, fip_reservation['reservation_id'])
def on_end(self, resource_id):
raise NotImplementedError
fip_reservation = db_api.fip_reservation_get(resource_id)
allocations = db_api.fip_allocation_get_all_by_values(
reservation_id=fip_reservation['reservation_id'])
fip_pool = neutron.FloatingIPPool(fip_reservation['network_id'])
for alloc in allocations:
fip = db_api.floatingip_get(alloc['floatingip_id'])
fip_pool.delete_reserved_floatingip(fip['floating_ip_address'])
def _matching_fips(self, network_id, fip_addresses, amount,
start_date, end_date):

View File

@ -17,6 +17,7 @@ import datetime
import mock
from oslo_config import cfg
from blazar import context
from blazar.db import api as db_api
from blazar.db import utils as db_utils
from blazar.manager import exceptions as mgr_exceptions
@ -291,6 +292,65 @@ class FloatingIpPluginTest(tests.TestCase):
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
values)
def test_on_start(self):
fip_reservation_get = self.patch(self.db_api, 'fip_reservation_get')
fip_reservation_get.return_value = {
'reservation_id': 'reservation-id1',
'network_id': 'network-id1'
}
fip_allocation_get_all_by_values = self.patch(
self.db_api, 'fip_allocation_get_all_by_values'
)
fip_allocation_get_all_by_values.return_value = [{
'floatingip_id': 'fip-id',
}]
fip_get = self.patch(self.db_api, 'floatingip_get')
fip_get.return_value = {
'network_id': 'net-id',
'subnet_id': 'subnet-id',
'floating_ip_address': '172.2.24.100'
}
self.set_context(context.BlazarContext(project_id='fake-project-id'))
m = mock.MagicMock()
self.fip_pool.return_value = m
fip_plugin = floatingip_plugin.FloatingIpPlugin()
fip_plugin.on_start('resource-id1')
self.fip_pool.assert_called_once_with('network-id1')
m.create_reserved_floatingip.assert_called_once_with('subnet-id',
'172.2.24.100',
'fake-project-id',
'reservation-id1')
def test_on_end(self):
fip_reservation_get = self.patch(self.db_api, 'fip_reservation_get')
fip_reservation_get.return_value = {
'reservation_id': 'reservation-id1',
'network_id': 'network-id1'
}
fip_allocation_get_all_by_values = self.patch(
self.db_api, 'fip_allocation_get_all_by_values'
)
fip_allocation_get_all_by_values.return_value = [{
'floatingip_id': 'fip-id',
}]
fip_get = self.patch(self.db_api, 'floatingip_get')
fip_get.return_value = {
'network_id': 'net-id',
'subnet_id': 'subnet-id',
'floating_ip_address': '172.2.24.100'
}
self.set_context(context.BlazarContext(project_id='fake-project-id'))
m = mock.MagicMock()
self.fip_pool.return_value = m
fip_plugin = floatingip_plugin.FloatingIpPlugin()
fip_plugin.on_end('resource-id1')
self.fip_pool.assert_called_once_with('network-id1')
m.delete_reserved_floatingip.assert_called_once_with('172.2.24.100')
def test_matching_fips_not_allocated_fips(self):
def fip_allocation_get_all_by_values(**kwargs):
if kwargs['floatingip_id'] == 'fip1':

View File

@ -43,17 +43,102 @@ class TestBlazarNeutronClient(tests.TestCase):
class TestFloatingIPPool(tests.TestCase):
def setUp(self):
super(TestFloatingIPPool, self).setUp()
self.mock_net = self.patch(neutronclient.v2_0.client.Client,
'show_network')
self.mock_net.return_value = {'network': {'id': 'net-id'}}
@mock.patch.object(neutronclient.v2_0.client.Client, 'show_network')
def test_init_floatingippool(self, mock_net):
mock_net.return_value = {'network': {'id': 'net-id'}}
def test_init_floatingippool(self):
client = neutron.FloatingIPPool('net-id')
self.assertEqual('net-id', client.network_id)
mock_net.assert_called_once_with('net-id')
self.mock_net.assert_called_once_with('net-id')
@mock.patch.object(neutronclient.v2_0.client.Client, 'show_network')
def test_init_with_invalid_network_id(self, mock_net):
mock_net.side_effect = neutron_exceptions.NotFound()
def test_init_with_invalid_network_id(self):
self.mock_net.side_effect = neutron_exceptions.NotFound()
self.assertRaises(exceptions.FloatingIPNetworkNotFound,
neutron.FloatingIPPool, 'invalid-net-id')
@mock.patch.object(neutronclient.v2_0.client.Client, 'create_floatingip')
@mock.patch.object(neutronclient.v2_0.client.Client, 'replace_tag')
def test_create_reserved_floatingip(self, mock_tag, mock_fip):
mock_fip.return_value = {'floatingip': {'id': 'fip-id'}}
client = neutron.FloatingIPPool('net-id')
client.create_reserved_floatingip('subnet-id', '172.24.4.200',
'project-id', 'reservation-id')
expected_body = {
'floatingip': {
'floating_network_id': 'net-id',
'subnet_id': 'subnet-id',
'floating_ip_address': '172.24.4.200',
'project_id': 'project-id'
}
}
mock_fip.assert_called_once_with(expected_body)
mock_tag.assert_called_once_with(
'floatingips',
'fip-id',
{'tags': ['blazar', 'reservation:reservation-id']}
)
@mock.patch.object(neutronclient.v2_0.client.Client, 'list_floatingips')
@mock.patch.object(neutronclient.v2_0.client.Client, 'update_floatingip')
@mock.patch.object(neutronclient.v2_0.client.Client, 'delete_floatingip')
def test_delete_floatingip_with_deleted(self, mock_delete,
mock_update, mock_list):
mock_list.return_value = {'floatingips': []}
client = neutron.FloatingIPPool('net-id')
client.delete_reserved_floatingip('172.24.4.200')
query = {
'floating_ip_address': '172.24.4.200',
'floating_network_id': 'net-id'
}
mock_list.assert_called_once_with(**query)
mock_update.assert_not_called()
mock_delete.assert_not_called()
@mock.patch.object(neutronclient.v2_0.client.Client, 'list_floatingips')
@mock.patch.object(neutronclient.v2_0.client.Client, 'update_floatingip')
@mock.patch.object(neutronclient.v2_0.client.Client, 'delete_floatingip')
def test_delete_floatingip_with_associated(self, mock_delete,
mock_update, mock_list):
mock_list.return_value = {
'floatingips': [
{'port_id': 'port-id', 'id': 'fip-id'}
]}
client = neutron.FloatingIPPool('net-id')
client.delete_reserved_floatingip('172.24.4.200')
query = {
'floating_ip_address': '172.24.4.200',
'floating_network_id': 'net-id'
}
mock_list.assert_called_once_with(**query)
mock_update.assert_called_once_with('fip-id',
{'floatingip': {'port_id': None}})
mock_delete.assert_called_once_with('fip-id')
@mock.patch.object(neutronclient.v2_0.client.Client, 'list_floatingips')
@mock.patch.object(neutronclient.v2_0.client.Client, 'update_floatingip')
@mock.patch.object(neutronclient.v2_0.client.Client, 'delete_floatingip')
def test_delete_floatingip_with_deassociated(self, mock_delete,
mock_update, mock_list):
mock_list.return_value = {
'floatingips': [
{'port_id': None, 'id': 'fip-id'}
]}
client = neutron.FloatingIPPool('net-id')
client.delete_reserved_floatingip('172.24.4.200')
query = {
'floating_ip_address': '172.24.4.200',
'floating_network_id': 'net-id'
}
mock_list.assert_called_once_with(**query)
mock_update.assert_not_called()
mock_delete.assert_called_once_with('fip-id')

View File

@ -101,3 +101,43 @@ class FloatingIPPool(BlazarNeutronClient):
return subnet
raise exceptions.FloatingIPSubnetNotFound(fip=floatingip)
def create_reserved_floatingip(self, subnet_id, address, project_id,
reservation_id):
body = {
'floatingip': {
'floating_network_id': self.network_id,
'subnet_id': subnet_id,
'floating_ip_address': address,
'project_id': project_id
}
}
fip = self.neutron.create_floatingip(body)['floatingip']
body = {
'tags': ['blazar', 'reservation:%s' % reservation_id]
}
self.neutron.replace_tag('floatingips', fip['id'], body)
def delete_reserved_floatingip(self, address):
query = {
'floating_ip_address': address,
'floating_network_id': self.network_id
}
fips = self.neutron.list_floatingips(**query)['floatingips']
if not fips:
# The floating ip address already deleted by the user.
return None
fip = next(iter(fips))
if fip['port_id']:
# Deassociate the floating ip from the attached port because
# the delete floatingip API deletes both the floating ip and
# associated port.
body = {
'floatingip': {
'port_id': None,
}
}
self.neutron.update_floatingip(fip['id'], body)
self.neutron.delete_floatingip(fip['id'])