diff --git a/snap_openstack/base.py b/snap_openstack/base.py index 8188aa7..db6c95f 100644 --- a/snap_openstack/base.py +++ b/snap_openstack/base.py @@ -35,6 +35,15 @@ SNAP_ENV = ['SNAP_NAME', 'SNAP_USER_COMMON', 'TMPDIR'] +DEFAULT_EP_TYPE = 'simple' +UWSGI_EP_TYPE = 'uwsgi' + +VALID_EP_TYPES = (DEFAULT_EP_TYPE, UWSGI_EP_TYPE) + +DEFAULT_UWSGI_ARGS = ["--master", + "--die-on-term", + "--emperor"] + def snap_env(): '''Grab SNAP* environment variables @@ -106,31 +115,49 @@ class OpenStackSnap(object): other_args = argv[2:] LOG.debug(entry_point) + # Build out command to run - cmd = [entry_point['binary']] + cmd_type = entry_point.get('type', + DEFAULT_EP_TYPE) - for cfile in entry_point.get('config-files', []): - cfile = cfile.format(**self.snap_env) - if os.path.exists(cfile): - cmd.append('--config-file={}'.format(cfile)) - else: - LOG.warning('Configuration file {} not found' - ', skipping'.format(cfile)) + if cmd_type not in VALID_EP_TYPES: + _msg = 'Invalid entry point type: {}'.format(cmd_type) + LOG.error(_msg) + raise ValueError(_msg) - for cdir in entry_point.get('config-dirs', []): - cdir = cdir.format(**self.snap_env) - if os.path.exists(cdir): - cmd.append('--config-dir={}'.format(cdir)) - else: - LOG.warning('Configuration directory {} not found' - ', skipping'.format(cdir)) + if cmd_type == DEFAULT_EP_TYPE: + cmd = [entry_point['binary']] + for cfile in entry_point.get('config-files', []): + cfile = cfile.format(**self.snap_env) + if os.path.exists(cfile): + cmd.append('--config-file={}'.format(cfile)) + else: + LOG.warning('Configuration file {} not found' + ', skipping'.format(cfile)) - log_file = entry_point.get('log-file') - if log_file: - log_file = log_file.format(**self.snap_env) - cmd.append('--log-file={}'.format(log_file)) + for cdir in entry_point.get('config-dirs', []): + cdir = cdir.format(**self.snap_env) + if os.path.exists(cdir): + cmd.append('--config-dir={}'.format(cdir)) + else: + LOG.warning('Configuration directory {} not found' + ', skipping'.format(cdir)) + + log_file = entry_point.get('log-file') + if log_file: + log_file = log_file.format(**self.snap_env) + cmd.append('--log-file={}'.format(log_file)) + + # Ensure any arguments passed to wrapper are propagated + cmd.extend(other_args) + + elif cmd_type == UWSGI_EP_TYPE: + cmd = [UWSGI_EP_TYPE] + cmd.extend(DEFAULT_UWSGI_ARGS) + uwsgi_dir = entry_point.get('uwsgi-dir') + if uwsgi_dir: + uwsgi_dir = uwsgi_dir.format(**self.snap_env) + cmd.append(uwsgi_dir) - # Ensure any arguments passed to wrapper are propagated - cmd.extend(other_args) LOG.debug('Executing command {}'.format(' '.join(cmd))) - os.execvp(entry_point['binary'], cmd) + os.execvp(cmd[0], cmd) diff --git a/snap_openstack/tests/data/snap-openstack.yaml b/snap_openstack/tests/data/snap-openstack.yaml index 7e4b4ad..0d8edb2 100644 --- a/snap_openstack/tests/data/snap-openstack.yaml +++ b/snap_openstack/tests/data/snap-openstack.yaml @@ -15,6 +15,7 @@ entry_points: config-dirs: - "{snap_common}/etc/nova.conf.d" nova-scheduler: + type: simple binary: nova-scheduler config-files: - "{snap}/etc/nova/nova.conf" @@ -22,3 +23,10 @@ entry_points: config-dirs: - "{snap_common}/etc/nova.conf.d" log-file: "{snap_common}/logs/nova-scheduler.log" + keystone-api: + type: uwsgi + uwsgi-dir: "{snap_common}/etc/uwsgi" + log-file: "{snap_common}/logs/keystone.log" + nova-broken: + type: unknown + binary: nova-broken diff --git a/snap_openstack/tests/test_snap_openstack.py b/snap_openstack/tests/test_snap_openstack.py index 7d0078c..a544708 100644 --- a/snap_openstack/tests/test_snap_openstack.py +++ b/snap_openstack/tests/test_snap_openstack.py @@ -98,3 +98,35 @@ class TestOpenStackSnapExecute(test_base.TestCase): snap.execute, ['snap-openstack', 'nova-api']) + + @patch.object(base, 'snap_env') + @patch.object(base, 'os') + def test_base_snap_config_uwsgi(self, mock_os, + mock_snap_env): + '''Ensure wrapped binary of uwsgi called with correct arguments''' + mock_snap_env.return_value = MOCK_SNAP_ENV + snap = base.OpenStackSnap(os.path.join(TEST_DIR, + 'snap-openstack.yaml')) + mock_os.path.exists.side_effect = self.mock_exists + snap.execute(['snap-openstack', + 'keystone-api']) + mock_os.execvp.assert_called_with( + 'uwsgi', + ['uwsgi', '--master', + '--die-on-term', '--emperor', + '/var/snap/test/common/etc/uwsgi'] + ) + + @patch.object(base, 'snap_env') + @patch.object(base, 'os') + def test_base_snap_config_invalid_ep_type(self, mock_os, + mock_snap_env): + '''Ensure endpoint types are correctly validated''' + mock_snap_env.return_value = MOCK_SNAP_ENV + snap = base.OpenStackSnap(os.path.join(TEST_DIR, + 'snap-openstack.yaml')) + mock_os.path.exists.side_effect = self.mock_exists + self.assertRaises(ValueError, + snap.execute, + ['snap-openstack', + 'nova-broken'])