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
CONF = cfg.CONF
CONF.register_opts(agent_opts, "AGENT")
+config.register_agent_state_opts_helper(cfg.CONF)
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
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 = {}
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
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
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):
# 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()
self._parse_network_vlan_ranges()
self._create_network_providers_map()
-
self._db.sync_vlan_allocations(self._network_vlan_ranges)
self._setup_rpc()
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
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."""
# 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
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
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'
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: