diff --git a/os_collect_config/collect.py b/os_collect_config/collect.py index 0599543..0cd0efa 100644 --- a/os_collect_config/collect.py +++ b/os_collect_config/collect.py @@ -15,6 +15,7 @@ import json import os +import signal import subprocess import sys import time @@ -114,7 +115,23 @@ def collect_all(collectors, store=False, requests_impl_map=None): return (any_changed, paths_or_content) +def reexec_self(signal=None, frame=None): + if signal: + logger.info('Signal received. Re-executing %s' % sys.argv) + # Close all but stdin/stdout/stderr + os.closerange(3, 255) + os.execv(sys.argv[0], sys.argv) + + +def call_command(files, command): + env = dict(os.environ) + env["OS_CONFIG_FILES"] = ':'.join(files) + logger.info("Executing %s" % command) + subprocess.call(CONF.command, env=env, shell=True) + + def __main__(args=sys.argv, requests_impl_map=None): + signal.signal(signal.SIGHUP, reexec_self) setup_conf() CONF(args=args[1:], prog="os-collect-config") @@ -133,12 +150,13 @@ def __main__(args=sys.argv, requests_impl_map=None): requests_impl_map=requests_impl_map) if CONF.command: if any_changed: - env = dict(os.environ) - env["OS_CONFIG_FILES"] = ':'.join(content) - logger.info("Executing %s" % CONF.command) - subprocess.call(CONF.command, env=env, shell=True) + # ignore HUP now since we will reexec after commit anyway + signal.signal(signal.SIGHUP, signal.SIG_IGN) + call_command(content, CONF.command) for collector in cfg.CONF.collectors: cache.commit(collector) + if not CONF.one_time: + reexec_self() else: logger.debug("No changes detected.") if CONF.one_time: diff --git a/os_collect_config/tests/test_collect.py b/os_collect_config/tests/test_collect.py index 55a7884..963ee35 100644 --- a/os_collect_config/tests/test_collect.py +++ b/os_collect_config/tests/test_collect.py @@ -18,8 +18,11 @@ import extras import fixtures import json import os -from oslo.config import cfg +import signal +import sys import tempfile + +from oslo.config import cfg import testtools from testtools import matchers @@ -39,6 +42,7 @@ def _setup_local_metadata(test_case): class TestCollect(testtools.TestCase): + def setUp(self): super(TestCollect, self).setUp() self.useFixture(fixtures.FakeLogger()) @@ -235,8 +239,35 @@ class TestCollectAll(testtools.TestCase): class TestConf(testtools.TestCase): + def test_setup_conf(self): collect.setup_conf() self.assertEquals('/var/run/os-collect-config', cfg.CONF.cachedir) self.assertTrue(extras.safe_hasattr(cfg.CONF, 'ec2')) self.assertTrue(extras.safe_hasattr(cfg.CONF, 'cfn')) + + +class TestHup(testtools.TestCase): + + def setUp(self): + super(TestHup, self).setUp() + self.log = self.useFixture(fixtures.FakeLogger()) + + def fake_closerange(low, high): + self.assertEquals(3, low) + self.assertEquals(255, high) + + def fake_execv(path, args): + self.assertEquals(sys.argv[0], path) + self.assertEquals(sys.argv, args) + + self.useFixture(fixtures.MonkeyPatch('os.execv', fake_execv)) + self.useFixture(fixtures.MonkeyPatch('os.closerange', fake_closerange)) + + def test_reexec_self_signal(self): + collect.reexec_self(signal.SIGHUP, None) + self.assertIn('Signal received', self.log.output) + + def test_reexec_self(self): + collect.reexec_self() + self.assertNotIn('Signal received', self.log.output)