Fixes Hyper-V agent RPC calls for ML2 support
Adds support for the RPC report status in the Hyper-V agent and plugin. Fixes bug: #1226654 Change-Id: Ie5eee875afc062c536856589d6a3fd0414190f6d
This commit is contained in:
parent
151cff7554
commit
3e10546c25
@ -25,11 +25,14 @@ import time
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.agent.common import config
|
||||
from neutron.agent import rpc as agent_rpc
|
||||
from neutron.common import config as logging_config
|
||||
from neutron.common import constants as n_const
|
||||
from neutron.common import topics
|
||||
from neutron import context
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import loopingcall
|
||||
from neutron.openstack.common.rpc import dispatcher
|
||||
from neutron.plugins.hyperv.agent import utils
|
||||
from neutron.plugins.hyperv.agent import utilsfactory
|
||||
@ -63,6 +66,7 @@ agent_opts = [
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(agent_opts, "AGENT")
|
||||
config.register_agent_state_opts_helper(cfg.CONF)
|
||||
|
||||
|
||||
class HyperVNeutronAgent(object):
|
||||
@ -74,13 +78,34 @@ class HyperVNeutronAgent(object):
|
||||
self._polling_interval = CONF.AGENT.polling_interval
|
||||
self._load_physical_network_mappings()
|
||||
self._network_vswitch_map = {}
|
||||
self._set_agent_state()
|
||||
self._setup_rpc()
|
||||
|
||||
def _set_agent_state(self):
|
||||
self.agent_state = {
|
||||
'binary': 'neutron-hyperv-agent',
|
||||
'host': cfg.CONF.host,
|
||||
'topic': n_const.L2_AGENT_TOPIC,
|
||||
'configurations': {'vswitch_mappings':
|
||||
self._physical_network_mappings},
|
||||
'agent_type': n_const.AGENT_TYPE_HYPERV,
|
||||
'start_flag': True}
|
||||
|
||||
def _report_state(self):
|
||||
try:
|
||||
self.state_rpc.report_state(self.context,
|
||||
self.agent_state)
|
||||
self.agent_state.pop('start_flag', None)
|
||||
except Exception as ex:
|
||||
LOG.exception(_("Failed reporting state! %s"), ex)
|
||||
|
||||
def _setup_rpc(self):
|
||||
self.agent_id = 'hyperv_%s' % platform.node()
|
||||
self.topic = topics.AGENT
|
||||
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)
|
||||
|
||||
self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN)
|
||||
|
||||
# RPC network init
|
||||
self.context = context.get_admin_context_without_session()
|
||||
# Handle updates from service
|
||||
@ -93,6 +118,10 @@ class HyperVNeutronAgent(object):
|
||||
self.connection = agent_rpc.create_consumers(self.dispatcher,
|
||||
self.topic,
|
||||
consumers)
|
||||
report_interval = CONF.AGENT.report_interval
|
||||
if report_interval:
|
||||
heartbeat = loopingcall.LoopingCall(self._report_state)
|
||||
heartbeat.start(interval=report_interval)
|
||||
|
||||
def _load_physical_network_mappings(self):
|
||||
self._physical_network_mappings = {}
|
||||
@ -103,14 +132,14 @@ class HyperVNeutronAgent(object):
|
||||
else:
|
||||
pattern = re.escape(parts[0].strip()).replace('\\*', '.*')
|
||||
vswitch = parts[1].strip()
|
||||
self._physical_network_mappings[re.compile(pattern)] = vswitch
|
||||
self._physical_network_mappings[pattern] = vswitch
|
||||
|
||||
def _get_vswitch_for_physical_network(self, phys_network_name):
|
||||
for compre in self._physical_network_mappings:
|
||||
for pattern in self._physical_network_mappings:
|
||||
if phys_network_name is None:
|
||||
phys_network_name = ''
|
||||
if compre.match(phys_network_name):
|
||||
return self._physical_network_mappings[compre]
|
||||
if re.match(pattern, phys_network_name):
|
||||
return self._physical_network_mappings[pattern]
|
||||
# Not found in the mappings, the vswitch has the same name
|
||||
return phys_network_name
|
||||
|
||||
|
@ -21,6 +21,7 @@ from oslo.config import cfg
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import exceptions as q_exc
|
||||
from neutron.common import topics
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import external_net_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
@ -143,7 +144,8 @@ class VlanNetworkProvider(BaseNetworkProvider):
|
||||
network[provider.SEGMENTATION_ID] = binding.segmentation_id
|
||||
|
||||
|
||||
class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
class HyperVNeutronPlugin(agents_db.AgentDbMixin,
|
||||
db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net_db.External_net_db_mixin,
|
||||
l3_gwmode_db.L3_NAT_db_mixin,
|
||||
portbindings_base.PortBindingBaseMixin):
|
||||
@ -153,7 +155,7 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# is qualified by class
|
||||
__native_bulk_support = True
|
||||
supported_extension_aliases = ["provider", "external-net", "router",
|
||||
"ext-gw-mode", "binding", "quotas"]
|
||||
"agent", "ext-gw-mode", "binding", "quotas"]
|
||||
|
||||
def __init__(self, configfile=None):
|
||||
self._db = hyperv_db.HyperVPluginDB()
|
||||
@ -165,7 +167,6 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
self._parse_network_vlan_ranges()
|
||||
self._create_network_providers_map()
|
||||
|
||||
self._db.sync_vlan_allocations(self._network_vlan_ranges)
|
||||
|
||||
self._setup_rpc()
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
from neutron.common import constants as q_const
|
||||
from neutron.common import rpc as q_rpc
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import dhcp_rpc_base
|
||||
from neutron.db import l3_rpc_base
|
||||
from neutron.openstack.common import log as logging
|
||||
@ -44,7 +45,8 @@ class HyperVRpcCallbacks(
|
||||
If a manager would like to set an rpc API version, or support more than
|
||||
one class as the target of rpc messages, override this method.
|
||||
'''
|
||||
return q_rpc.PluginRpcDispatcher([self])
|
||||
return q_rpc.PluginRpcDispatcher([self,
|
||||
agents_db.AgentExtRpcCallback()])
|
||||
|
||||
def get_device_details(self, rpc_context, **kwargs):
|
||||
"""Agent requests device details."""
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
|
||||
from neutron.common import constants
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.openstack.common import log
|
||||
@ -46,6 +48,10 @@ class HypervMechanismDriver(mech_agent.AgentMechanismDriverBase):
|
||||
if network_type == 'local':
|
||||
return True
|
||||
elif network_type in ['flat', 'vlan']:
|
||||
return segment[api.PHYSICAL_NETWORK] in mappings
|
||||
for pattern in mappings:
|
||||
if re.match(pattern, segment[api.PHYSICAL_NETWORK]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
@ -39,11 +39,32 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
|
||||
|
||||
utilsfactory._get_windows_version = mock.MagicMock(
|
||||
return_value='6.2.0')
|
||||
|
||||
class MockFixedIntervalLoopingCall(object):
|
||||
def __init__(self, f):
|
||||
self.f = f
|
||||
|
||||
def start(self, interval=0):
|
||||
self.f()
|
||||
|
||||
mock.patch('neutron.openstack.common.loopingcall.'
|
||||
'FixedIntervalLoopingCall',
|
||||
new=MockFixedIntervalLoopingCall)
|
||||
|
||||
self.agent = hyperv_neutron_agent.HyperVNeutronAgent()
|
||||
self.agent.plugin_rpc = mock.Mock()
|
||||
self.agent.context = mock.Mock()
|
||||
self.agent.agent_id = mock.Mock()
|
||||
|
||||
fake_agent_state = {
|
||||
'binary': 'neutron-hyperv-agent',
|
||||
'host': 'fake_host_name',
|
||||
'topic': 'N/A',
|
||||
'configurations': {'vswitch_mappings': ['*:MyVirtualSwitch']},
|
||||
'agent_type': 'HyperV agent',
|
||||
'start_flag': True}
|
||||
self.agent_state = fake_agent_state
|
||||
|
||||
def test_port_bound(self):
|
||||
port = mock.Mock()
|
||||
net_uuid = 'my-net-uuid'
|
||||
@ -112,6 +133,14 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
|
||||
def test_treat_devices_removed_ignores_missing_port(self):
|
||||
self.mock_treat_devices_removed(False)
|
||||
|
||||
def test_report_state(self):
|
||||
with mock.patch.object(self.agent.state_rpc,
|
||||
"report_state") as report_st:
|
||||
self.agent._report_state()
|
||||
report_st.assert_called_with(self.agent.context,
|
||||
self.agent.agent_state)
|
||||
self.assertNotIn("start_flag", self.agent.agent_state)
|
||||
|
||||
def test_main(self):
|
||||
with mock.patch.object(hyperv_neutron_agent,
|
||||
'HyperVNeutronAgent') as plugin:
|
||||
|
Loading…
Reference in New Issue
Block a user