Add "activate_port_binding" neutron API method
This method will be needed to activate the inactive port binding for the destination host during post-live-migration. This is based on the neutron API spec: https://specs.openstack.org/openstack/neutron-specs/specs/backlog/pike/portbinding_information_for_nova.html#activating-an-inactive-binding And neutron ML2 plugin API code: https://review.openstack.org/414251/ Part of blueprint neutron-new-port-binding-api Change-Id: Ic9fe5ebd3433073b51e95b62867d5c1cd5f2cc8f
This commit is contained in:
parent
19c334b1d7
commit
c5356cb3d8
|
@ -880,6 +880,11 @@ class PortBindingDeletionFailed(NovaException):
|
|||
"%(host)s.")
|
||||
|
||||
|
||||
class PortBindingActivationFailed(NovaException):
|
||||
msg_fmt = _("Failed to activate binding for port %(port_id)s and host "
|
||||
"%(host)s.")
|
||||
|
||||
|
||||
class PortUpdateFailed(Invalid):
|
||||
msg_fmt = _("Port update failed for port %(port_id)s: %(reason)s")
|
||||
|
||||
|
|
|
@ -1284,6 +1284,44 @@ class API(base_api.NetworkAPI):
|
|||
raise exception.PortBindingDeletionFailed(
|
||||
port_id=port_id, host=host)
|
||||
|
||||
def activate_port_binding(self, context, port_id, host):
|
||||
"""Activates an inactive port binding.
|
||||
|
||||
If there are two port bindings to different hosts, activating the
|
||||
inactive binding atomically changes the other binding to inactive.
|
||||
|
||||
:param context: The request context for the operation.
|
||||
:param port_id: The ID of the port with an inactive binding on the
|
||||
host.
|
||||
:param host: The host on which the inactive port binding should be
|
||||
activated.
|
||||
:raises: nova.exception.PortBindingActivationFailed if a non-409 error
|
||||
response is received from neutron.
|
||||
"""
|
||||
client = _get_ksa_client(context, admin=True)
|
||||
# This is a bit weird in that we don't PUT and update the status
|
||||
# to ACTIVE, it's more like a POST action method in the compute API.
|
||||
resp = client.put(
|
||||
'/v2.0/ports/%s/bindings/%s/activate' % (port_id, host),
|
||||
raise_exc=False)
|
||||
if resp:
|
||||
LOG.debug('Activated binding for port %s and host %s.',
|
||||
port_id, host)
|
||||
else:
|
||||
# A 409 means the port binding is already active, which shouldn't
|
||||
# happen if the caller is doing things in the correct order.
|
||||
if resp.status_code == 409:
|
||||
LOG.warning('Binding for port %s and host %s is already '
|
||||
'active.', port_id, host)
|
||||
else:
|
||||
# Log the details, raise an exception.
|
||||
LOG.error('Unexpected error trying to activate binding '
|
||||
'for port %s and host %s. Code: %s. '
|
||||
'Error: %s', port_id, host, resp.status_code,
|
||||
resp.text)
|
||||
raise exception.PortBindingActivationFailed(
|
||||
port_id=port_id, host=host)
|
||||
|
||||
def _get_pci_device_profile(self, pci_dev):
|
||||
dev_spec = self.pci_whitelist.get_devspec(pci_dev)
|
||||
if dev_spec:
|
||||
|
|
|
@ -5464,6 +5464,43 @@ class TestPortBindingWithMock(test.NoDBTestCase):
|
|||
else:
|
||||
self.api.delete_port_binding(ctxt, port_id, 'fake-host')
|
||||
|
||||
@mock.patch('nova.network.neutronv2.api._get_ksa_client')
|
||||
def test_activate_port_binding(self, mock_client):
|
||||
"""Tests the happy path of activating an inactive port binding."""
|
||||
ctxt = context.get_context()
|
||||
resp = fake_req.FakeResponse(200)
|
||||
mock_client.return_value.put.return_value = resp
|
||||
self.api.activate_port_binding(ctxt, uuids.port_id, 'fake-host')
|
||||
mock_client.return_value.put.assert_called_once_with(
|
||||
'/v2.0/ports/%s/bindings/fake-host/activate' % uuids.port_id,
|
||||
raise_exc=False)
|
||||
|
||||
@mock.patch('nova.network.neutronv2.api._get_ksa_client')
|
||||
@mock.patch('nova.network.neutronv2.api.LOG.warning')
|
||||
def test_activate_port_binding_already_active(
|
||||
self, mock_log_warning, mock_client):
|
||||
"""Tests the 409 case of activating an already active port binding."""
|
||||
ctxt = context.get_context()
|
||||
mock_client.return_value.put.return_value = fake_req.FakeResponse(409)
|
||||
self.api.activate_port_binding(ctxt, uuids.port_id, 'fake-host')
|
||||
mock_client.return_value.put.assert_called_once_with(
|
||||
'/v2.0/ports/%s/bindings/fake-host/activate' % uuids.port_id,
|
||||
raise_exc=False)
|
||||
self.assertEqual(1, mock_log_warning.call_count)
|
||||
self.assertIn('is already active', mock_log_warning.call_args[0][0])
|
||||
|
||||
@mock.patch('nova.network.neutronv2.api._get_ksa_client')
|
||||
def test_activate_port_binding_fails(self, mock_client):
|
||||
"""Tests the unknown error case of binding activation."""
|
||||
ctxt = context.get_context()
|
||||
mock_client.return_value.put.return_value = fake_req.FakeResponse(500)
|
||||
self.assertRaises(exception.PortBindingActivationFailed,
|
||||
self.api.activate_port_binding,
|
||||
ctxt, uuids.port_id, 'fake-host')
|
||||
mock_client.return_value.put.assert_called_once_with(
|
||||
'/v2.0/ports/%s/bindings/fake-host/activate' % uuids.port_id,
|
||||
raise_exc=False)
|
||||
|
||||
|
||||
class TestAllocateForInstance(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue