Enable deferred IP on Neutron ports
When booting a VM using an existing port, Nova checks that the port has fixed ips and fails if it doesn't. In the context of Neutron routed networks, a port may not have an IP address because address allocation was deferred. Neutron can communicate that this is ok through the ip_allocation attribute of the port added in the patch on which this one depends. In the absence of the ip_allocation attribute, Nova falls back to its previous behavior. Change-Id: I03f2e02377a743f4dd10ca12e6c31bb71ee36767 Depends-On: I591d32df512712e4de36fe20e389b3a14d58157f Depends-On: I8dc8890907d1e241dd12448fa184cea1b0620663 Partially-Implements: blueprint neutron-routed-networks
This commit is contained in:
parent
a0fcff8bad
commit
54b8d7770a
@ -420,8 +420,8 @@ class ServersController(wsgi.Controller):
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
if request.address is not None:
|
||||
msg = _("Specified Fixed IP '%(addr)s' cannot be used "
|
||||
"with port '%(port)s': port already has "
|
||||
"a Fixed IP allocated.") % {
|
||||
"with port '%(port)s': the two cannot be "
|
||||
"specified together.") % {
|
||||
"addr": request.address,
|
||||
"port": request.port_id}
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
@ -1413,7 +1413,12 @@ class API(base_api.NetworkAPI):
|
||||
neutron_client=neutron)
|
||||
if port.get('device_id', None):
|
||||
raise exception.PortInUse(port_id=request.port_id)
|
||||
if not port.get('fixed_ips'):
|
||||
deferred_ip = port.get('ip_allocation') == 'deferred'
|
||||
# NOTE(carl_baldwin) A deferred IP port doesn't have an
|
||||
# address here. If it fails to get one later when nova
|
||||
# updates it with host info, Neutron will error which
|
||||
# raises an exception.
|
||||
if not deferred_ip and not port.get('fixed_ips'):
|
||||
raise exception.PortRequiresFixedIP(
|
||||
port_id=request.port_id)
|
||||
request.network_id = port['network_id']
|
||||
|
@ -419,7 +419,8 @@ class SecurityGroupAPI(security_group_base.SecurityGroupBase):
|
||||
def _has_security_group_requirements(self, port):
|
||||
port_security_enabled = port.get('port_security_enabled', True)
|
||||
has_ip = port.get('fixed_ips')
|
||||
if has_ip:
|
||||
deferred_ip = port.get('ip_allocation') == 'deferred'
|
||||
if has_ip or deferred_ip:
|
||||
return port_security_enabled
|
||||
return False
|
||||
|
||||
|
@ -73,7 +73,7 @@ class TestNeutronSecurityGroupsV21(
|
||||
def _create_port(self, **kwargs):
|
||||
body = {'port': {'binding:vnic_type': model.VNIC_TYPE_NORMAL}}
|
||||
fields = ['security_groups', 'device_id', 'network_id',
|
||||
'port_security_enabled']
|
||||
'port_security_enabled', 'ip_allocation']
|
||||
for field in fields:
|
||||
if field in kwargs:
|
||||
body['port'][field] = kwargs[field]
|
||||
@ -278,6 +278,22 @@ class TestNeutronSecurityGroupsV21(
|
||||
self.manager._addSecurityGroup,
|
||||
req, UUID_SERVER, body)
|
||||
|
||||
def test_associate_deferred_ip_port(self):
|
||||
sg = self._create_sg_template().get('security_group')
|
||||
net = self._create_network()
|
||||
self._create_port(
|
||||
network_id=net['network']['id'], security_groups=[sg['id']],
|
||||
port_security_enabled=True, ip_allocation='deferred',
|
||||
device_id=UUID_SERVER)
|
||||
|
||||
self.stub_out('nova.db.instance_get_by_uuid',
|
||||
test_security_groups.return_server)
|
||||
body = dict(addSecurityGroup=dict(name="test"))
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/servers/%s/action' %
|
||||
UUID_SERVER)
|
||||
self.manager._addSecurityGroup(req, UUID_SERVER, body)
|
||||
|
||||
def test_disassociate_by_non_existing_security_group_name(self):
|
||||
self.stub_out('nova.db.instance_get_by_uuid',
|
||||
test_security_groups.return_server)
|
||||
@ -696,6 +712,7 @@ class MockClient(object):
|
||||
'admin_state_up': p.get('admin_state_up', True),
|
||||
'security_groups': p.get('security_groups', []),
|
||||
'network_id': p.get('network_id'),
|
||||
'ip_allocation': p.get('ip_allocation'),
|
||||
'binding:vnic_type':
|
||||
p.get('binding:vnic_type') or model.VNIC_TYPE_NORMAL}
|
||||
|
||||
@ -710,7 +727,7 @@ class MockClient(object):
|
||||
if not port_security and ret['security_groups']:
|
||||
raise exception.SecurityGroupCannotBeApplied()
|
||||
|
||||
if network['subnets']:
|
||||
if network['subnets'] and p.get('ip_allocation') != 'deferred':
|
||||
ret['fixed_ips'] = [{'subnet_id': network['subnets'][0],
|
||||
'ip_address': '10.0.0.1'}]
|
||||
if not ret['security_groups'] and (port_security is None or
|
||||
|
@ -3055,6 +3055,37 @@ class TestNeutronv2WithMock(test.TestCase):
|
||||
'fake-user', 'fake-project',
|
||||
auth_token='bff4a5a6b9eb4ea2a6efec6eefb77936')
|
||||
|
||||
@mock.patch('nova.network.neutronv2.api.API._show_port')
|
||||
def test_deferred_ip_port_immediate_allocation(self, mock_show):
|
||||
port = {'network_id': 'my_netid1',
|
||||
'device_id': None,
|
||||
'id': uuids.port,
|
||||
'fixed_ips': [], # no fixed ip
|
||||
'ip_allocation': 'immediate', }
|
||||
|
||||
mock_show.return_value = port
|
||||
|
||||
requested_networks = objects.NetworkRequestList(
|
||||
objects=[objects.NetworkRequest(port_id=port['id'])])
|
||||
self.assertRaises(exception.PortRequiresFixedIP,
|
||||
self.api.validate_networks,
|
||||
self.context, requested_networks, 1)
|
||||
|
||||
@mock.patch('nova.network.neutronv2.api.API._show_port')
|
||||
def test_deferred_ip_port_deferred_allocation(self, mock_show):
|
||||
port = {'network_id': 'my_netid1',
|
||||
'device_id': None,
|
||||
'id': uuids.port,
|
||||
'fixed_ips': [], # no fixed ip
|
||||
'ip_allocation': 'deferred', }
|
||||
|
||||
mock_show.return_value = port
|
||||
|
||||
requested_networks = objects.NetworkRequestList(
|
||||
objects=[objects.NetworkRequest(port_id=port['id'])])
|
||||
count = self.api.validate_networks(self.context, requested_networks, 1)
|
||||
self.assertEqual(1, count)
|
||||
|
||||
@mock.patch('oslo_concurrency.lockutils.lock')
|
||||
def test_get_instance_nw_info_locks_per_instance(self, mock_lock):
|
||||
instance = objects.Instance(uuid=uuid.uuid4())
|
||||
|
Loading…
Reference in New Issue
Block a user