Skip to content

Commit

Permalink
Fixes Hyper-V agent RPC calls for ML2 support
Browse files Browse the repository at this point in the history
Adds support for the RPC report status in the Hyper-V
agent and plugin.

Fixes bug: #1226654

Change-Id: Ie5eee875afc062c536856589d6a3fd0414190f6d
  • Loading branch information
petrutlucian94 committed Sep 25, 2013
1 parent 4afee80 commit 028cca9
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 9 deletions.
37 changes: 33 additions & 4 deletions neutron/plugins/hyperv/agent/hyperv_neutron_agent.py
Expand Up @@ -25,11 +25,14 @@

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
Expand Down Expand Up @@ -63,6 +66,7 @@

CONF = cfg.CONF
CONF.register_opts(agent_opts, "AGENT")
config.register_agent_state_opts_helper(cfg.CONF)


class HyperVNeutronAgent(object):
Expand All @@ -74,13 +78,34 @@ def __init__(self):
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
Expand All @@ -93,6 +118,10 @@ def _setup_rpc(self):
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 = {}
Expand All @@ -103,14 +132,14 @@ def _load_physical_network_mappings(self):
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

Expand Down
7 changes: 4 additions & 3 deletions neutron/plugins/hyperv/hyperv_neutron_plugin.py
Expand Up @@ -21,6 +21,7 @@
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
Expand Down Expand Up @@ -143,7 +144,8 @@ def extend_network_dict(self, network, binding):
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):
Expand All @@ -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()
Expand All @@ -165,7 +167,6 @@ def __init__(self, configfile=None):

self._parse_network_vlan_ranges()
self._create_network_providers_map()

self._db.sync_vlan_allocations(self._network_vlan_ranges)

self._setup_rpc()
Expand Down
4 changes: 3 additions & 1 deletion neutron/plugins/hyperv/rpc_callbacks.py
Expand Up @@ -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
Expand All @@ -44,7 +45,8 @@ def create_rpc_dispatcher(self):
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."""
Expand Down
8 changes: 7 additions & 1 deletion neutron/plugins/ml2/drivers/mech_hyperv.py
Expand Up @@ -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
Expand Down Expand Up @@ -46,6 +48,10 @@ def check_segment_for_agent(self, segment, agent):
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
29 changes: 29 additions & 0 deletions neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py
Expand Up @@ -39,11 +39,32 @@ def setUp(self):

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'
Expand Down Expand Up @@ -112,6 +133,14 @@ def test_treat_devices_removed_unbinds_port(self):
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:
Expand Down

0 comments on commit 028cca9

Please sign in to comment.