Merge "Update logic when a port is added for live migration"

changes/95/858095/1
Zuul 9 months ago committed by Gerrit Code Review
commit 9232803226
  1. 46
      neutron/plugins/ml2/drivers/zvm/mech_zvm.py
  2. 13
      neutron/plugins/zvm/agent/zvm_neutron_agent.py
  3. 37
      neutron/tests/unit/plugins/ml2/zvm/test_mech_zvm.py
  4. 18
      neutron/tests/unit/plugins/zvm/test_zvm_neutron_agent.py

@ -14,15 +14,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants
from neutron_lib.plugins import directory
from oslo_log import log as logging
from neutron.plugins.ml2.drivers import mech_agent
LOG = logging.getLogger(__name__)
AGENT_TYPE_ZVM = 'z/VM agent'
VIF_TYPE_ZVM = 'zvm'
MIGRATING_ATTR = 'migrating_to'
class ZvmMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
@ -39,6 +44,13 @@ class ZvmMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
AGENT_TYPE_ZVM,
VIF_TYPE_ZVM,
{portbindings.CAP_PORT_FILTER: False})
self._plugin_property = None
@property
def _plugin(self):
if self._plugin_property is None:
self._plugin_property = directory.get_plugin()
return self._plugin_property
def get_allowed_network_types(self, agent=None):
return [constants.TYPE_LOCAL, constants.TYPE_FLAT,
@ -46,3 +58,37 @@ class ZvmMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
def get_mappings(self, agent):
return agent['configurations'].get('vswitch_mappings', {})
def update_port_postcommit(self, context):
"""Update a port.
:param context: PortContext instance describing the new
state of the port, as well as the original state prior
to the update_port call.
Called after the transaction completes. Call can block, though
will block the entire process so care should be taken to not
drastically affect performance. Raising an exception will
result in the deletion of the resource.
update_port_postcommit is called for all changes to the port
state. It is up to the mechanism driver to ignore state or
state changes that it does not know or care about.
For zvm mechnism driver, this action is taken to update
a port to active after live migration happens.
"""
port = copy.deepcopy(context.current)
original_port = copy.deepcopy(context.original)
if (port['status'] == constants.PORT_STATUS_DOWN and
port[portbindings.VIF_TYPE] == VIF_TYPE_ZVM and
(MIGRATING_ATTR in port[portbindings.PROFILE].keys() or
MIGRATING_ATTR in original_port[portbindings.PROFILE].keys())):
LOG.info("Setting port %s status from DOWN to UP after "
"migration completes.",
port['id'])
self._plugin.update_port_status(context._plugin_context,
port['id'],
constants.PORT_STATUS_ACTIVE)
return

@ -23,6 +23,7 @@ from neutron_lib import constants as q_const
from neutron_lib import context
from neutron_lib.utils import helpers
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_service import loopingcall
from neutron.agent import rpc as agent_rpc
@ -113,6 +114,18 @@ class zvmNeutronAgent(object):
LOG.info("Update received for old port. UUID: %s", port)
# For migrated VM, no need do couple nic operation
profile = port.get('binding:profile')
if profile:
profile = (jsonutils.loads(profile) if isinstance(profile, str)
else profile)
migrating_to = profile.get('migrating_to')
if migrating_to:
# Do nothing, because a migration is just started
LOG.info('Port %(id)s is being migrated to host %(host)s.',
{'id': port['id'], 'host': migrating_to})
return
vswitch = self._port_map[port['id']]['vswitch']
userid = self._port_map[port['id']]['userid']
vlan_id = self._port_map[port['id']].get('vlan_id')

@ -20,12 +20,19 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron.plugins.ml2.drivers.zvm import mech_zvm
from neutron.tests.unit import fake_resources as fakes
from neutron.tests.unit.plugins.ml2 import _test_mech_agent as base
from neutron.tests.unit.plugins.ml2 import test_plugin
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants as const
class ZvmMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
class ZvmMechanismBaseTestCase(base.AgentMechanismBaseTestCase,
test_plugin.Ml2PluginV2TestCase):
VIF_TYPE = mech_zvm.VIF_TYPE_ZVM
CAP_PORT_FILTER = False
AGENT_TYPE = mech_zvm.AGENT_TYPE_ZVM
@ -73,3 +80,31 @@ class ZvmvMechanismFlatTestCase(ZvmMechanismBaseTestCase,
class ZvmvMechanismVlanTestCase(ZvmMechanismBaseTestCase,
base.AgentMechanismVlanTestCase):
pass
class TestZvmMechanismDriver(ZvmMechanismBaseTestCase):
def test_update_port_postcommit(self):
fake_port = fakes.FakePort.create_one_port(
attrs={'status': const.PORT_STATUS_ACTIVE}).info()
fake_ctx = mock.Mock(current=fake_port, original=fake_port)
self.driver._plugin.update_port_status = mock.Mock()
self.driver.update_port_postcommit(fake_ctx)
self.driver._plugin.update_port_status.assert_not_called()
def test_update_port_postcommit_live_migration(self):
fake_context = 'fake_context'
fake_port = fakes.FakePort.create_one_port(
attrs={
'status': const.PORT_STATUS_DOWN,
portbindings.PROFILE: {mech_zvm.MIGRATING_ATTR: 'foo'},
portbindings.VIF_TYPE: mech_zvm.VIF_TYPE_ZVM}).info()
fake_ctx = mock.Mock(current=fake_port, original=fake_port,
_plugin_context=fake_context)
self.driver._plugin.update_port_status = mock.Mock()
self.driver.update_port_postcommit(fake_ctx)
self.driver._plugin.update_port_status.assert_called_once_with(
fake_context, fake_port['id'], const.PORT_STATUS_ACTIVE)

@ -226,6 +226,24 @@ class TestZVMNeutronAgent(base.BaseTestCase):
'admin_state_up': False})
self.assertTrue(rpc.called)
def test_port_update_migration(self):
sdk_req_resp = []
sdk_req_resp.append([{'userid': 'fake_user1', 'interface': '1000',
'switch': None, 'port': 'fake_uuid1',
'comments': None}])
sdk_req_resp.append('')
call_ret = mock.MagicMock(side_effect=sdk_req_resp)
with mock.patch.object(self.agent.plugin_rpc,
"update_device_up") as rpc:
with mock.patch.object(self.agent._requesthandler, "call",
call_ret):
self.agent.port_update(None,
port={'id': 'fake_uuid1',
'admin_state_up': True,
'binding:profile': {'migrating_to': 'TEST'}})
self.assertFalse(rpc.called)
def test_treat_vif_port_admin_true(self):
call_ret = mock.MagicMock(return_value=[
{'userid': 'fake_user', 'interface': 'nic',

Loading…
Cancel
Save