from neutron.agent.l3 import ha_router
from neutron.agent.l3 import legacy_router
from neutron.agent.l3 import router_processing_queue as queue
+from neutron.agent.linux import external_process
from neutron.agent.linux import ip_lib
from neutron.agent.linux import ra
from neutron.agent.metadata import driver as metadata_driver
self._check_config_params()
+ self.process_monitor = external_process.ProcessMonitor(
+ config=self.conf,
+ root_helper=self.root_helper,
+ resource_type='router')
+
try:
self.driver = importutils.import_object(
self.conf.interface_driver,
def _destroy_router_namespace(self, ns):
router_id = self.get_router_id(ns)
- ra.disable_ipv6_ra(router_id, ns, self.root_helper)
+ ra.disable_ipv6_ra(router_id, self.process_monitor)
ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=ns)
for d in ns_ip.get_devices(exclude_loopback=True):
if d.name.startswith(INTERNAL_DEV_PREFIX):
ri.ns_name,
internal_ports,
self.get_internal_device_name,
- self.root_helper)
+ self.process_monitor)
existing_devices = self._get_existing_devices(ri)
current_internal_devs = set([n for n in existing_devices
callback = (
metadata_driver.MetadataDriver._get_metadata_proxy_callback(
ri.router_id, self.conf))
+ # TODO(mangelajo): use the process monitor in keepalived when
+ # keepalived stops killing/starting metadata
+ # proxy on its own
pm = (
metadata_driver.MetadataDriver.
_get_metadata_proxy_process_manager(ri.router_id,
ri.ns_name,
self.conf))
- pid = pm.get_pid_file_name(ensure_pids_dir=True)
+ pid = pm.get_pid_file_name()
ri.keepalived_manager.add_notifier(
callback(pid), 'master', ri.ha_vr_id)
for state in ('backup', 'fault'):
self.service_pid_fname = 'pid'
self.service = 'default-service'
+ utils.ensure_dir(os.path.dirname(self.get_pid_file_name()))
+
def enable(self, cmd_callback=None, reload_cfg=False):
if not self.active:
if not cmd_callback:
cmd_callback = self.default_cmd_callback
- cmd = cmd_callback(self.get_pid_file_name(ensure_pids_dir=True))
+ cmd = cmd_callback(self.get_pid_file_name())
ip_wrapper = ip_lib.IPWrapper(self.root_helper, self.namespace)
ip_wrapper.netns.execute(cmd, addl_env=self.cmd_addl_env)
else:
LOG.debug('No process started for %s', self.uuid)
- def get_pid_file_name(self, ensure_pids_dir=False):
+ def get_pid_file_name(self):
"""Returns the file name for a given kind of config file."""
if self.pid_file:
- if ensure_pids_dir:
- utils.ensure_dir(os.path.dirname(self.pid_file))
return self.pid_file
else:
return utils.get_conf_file_name(self.pids_path,
self.uuid,
- self.service_pid_fname,
- ensure_pids_dir)
+ self.service_pid_fname)
@property
def pid(self):
service=service,
pid_file=pid_file).pid
+ def get_pid_file_name(self, uuid, service=None):
+ return self._ensure_process_manager(
+ uuid=uuid,
+ service=service).get_pid_file_name()
+
def _ensure_process_manager(self, uuid, cmd_callback=None,
namespace=None, service=None,
cmd_addl_env=None,
from oslo.config import cfg
import six
-from neutron.agent.linux import external_process
from neutron.agent.linux import utils
from neutron.common import constants
from neutron.openstack.common import log as logging
+RADVD_SERVICE_NAME = 'radvd'
+RADVD_SERVICE_CMD = 'radvd'
+
LOG = logging.getLogger(__name__)
OPTS = [
return radvd_conf
-def _spawn_radvd(router_id, radvd_conf, router_ns, root_helper):
+def _spawn_radvd(router_id, radvd_conf, router_ns, process_monitor):
def callback(pid_file):
# we need to use -m syslog and f.e. not -m stderr (the default)
# or -m stderr_syslog so that radvd 2.0+ will close stderr and
# exit after daemonization; otherwise, the current thread will
# be locked waiting for result from radvd that won't ever come
# until the process dies
- radvd_cmd = ['radvd',
+ radvd_cmd = [RADVD_SERVICE_CMD,
'-C', '%s' % radvd_conf,
'-p', '%s' % pid_file,
'-m', 'syslog']
return radvd_cmd
- radvd = external_process.ProcessManager(cfg.CONF,
- router_id,
- root_helper,
- router_ns,
- 'radvd')
- radvd.enable(callback, True)
+ process_monitor.enable(uuid=router_id,
+ cmd_callback=callback,
+ namespace=router_ns,
+ service=RADVD_SERVICE_NAME,
+ reload_cfg=True)
LOG.debug("radvd enabled for router %s", router_id)
def enable_ipv6_ra(router_id, router_ns, router_ports,
- dev_name_helper, root_helper):
+ dev_name_helper, process_monitor):
for p in router_ports:
if netaddr.IPNetwork(p['subnet']['cidr']).version == 6:
break
else:
# Kill the daemon if it's running
- disable_ipv6_ra(router_id, router_ns, root_helper)
+ disable_ipv6_ra(router_id, process_monitor)
return
LOG.debug("Enable IPv6 RA for router %s", router_id)
radvd_conf = _generate_radvd_conf(router_id, router_ports, dev_name_helper)
- _spawn_radvd(router_id, radvd_conf, router_ns, root_helper)
+ _spawn_radvd(router_id, radvd_conf, router_ns, process_monitor)
-def disable_ipv6_ra(router_id, router_ns, root_helper):
- radvd = external_process.ProcessManager(cfg.CONF,
- router_id,
- root_helper,
- router_ns,
- 'radvd')
- radvd.disable()
+def disable_ipv6_ra(router_id, process_monitor):
+ process_monitor.disable(router_id, service=RADVD_SERVICE_NAME)
utils.remove_conf_files(cfg.CONF.ra_confs, router_id)
LOG.debug("radvd disabled for router %s", router_id)
def _get_conf_base(cfg_root, uuid, ensure_conf_dir):
+ #TODO(mangelajo): separate responsibilities here, ensure_conf_dir
+ # should be a separate function
conf_dir = os.path.abspath(os.path.normpath(cfg_root))
conf_base = os.path.join(conf_dir, uuid)
if ensure_conf_dir:
router.iptables_manager.apply()
if not router.is_ha:
- self._spawn_metadata_proxy(router.router_id,
- router.ns_name,
- self.l3_agent.conf)
+ self._spawn_monitored_metadata_proxy(router.router_id,
+ router.ns_name)
def before_router_removed(self, router):
for c, r in self.metadata_filter_rules(self.metadata_port):
router.iptables_manager.ipv4['nat'].remove_rule(c, r)
router.iptables_manager.apply()
- self._destroy_metadata_proxy(router.router['id'],
- router.ns_name,
- self.l3_agent.conf)
+ self._destroy_monitored_metadata_proxy(router.router['id'],
+ router.ns_name)
@classmethod
def metadata_filter_rules(cls, port):
return callback
+ def _spawn_monitored_metadata_proxy(self, router_id, ns_name):
+ callback = self._get_metadata_proxy_callback(
+ router_id, self.l3_agent.conf)
+ self.l3_agent.process_monitor.enable(router_id, callback, ns_name)
+
+ def _destroy_monitored_metadata_proxy(self, router_id, ns_name):
+ self.l3_agent.process_monitor.disable(router_id, ns_name)
+
+ # TODO(mangelajo): remove the unmonitored _get_*_process_manager,
+ # _spawn_* and _destroy* when keepalived stops
+ # spawning and killing proxies on its own.
@classmethod
def _get_metadata_proxy_process_manager(cls, router_id, ns_name, conf):
return external_process.ProcessManager(
config.register_cli_opts(logging.logging_cli_opts)
config.register_opts(logging.generic_log_opts)
config.register_opts(logging.log_opts)
+ agent_config.register_process_monitor_opts(config)
return config
def _configure_agent(self, host):
import mock
import netaddr
-from oslo.config import cfg
from oslo import messaging
from testtools import matchers
from neutron.agent.l3 import ha
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.l3 import router_info as l3router
+from neutron.agent.linux import external_process
from neutron.agent.linux import interface
from neutron.agent.linux import ra
from neutron.agent.metadata import driver as metadata_driver
agent_config.register_interface_driver_opts_helper(self.conf)
agent_config.register_use_namespaces_opts_helper(self.conf)
agent_config.register_root_helper(self.conf)
+ agent_config.register_process_monitor_opts(self.conf)
self.conf.register_opts(interface.OPTS)
+ self.conf.register_opts(external_process.OPTS)
self.conf.set_override('router_id', 'fake_id')
self.conf.set_override('interface_driver',
'neutron.agent.linux.interface.NullDriver')
self.assertFalse(nat_rules_delta)
return ri
- def _expected_call_lookup_ri_process(self, ri, process):
+ def _expected_call_lookup_ri_process_enabled(self, ri, process):
"""Expected call if a process is looked up in a router instance."""
- return [mock.call(cfg.CONF,
- ri.router['id'],
- self.conf.root_helper,
- ri.ns_name,
- process)]
+ return [mock.call(uuid=ri.router['id'],
+ service=process,
+ default_cmd_callback=mock.ANY,
+ namespace=ri.ns_name,
+ root_helper=self.conf.root_helper,
+ conf=self.conf,
+ pid_file=None,
+ cmd_addl_env=None)]
+
+ def _expected_call_lookup_ri_process_disabled(self, ri, process):
+ """Expected call if a process is looked up in a router instance."""
+ # The ProcessManager does already exist, and it's found via
+ # ProcessMonitor lookup _ensure_process_manager
+ return [mock.call().__nonzero__()]
def _assert_ri_process_enabled(self, ri, process):
"""Verify that process was enabled for a router instance."""
- expected_calls = self._expected_call_lookup_ri_process(ri, process)
- expected_calls.append(mock.call().enable(mock.ANY, True))
+ expected_calls = self._expected_call_lookup_ri_process_enabled(
+ ri, process)
+ expected_calls.append(mock.call().enable(reload_cfg=True))
self.assertEqual(expected_calls, self.external_process.mock_calls)
def _assert_ri_process_disabled(self, ri, process):
"""Verify that process was disabled for a router instance."""
- expected_calls = self._expected_call_lookup_ri_process(ri, process)
+ expected_calls = self._expected_call_lookup_ri_process_disabled(
+ ri, process)
expected_calls.append(mock.call().disable())
self.assertEqual(expected_calls, self.external_process.mock_calls)
'distributed': False}
driver = metadata_driver.MetadataDriver
with mock.patch.object(
- driver, '_destroy_metadata_proxy') as destroy_proxy:
+ driver, '_destroy_monitored_metadata_proxy') as destroy_proxy:
with mock.patch.object(
- driver, '_spawn_metadata_proxy') as spawn_proxy:
+ driver, '_spawn_monitored_metadata_proxy') as spawn_proxy:
agent._process_added_router(router)
if enableflag:
spawn_proxy.assert_called_with(router_id,
- mock.ANY,
mock.ANY)
else:
self.assertFalse(spawn_proxy.call_count)
agent._router_removed(router_id)
if enableflag:
destroy_proxy.assert_called_with(router_id,
- mock.ANY,
mock.ANY)
else:
self.assertFalse(destroy_proxy.call_count)
self.external_process_p.stop()
self.ip_cls_p.stop()
+ ensure_dir = 'neutron.agent.linux.utils.ensure_dir'
get_pid_file_name = ('neutron.agent.linux.external_process.'
'ProcessManager.get_pid_file_name')
with mock.patch('neutron.agent.linux.utils.execute') as execute:
with mock.patch(get_pid_file_name) as get_pid:
- get_pid.return_value = pidfile
- ra._spawn_radvd(router['id'],
- conffile,
- agent.get_ns_name(router['id']),
- self.conf.root_helper)
+ with mock.patch(ensure_dir) as ensure_dir:
+ get_pid.return_value = pidfile
+ ra._spawn_radvd(router['id'],
+ conffile,
+ agent.get_ns_name(router['id']),
+ agent.process_monitor)
cmd = execute.call_args[0][0]
self.assertIn('radvd', cmd)
# under the License.
import mock
+import os.path
from neutron.agent.linux import external_process as ep
from neutron.tests import base
self.execute = self.execute_p.start()
self.delete_if_exists = mock.patch(
'neutron.openstack.common.fileutils.delete_if_exists').start()
+ self.makedirs = mock.patch('os.makedirs').start()
self.conf = mock.Mock()
self.conf.external_pids = '/var/path'
+ def test_processmanager_ensures_pid_dir(self):
+ pid_file = os.path.join(self.conf.external_pids, 'pid')
+ ep.ProcessManager(self.conf, 'uuid', pid_file=pid_file)
+ self.makedirs.assert_called_once_with(self.conf.external_pids, 0o755)
+
def test_enable_no_namespace(self):
callback = mock.Mock()
callback.return_value = ['the', 'cmd']
manager = ep.ProcessManager(self.conf, 'uuid')
manager.enable(callback)
callback.assert_called_once_with('pidfile')
- name.assert_called_once_with(ensure_pids_dir=True)
self.execute.assert_called_once_with(['the', 'cmd'],
root_helper='sudo',
check_exit_code=True,
with mock.patch.object(ep, 'ip_lib') as ip_lib:
manager.enable(callback)
callback.assert_called_once_with('pidfile')
- name.assert_called_once_with(ensure_pids_dir=True)
ip_lib.assert_has_calls([
mock.call.IPWrapper('sudo', 'ns'),
mock.call.IPWrapper().netns.execute(['the', 'cmd'],
manager.disable()
debug.assert_called_once_with(mock.ANY, mock.ANY)
- def test_get_pid_file_name_existing(self):
- with mock.patch.object(ep.utils.os.path, 'isdir') as isdir:
- isdir.return_value = True
- manager = ep.ProcessManager(self.conf, 'uuid')
- retval = manager.get_pid_file_name(ensure_pids_dir=True)
- self.assertEqual(retval, '/var/path/uuid.pid')
-
- def test_get_pid_file_name_not_existing(self):
- with mock.patch.object(ep.utils.os.path, 'isdir') as isdir:
- with mock.patch.object(ep.utils.os, 'makedirs') as makedirs:
- isdir.return_value = False
- manager = ep.ProcessManager(self.conf, 'uuid')
- retval = manager.get_pid_file_name(ensure_pids_dir=True)
- self.assertEqual(retval, '/var/path/uuid.pid')
- makedirs.assert_called_once_with('/var/path', 0o755)
-
def test_get_pid_file_name_default(self):
- with mock.patch.object(ep.utils.os.path, 'isdir') as isdir:
- isdir.return_value = True
- manager = ep.ProcessManager(self.conf, 'uuid')
- retval = manager.get_pid_file_name(ensure_pids_dir=False)
- self.assertEqual(retval, '/var/path/uuid.pid')
- self.assertFalse(isdir.called)
+ manager = ep.ProcessManager(self.conf, 'uuid')
+ retval = manager.get_pid_file_name()
+ self.assertEqual(retval, '/var/path/uuid.pid')
def test_pid(self):
with mock.patch('__builtin__.open') as mock_open: