From 44b532041f19c988fac094ca7789d95620a0b4c7 Mon Sep 17 00:00:00 2001 From: Corey Bryant Date: Tue, 16 May 2017 17:58:44 +0000 Subject: [PATCH] Enable dynamic creation of uwsgi pyargv option Specifying hard-coded config files via the uwsgi pyargv option caused failures when a file didn't exist. This patch enables dynamic creation of the pyargv option. This value is pushed onto the context for templated file generation which is now supported as a subelement of an entry point as well as a top level global option. Change-Id: I1d0fae42b2e43fe8808fda3de83e122502233a4c --- snap_openstack/base.py | 43 ++++++++++++++++++- snap_openstack/tests/data/snap-openstack.yaml | 9 +++- snap_openstack/tests/test_snap_openstack.py | 24 ++++++++--- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/snap_openstack/base.py b/snap_openstack/base.py index 8318df4..45cc7cb 100644 --- a/snap_openstack/base.py +++ b/snap_openstack/base.py @@ -131,6 +131,7 @@ class OpenStackSnap(object): def execute(self, argv): '''Execute snap command building out configuration and log options''' + renderer = SnapFileRenderer() utils = SnapUtils() entry_point = self.configuration['entry_points'].get(argv[1]) @@ -180,16 +181,56 @@ class OpenStackSnap(object): cmd = ["{snap}/bin/uwsgi".format(**utils.snap_env)] defaults = [d.format(**utils.snap_env) for d in DEFAULT_UWSGI_ARGS] cmd.extend(defaults) + pyargv = [] uwsgi_dir = entry_point.get('uwsgi-dir') if uwsgi_dir: uwsgi_dir = uwsgi_dir.format(**utils.snap_env) cmd.append(uwsgi_dir) + uwsgi_log = entry_point.get('uwsgi-log') + if uwsgi_log: + uwsgi_log = uwsgi_log.format(**utils.snap_env) + cmd.extend(['--logto', uwsgi_log]) + + for cfile in entry_point.get('config-files', []): + cfile = cfile.format(**utils.snap_env) + if os.path.exists(cfile): + pyargv.append('--config-file={}'.format(cfile)) + else: + LOG.debug('Configuration file {} not found' + ', skipping'.format(cfile)) + + for cdir in entry_point.get('config-dirs', []): + cdir = cdir.format(**utils.snap_env) + if os.path.exists(cdir): + pyargv.append('--config-dir={}'.format(cdir)) + else: + LOG.debug('Configuration directory {} not found' + ', skipping'.format(cdir)) + log_file = entry_point.get('log-file') if log_file: log_file = log_file.format(**utils.snap_env) - cmd.extend(['--logto', log_file]) + + pyargv.append('--log-file={}'.format(log_file)) + + # NOTE(jamespage): Pass dynamically built pyargv into + # context for template generation. + snap_env = utils.snap_env + if pyargv: + snap_env['pyargv'] = ' '.join(pyargv) + + for template in entry_point.get('templates', []): + target = entry_point['templates'][template] + target_file = target.format(**utils.snap_env) + utils.ensure_dir(target_file, is_file=True) + if not os.path.isfile(target_file): + LOG.debug('Rendering {} to {}'.format(template, + target_file)) + with open(target_file, 'w') as tf: + os.fchmod(tf.fileno(), 0o640) + tf.write(renderer.render(template, snap_env)) elif cmd_type == NGINX_EP_TYPE: cmd = ["{snap}/usr/sbin/nginx".format(**utils.snap_env)] diff --git a/snap_openstack/tests/data/snap-openstack.yaml b/snap_openstack/tests/data/snap-openstack.yaml index 6ba46a6..c8d759b 100644 --- a/snap_openstack/tests/data/snap-openstack.yaml +++ b/snap_openstack/tests/data/snap-openstack.yaml @@ -28,7 +28,14 @@ entry_points: keystone-uwsgi: type: uwsgi uwsgi-dir: "/etc/uwsgi" - log-file: "/var/log/uwsgi/keystone.log" + uwsgi-log: "/var/log/uwsgi/keystone.log" + config-files: + - "/etc/keystone/keystone.conf" + config-dirs: + - "/etc/keystone/conf.d" + log-file: "/var/log/keystone/keystone.log" + templates: + "admin.ini.j2": "/etc/uwsgi/admin.ini" keystone-nginx: type: nginx config-file: "/etc/nginx/keystone/nginx.conf" diff --git a/snap_openstack/tests/test_snap_openstack.py b/snap_openstack/tests/test_snap_openstack.py index 73fd7df..4c45e6d 100644 --- a/snap_openstack/tests/test_snap_openstack.py +++ b/snap_openstack/tests/test_snap_openstack.py @@ -51,9 +51,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): snap_utils.snap_env = MOCK_SNAP_ENV snap_utils.drop_privileges.return_value = None + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config(self, mock_os, mock_utils): + def test_base_snap_config(self, mock_os, mock_utils, + mock_renderer): '''Ensure wrapped binary called with full args list''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR, @@ -69,9 +71,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): '--log-file=/var/log/nova/scheduler.log'] ) + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config_no_logging(self, mock_os, mock_utils): + def test_base_snap_config_no_logging(self, mock_os, mock_utils, + mock_renderer): '''Ensure wrapped binary called correctly with no logfile''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR, @@ -88,9 +92,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): 'db', 'sync'] ) + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config_missing_entry_point(self, mock_os, mock_utils): + def test_base_snap_config_missing_entry_point(self, mock_os, mock_utils, + mock_renderer): '''Ensure ValueError raised for missing entry_point''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR, @@ -101,9 +107,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): ['snap-openstack', 'nova-api']) + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config_uwsgi(self, mock_os, mock_utils): + def test_base_snap_config_uwsgi(self, mock_os, mock_utils, + mock_renderer): '''Ensure wrapped binary of uwsgi called with correct arguments''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR, @@ -119,9 +127,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): '--logto', '/var/log/uwsgi/keystone.log'] ) + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config_nginx(self, mock_os, mock_utils): + def test_base_snap_config_nginx(self, mock_os, mock_utils, + mock_renderer): '''Ensure wrapped binary of nginx called with correct arguments''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR, @@ -135,9 +145,11 @@ class TestOpenStackSnapExecute(test_base.TestCase): 'daemon on; master_process on;'] ) + @patch.object(base, 'SnapFileRenderer') @patch('snap_openstack.base.SnapUtils') @patch.object(base, 'os') - def test_base_snap_config_invalid_ep_type(self, mock_os, mock_utils): + def test_base_snap_config_invalid_ep_type(self, mock_os, mock_utils, + mock_renderer): '''Ensure endpoint types are correctly validated''' self.mock_snap_utils(mock_utils) snap = base.OpenStackSnap(os.path.join(TEST_DIR,