From d0d5792d726805e980eb1a6bec50bc4e61f920e1 Mon Sep 17 00:00:00 2001 From: Akihiro MOTOKI Date: Thu, 28 Feb 2013 14:58:20 +0900 Subject: [PATCH] NEC plugin support for dhcp network and router scheduling blueprint quantum-scheduler Change-Id: Icc1e4213cb6109ec82f4d438e277bd870c02729e --- quantum/common/constants.py | 1 + .../versions/4692d074d587_agent_scheduler.py | 1 + .../511471cc46b_agent_ext_model_supp.py | 1 + .../plugins/nec/agent/nec_quantum_agent.py | 36 ++++++++++++++++--- quantum/plugins/nec/common/config.py | 3 ++ quantum/plugins/nec/nec_plugin.py | 29 +++++++++++---- .../tests/unit/nec/test_agent_scheduler.py | 34 ++++++++++++++++++ quantum/tests/unit/nec/test_nec_plugin.py | 5 ++- 8 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 quantum/tests/unit/nec/test_agent_scheduler.py diff --git a/quantum/common/constants.py b/quantum/common/constants.py index e1bc25f18c..966a3fd54c 100644 --- a/quantum/common/constants.py +++ b/quantum/common/constants.py @@ -59,6 +59,7 @@ TYPE_DICT = "dict" AGENT_TYPE_DHCP = 'DHCP agent' AGENT_TYPE_OVS = 'Open vSwitch agent' AGENT_TYPE_LINUXBRIDGE = 'Linux bridge agent' +AGENT_TYPE_NEC = 'NEC plugin agent' AGENT_TYPE_L3 = 'L3 agent' L2_AGENT_TOPIC = 'N/A' diff --git a/quantum/db/migration/alembic_migrations/versions/4692d074d587_agent_scheduler.py b/quantum/db/migration/alembic_migrations/versions/4692d074d587_agent_scheduler.py index 6594fc6723..0cfd44641d 100644 --- a/quantum/db/migration/alembic_migrations/versions/4692d074d587_agent_scheduler.py +++ b/quantum/db/migration/alembic_migrations/versions/4692d074d587_agent_scheduler.py @@ -33,6 +33,7 @@ migration_for_plugins = [ 'quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2', 'quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2', 'quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin.NvpPluginV2', + 'quantum.plugins.nec.nec_plugin.NECPluginV2', ] from alembic import op diff --git a/quantum/db/migration/alembic_migrations/versions/511471cc46b_agent_ext_model_supp.py b/quantum/db/migration/alembic_migrations/versions/511471cc46b_agent_ext_model_supp.py index 7410b42010..0ee357066e 100644 --- a/quantum/db/migration/alembic_migrations/versions/511471cc46b_agent_ext_model_supp.py +++ b/quantum/db/migration/alembic_migrations/versions/511471cc46b_agent_ext_model_supp.py @@ -33,6 +33,7 @@ migration_for_plugins = [ 'quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2', 'quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2', 'quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin.NvpPluginV2', + 'quantum.plugins.nec.nec_plugin.NECPluginV2', ] from alembic import op diff --git a/quantum/plugins/nec/agent/nec_quantum_agent.py b/quantum/plugins/nec/agent/nec_quantum_agent.py index a170e0db6c..0559be46ad 100755 --- a/quantum/plugins/nec/agent/nec_quantum_agent.py +++ b/quantum/plugins/nec/agent/nec_quantum_agent.py @@ -32,10 +32,12 @@ from quantum.agent.linux import ovs_lib from quantum.agent import rpc as agent_rpc from quantum.agent import securitygroups_rpc as sg_rpc from quantum.common import config as logging_config +from quantum.common import constants as q_const from quantum.common import topics from quantum import context as q_context from quantum.extensions import securitygroup as ext_sg from quantum.openstack.common import log as logging +from quantum.openstack.common import loopingcall from quantum.openstack.common.rpc import dispatcher from quantum.openstack.common.rpc import proxy from quantum.plugins.nec.common import config @@ -124,8 +126,18 @@ class NECQuantumAgent(object): ''' self.int_br = ovs_lib.OVSBridge(integ_br, root_helper) self.polling_interval = polling_interval + self.cur_ports = [] self.datapath_id = "0x%s" % self.int_br.get_datapath_id() + + self.agent_state = { + 'binary': 'quantum-nec-agent', + 'host': config.CONF.host, + 'topic': q_const.L2_AGENT_TOPIC, + 'configurations': {}, + 'agent_type': q_const.AGENT_TYPE_NEC, + 'start_flag': True} + self.setup_rpc() def setup_rpc(self): @@ -137,6 +149,7 @@ class NECQuantumAgent(object): self.context = q_context.get_admin_context_without_session() self.plugin_rpc = NECPluginApi(topics.PLUGIN) + self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN) self.sg_agent = SecurityGroupAgentRpc(self.context) # RPC network init @@ -154,6 +167,22 @@ class NECQuantumAgent(object): self.topic, consumers) + report_interval = config.CONF.AGENT.report_interval + if report_interval: + heartbeat = loopingcall.LoopingCall(self._report_state) + heartbeat.start(interval=report_interval) + + def _report_state(self): + try: + # How many devices are likely used by a VM + num_devices = len(self.cur_ports) + self.agent_state['configurations']['devices'] = num_devices + self.state_rpc.report_state(self.context, + self.agent_state) + self.agent_state.pop('start_flag', None) + except Exception: + LOG.exception(_("Failed reporting state!")) + def _vif_port_to_port_info(self, vif_port): return dict(id=vif_port.vif_id, port_no=vif_port.ofport, mac=vif_port.vif_mac) @@ -167,7 +196,6 @@ class NECQuantumAgent(object): def daemon_loop(self): """Main processing loop for NEC Plugin Agent.""" - old_ports = [] while True: new_ports = [] @@ -175,12 +203,12 @@ class NECQuantumAgent(object): for vif_port in self.int_br.get_vif_ports(): port_id = vif_port.vif_id new_ports.append(port_id) - if port_id not in old_ports: + if port_id not in self.cur_ports: port_info = self._vif_port_to_port_info(vif_port) port_added.append(port_info) port_removed = [] - for port_id in old_ports: + for port_id in self.cur_ports: if port_id not in new_ports: port_removed.append(port_id) @@ -192,7 +220,7 @@ class NECQuantumAgent(object): else: LOG.debug(_("No port changed.")) - old_ports = new_ports + self.cur_ports = new_ports time.sleep(self.polling_interval) diff --git a/quantum/plugins/nec/common/config.py b/quantum/plugins/nec/common/config.py index d2de49866b..f6fa30c6d2 100644 --- a/quantum/plugins/nec/common/config.py +++ b/quantum/plugins/nec/common/config.py @@ -20,6 +20,7 @@ from oslo.config import cfg from quantum.agent.common import config # import rpc config options from quantum.openstack.common import rpc +from quantum import scheduler ovs_opts = [ @@ -54,7 +55,9 @@ ofc_opts = [ cfg.CONF.register_opts(ovs_opts, "OVS") cfg.CONF.register_opts(agent_opts, "AGENT") cfg.CONF.register_opts(ofc_opts, "OFC") +config.register_agent_state_opts_helper(cfg.CONF) config.register_root_helper(cfg.CONF) +cfg.CONF.register_opts(scheduler.AGENTS_SCHEDULER_OPTS) # shortcuts CONF = cfg.CONF diff --git a/quantum/plugins/nec/nec_plugin.py b/quantum/plugins/nec/nec_plugin.py index 518b1ee27e..e662f80c5c 100644 --- a/quantum/plugins/nec/nec_plugin.py +++ b/quantum/plugins/nec/nec_plugin.py @@ -17,11 +17,15 @@ # @author: Akihiro MOTOKI from quantum.agent import securitygroups_rpc as sg_rpc +from quantum.api.rpc.agentnotifiers import dhcp_rpc_agent_api +from quantum.api.rpc.agentnotifiers import l3_rpc_agent_api from quantum.common import constants as q_const from quantum.common import exceptions as q_exc from quantum.common import rpc as q_rpc from quantum.common import topics from quantum import context +from quantum.db import agents_db +from quantum.db import agentschedulers_db from quantum.db import dhcp_rpc_base from quantum.db import extraroute_db from quantum.db import l3_rpc_base @@ -30,6 +34,7 @@ from quantum.db import quota_db from quantum.db import securitygroups_rpc_base as sg_db_rpc from quantum.extensions import portbindings from quantum.extensions import securitygroup as ext_sg +from quantum.openstack.common import importutils from quantum.openstack.common import log as logging from quantum.openstack.common import rpc from quantum.openstack.common.rpc import proxy @@ -60,7 +65,8 @@ class OperationalStatus: class NECPluginV2(nec_plugin_base.NECPluginV2Base, extraroute_db.ExtraRoute_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin): + sg_db_rpc.SecurityGroupServerRpcMixin, + agentschedulers_db.AgentSchedulerDbMixin): """NECPluginV2 controls an OpenFlow Controller. The Quantum NECPluginV2 maps L2 logical networks to L2 virtualized networks @@ -75,7 +81,9 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base, """ supported_extension_aliases = ["router", "quotas", "binding", - "security-group", "extraroute"] + "security-group", "extraroute", + "agent", "agent_scheduler", + ] binding_view = "extension:port_binding:view" binding_set = "extension:port_binding:set" @@ -97,17 +105,24 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base, self.setup_rpc() + self.network_scheduler = importutils.import_object( + config.CONF.network_scheduler_driver) + self.router_scheduler = importutils.import_object( + config.CONF.router_scheduler_driver) + def setup_rpc(self): self.topic = topics.PLUGIN self.conn = rpc.create_connection(new=True) self.notifier = NECPluginV2AgentNotifierApi(topics.AGENT) + self.dhcp_agent_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI() + self.l3_agent_notifier = l3_rpc_agent_api.L3AgentNotify - self.callback_nec = NECPluginV2RPCCallbacks(self) - self.callback_dhcp = DhcpRpcCallback() - self.callback_l3 = L3RpcCallback() + # NOTE: callback_sg is referred to from the sg unit test. self.callback_sg = SecurityGroupServerRpcCallback() - callbacks = [self.callback_nec, self.callback_dhcp, - self.callback_l3, self.callback_sg] + callbacks = [NECPluginV2RPCCallbacks(self), + DhcpRpcCallback(), L3RpcCallback(), + self.callback_sg, + agents_db.AgentExtRpcCallback()] self.dispatcher = q_rpc.PluginRpcDispatcher(callbacks) self.conn.create_consumer(self.topic, self.dispatcher, fanout=False) # Consume from all consumers in a thread diff --git a/quantum/tests/unit/nec/test_agent_scheduler.py b/quantum/tests/unit/nec/test_agent_scheduler.py new file mode 100644 index 0000000000..9356cb0236 --- /dev/null +++ b/quantum/tests/unit/nec/test_agent_scheduler.py @@ -0,0 +1,34 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 NEC Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from quantum.tests.unit.openvswitch import test_agent_scheduler +from quantum.tests.unit.nec import test_nec_plugin + + +class NecAgentSchedulerTestCase( + test_agent_scheduler.OvsAgentSchedulerTestCase): + plugin_str = test_nec_plugin.PLUGIN_NAME + + +class NecDhcpAgentNotifierTestCase( + test_agent_scheduler.OvsDhcpAgentNotifierTestCase): + plugin_str = test_nec_plugin.PLUGIN_NAME + + +class NecL3AgentNotifierTestCase( + test_agent_scheduler.OvsL3AgentNotifierTestCase): + plugin_str = test_nec_plugin.PLUGIN_NAME diff --git a/quantum/tests/unit/nec/test_nec_plugin.py b/quantum/tests/unit/nec/test_nec_plugin.py index 747583ad35..080a5cc814 100644 --- a/quantum/tests/unit/nec/test_nec_plugin.py +++ b/quantum/tests/unit/nec/test_nec_plugin.py @@ -18,9 +18,12 @@ from quantum.tests.unit import _test_extension_portbindings as test_bindings from quantum.tests.unit import test_db_plugin as test_plugin +PLUGIN_NAME = 'quantum.plugins.nec.nec_plugin.NECPluginV2' + + class NecPluginV2TestCase(test_plugin.QuantumDbPluginV2TestCase): - _plugin_name = 'quantum.plugins.nec.nec_plugin.NECPluginV2' + _plugin_name = PLUGIN_NAME def setUp(self): super(NecPluginV2TestCase, self).setUp(self._plugin_name)