Local FIP not created after central FIP creation

1. What is the problem
After booting a VM, we associate a FIP to it via central Neutron.
However, local FIP is not created as expected. Also, there is no related
asynchronous job registered.

The reason may be that we don't trigger asynchronous job in
"create_floatingip" method, and since VM is already there, there's no
chance to trigger the job.

2. What is the solution for the problem
If "port_id" is specified in the body, trigger asynchronous job.

3. What features need to be implemented to the Tricircle to
realize the solution
Support creating FIP with "port_id" specified.

Change-Id: Iceb15f68acc23f8dcb8767ac0371947334a1e9db
Closes-Bug: #1691918
This commit is contained in:
zhiyuan_cai 2017-05-18 16:38:26 +08:00
parent 9bffb43330
commit 9897c65a26
4 changed files with 117 additions and 31 deletions

View File

@ -1733,10 +1733,35 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
return return_info
def create_floatingip(self, context, floatingip):
# create bottom fip when associating fixed ip
return super(TricirclePlugin, self).create_floatingip(
context, floatingip,
initial_status=constants.FLOATINGIP_STATUS_DOWN)
fip = None
t_ctx = t_context.get_context_from_neutron_context(context)
try:
fip = super(TricirclePlugin, self).create_floatingip(
context, floatingip,
initial_status=constants.FLOATINGIP_STATUS_DOWN)
if fip['router_id'] and fip['port_id']:
mappings = db_api.get_bottom_mappings_by_top_id(
t_ctx, fip['port_id'], t_constants.RT_PORT)
if not mappings:
# mapping does not exist, meaning that the bottom port has
# not been created, we just return and defer the work to
# setup bottom floating ip until vm creation
return
int_net_pod, b_int_port_id = mappings[0]
int_port = self.get_port(context, fip['port_id'])
net_id = int_port['network_id']
router = self._get_router(context, fip['router_id'])
self.xjob_handler.setup_bottom_router(
t_ctx, router['tenant_id'], net_id,
fip['router_id'], int_net_pod['pod_id'])
return fip
except Exception:
if fip:
# if we fail to register the job, delete the fip
super(TricirclePlugin, self).delete_floatingip(context,
fip['id'])
raise
def remove_router_interface(self, context, router_id, interface_info):
t_ctx = t_context.get_context_from_neutron_context(context)
@ -1875,8 +1900,8 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
t_ctx, int_port_id, t_constants.RT_PORT)
if not mappings:
# mapping does not exist, meaning that the bottom port has not
# been created, we just return and leave the work to setup bottom
# floating ip to nova api gateway
# been created, we just return and defer the work to setup bottom
# floating ip until vm creation
return
int_net_pod, b_int_port_id = mappings[0]

View File

@ -29,7 +29,8 @@ echo create router
router_id=$($openstacktop router create router -c id -f value)
echo attach router to external network
$openstacktop router set --external-gateway ext-net router
$openstacktop router set --external-gateway ext-net \
--fixed-ip subnet=ext-subnet,ip-address=163.3.124.10 router
echo create network1
$openstacktop network create net1
@ -52,7 +53,7 @@ echo attach subnet1 to router
$openstacktop router add subnet router subnet1
echo associate floating ip to port1
$openstacktop floating ip create --port $port1_id ext-net -c id -f value
$openstacktop floating ip create --port $port1_id --floating-ip-address 163.3.124.15 ext-net -c id -f value
image1_id=$($openstackpod1 image list -c ID -f value)
@ -60,15 +61,18 @@ echo create server1
$openstackpod1 server create --flavor 1 --image $image1_id --nic port-id=$port1_id vm1
echo create network2
net2_id=$($openstacktop network create net2 -c id -f value)
$openstacktop network create net2
echo create subnet2
$openstacktop subnet create --subnet-range 10.0.2.0/24 --network net2 subnet2
echo create port2
port2_id=$($openstacktop port create --network net2 port2 -c id -f value)
image2_id=$($openstackpod2 image list -c ID -f value)
echo create server2
$openstackpod2 server create --flavor 1 --image $image2_id --nic net-id=$net2_id vm2
$openstackpod2 server create --flavor 1 --image $image2_id --nic port-id=$port2_id vm2
echo attach subnet2 to router
$openstacktop router add subnet router subnet2
@ -83,6 +87,11 @@ $openstacktop subnet create --subnet-range 10.0.4.0/24 --network net4 \
echo create server3
$openstackpod1 server create --flavor 1 --image $image1_id --nic net-id=$net4_id vm3
sleep 10
echo associate floating ip to port2
$openstacktop floating ip create --port $port2_id --floating-ip-address 163.3.124.20 ext-net -c id -f value
sleep 20
TOP_DIR=$DEVSTACK_DIR
@ -171,3 +180,7 @@ $openstackpod2 router show $router_id -c routes -f json | python smoke_test_vali
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in router of RegionTwo"
fi
$openstackpod2 floating ip list -f json | python smoke_test_validation.py fip 2
if [ $? != 0 ]; then
die $LINENO "Smoke test fails, error in fip of RegionTwo"
fi

View File

@ -48,7 +48,9 @@ CONDITIONS = {
'router': [
{'routes': ContainedString(
"destination='0.0.0.0/0', gateway='100.0.0.1'")},
{'routes': ContainedString("destination='10.0.1")}]}
{'routes': ContainedString("destination='10.0.1")}],
'fip': [{'Floating IP Address': '163.3.124.15'},
{'Floating IP Address': '163.3.124.20'}]}
}

View File

@ -478,31 +478,39 @@ class FakeClient(test_utils.FakeClient):
pass
def update_floatingip_dict(fip_dict, update_dict):
if not update_dict.get('port_id'):
update_dict['fixed_port_id'] = None
update_dict['fixed_ip_address'] = None
update_dict['router_id'] = None
fip_dict.update(update_dict)
return fip_dict
for port in TOP_PORTS:
if port['id'] != update_dict['port_id']:
continue
update_dict['fixed_port_id'] = port['id']
update_dict[
'fixed_ip_address'] = port['fixed_ips'][0]['ip_address']
for router_port in TOP_ROUTERPORTS:
for _port in TOP_PORTS:
if _port['id'] != router_port['port_id']:
continue
if _port['network_id'] == port['network_id']:
update_dict['router_id'] = router_port['router_id']
fip_dict.update(update_dict)
return fip_dict
def update_floatingip(self, context, _id, floatingip):
for fip in TOP_FLOATINGIPS:
if fip['id'] != _id:
continue
update_dict = floatingip['floatingip']
if not floatingip['floatingip']['port_id']:
update_dict['fixed_port_id'] = None
update_dict['fixed_ip_address'] = None
update_dict['router_id'] = None
fip.update(update_dict)
return
for port in TOP_PORTS:
if port['id'] != floatingip['floatingip']['port_id']:
continue
update_dict['fixed_port_id'] = port['id']
update_dict[
'fixed_ip_address'] = port['fixed_ips'][0]['ip_address']
for router_port in TOP_ROUTERPORTS:
for _port in TOP_PORTS:
if _port['id'] != router_port['port_id']:
continue
if _port['network_id'] == port['network_id']:
update_dict['router_id'] = router_port['router_id']
update_floatingip_dict(fip, floatingip['floatingip'])
fip.update(update_dict)
def _update_fip_assoc(self, context, fip, floatingip_db, external_port):
return update_floatingip_dict(floatingip_db, fip)
class FakeBaseXManager(xmanager.XManager):
@ -2935,6 +2943,44 @@ class PluginTest(unittest.TestCase,
return t_port_id, b_port_id, fip, e_net
@patch.object(directory, 'get_plugin', new=fake_get_plugin)
@patch.object(driver.Pool, 'get_instance', new=fake_get_instance)
@patch.object(ipam_pluggable_backend.IpamPluggableBackend,
'_allocate_ips_for_port', new=fake_allocate_ips_for_port)
@patch.object(l3_db.L3_NAT_dbonly_mixin, '_make_router_dict',
new=fake_make_router_dict)
@patch.object(db_base_plugin_common.DbBasePluginCommon,
'_make_subnet_dict', new=fake_make_subnet_dict)
@patch.object(l3_db.L3_NAT_dbonly_mixin, '_update_fip_assoc',
new=_update_fip_assoc)
@patch.object(FakeClient, 'create_floatingips')
@patch.object(context, 'get_context_from_neutron_context')
def test_create_floatingip(self, mock_context, mock_create):
fake_plugin = FakePlugin()
q_ctx = FakeNeutronContext()
t_ctx = context.get_db_context()
mock_context.return_value = t_ctx
(t_port_id, b_port_id,
_, e_net) = self._prepare_associate_floatingip_test(t_ctx, q_ctx,
fake_plugin)
# in _prepare_associate_floatingip_test, we have created an empty fip,
# but here we just ignore it and create a new fip by specifying fix ip
# at the same time
fip_body = {'floating_network_id': e_net['id'],
'port_id': t_port_id,
'tenant_id': TEST_TENANT_ID}
fip = fake_plugin.create_floatingip(q_ctx, {'floatingip': fip_body})
b_ext_net_id = db_api.get_bottom_id_by_top_id_region_name(
t_ctx, e_net['id'], 'pod_2', constants.RT_NETWORK)
calls = [mock.call(t_ctx,
{'floatingip': {
'floating_network_id': b_ext_net_id,
'floating_ip_address': fip[
'floating_ip_address'],
'port_id': b_port_id}})]
mock_create.assert_has_calls(calls)
@patch.object(directory, 'get_plugin', new=fake_get_plugin)
@patch.object(driver.Pool, 'get_instance', new=fake_get_instance)
@patch.object(ipam_pluggable_backend.IpamPluggableBackend,