Example #1
0
    def test_get_sandbox_python_path_for_python_action_python2_used_for_venv(self,
            mock_get_python_lib):
        self.assertFalse(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))
Example #2
0
    def test_get_sandbox_python_path_for_python_action_python2_used_for_venv(self,
            mock_get_python_lib):
        self.assertFalse(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))
Example #3
0
    def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(
            self, mock_get_python_lib):
        self.assertTrue(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(
            pack='dummy_pack',
            inherit_from_parent=False,
            inherit_parent_virtualenv=False)

        split = python_path.strip(':').split(':')
        self.assertEqual(len(split), 3)

        # First entry should be lib/python3 dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[0])

        # Second entry should be python3 site-packages dir from venv
        self.assertTrue(
            'virtualenvs/dummy_pack/lib/python3.6/site-packages' in split[1])

        # Third entry should be actions/lib dir from pack root directory
        self.assertTrue('packs/dummy_pack/actions/lib/' in split[2])

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path_for_python_action(
            pack='dummy_pack',
            inherit_from_parent=True,
            inherit_parent_virtualenv=False)
        expected = (
            '/tmp/virtualenvs/dummy_pack/lib/python3.6:'
            '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
            '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2')
        self.assertEqual(python_path, expected)

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path_for_python_action(
            pack='dummy_pack',
            inherit_from_parent=True,
            inherit_parent_virtualenv=True)

        expected = (
            '/tmp/virtualenvs/dummy_pack/lib/python3.6:'
            '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
            '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2:'
            '%s/virtualenvtest' % (sys.prefix))
        self.assertEqual(python_path, expected)
Example #4
0
    def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(self,
            mock_get_python_lib):
        self.assertTrue(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        split = python_path.strip(':').split(':')
        self.assertEqual(len(split), 3)

        # First entry should be lib/python3 dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[0])

        # Second entry should be python3 site-packages dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6/site-packages' in split[1])

        # Third entry should be actions/lib dir from pack root directory
        self.assertTrue('packs/dummy_pack/actions/lib/' in split[2])

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=False)
        expected = ('/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2')
        self.assertEqual(python_path, expected)

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=True)

        expected = ('/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2:'
                    '%s/virtualenvtest' % (sys.prefix))
        self.assertEqual(python_path, expected)
Example #5
0
    def _spawn_sensor_process(self, sensor):
        """
        Spawn a new process for the provided sensor.

        New process uses isolated Python binary from a virtual environment
        belonging to the sensor pack.
        """
        sensor_id = self._get_sensor_id(sensor=sensor)
        pack_ref = sensor['pack']

        virtualenv_path = get_sandbox_virtualenv_path(pack=pack_ref)
        python_path = get_sandbox_python_binary_path(pack=pack_ref)

        if virtualenv_path and not os.path.isdir(virtualenv_path):
            format_values = {
                'pack': sensor['pack'],
                'virtualenv_path': virtualenv_path
            }
            msg = PACK_VIRTUALENV_DOESNT_EXIST % format_values
            raise Exception(msg)

        # NOTE: Running sensors using Python 3 virtual environments is not supported
        uses_python3, _ = is_pack_virtualenv_using_python3(pack=sensor['pack'])

        if uses_python3 and not six.PY3:
            format_values = {
                'pack': sensor['pack'],
                'virtualenv_path': virtualenv_path
            }
            msg = PACK_VIRTUALENV_USES_PYTHON3 % format_values
            raise Exception(msg)

        args = self._get_args_for_wrapper_script(python_binary=python_path,
                                                 sensor=sensor)

        if self._enable_common_pack_libs:
            pack_common_libs_path = get_pack_common_libs_path_for_pack_ref(
                pack_ref=pack_ref)
        else:
            pack_common_libs_path = None

        env = os.environ.copy()

        sandbox_python_path = get_sandbox_python_path(
            inherit_from_parent=True, inherit_parent_virtualenv=True)

        if self._enable_common_pack_libs and pack_common_libs_path:
            env['PYTHONPATH'] = pack_common_libs_path + ':' + sandbox_python_path
        else:
            env['PYTHONPATH'] = sandbox_python_path

        if self._create_token:
            # Include full api URL and API token specific to that sensor
            LOG.debug('Creating temporary auth token for sensor %s' %
                      (sensor['class_name']))

            ttl = cfg.CONF.auth.service_token_ttl
            metadata = {
                'service': 'sensors_container',
                'sensor_path': sensor['file_path'],
                'sensor_class': sensor['class_name']
            }
            temporary_token = create_token(username='******',
                                           ttl=ttl,
                                           metadata=metadata,
                                           service=True)

            env[API_URL_ENV_VARIABLE_NAME] = get_full_public_api_url()
            env[AUTH_TOKEN_ENV_VARIABLE_NAME] = temporary_token.token

            # TODO 1: Purge temporary token when service stops or sensor process dies
            # TODO 2: Store metadata (wrapper process id) with the token and delete
            # tokens for old, dead processes on startup

        cmd = ' '.join(args)
        LOG.debug('Running sensor subprocess (cmd="%s")', cmd)

        # TODO: Intercept stdout and stderr for aggregated logging purposes
        try:
            process = subprocess.Popen(args=args,
                                       stdin=None,
                                       stdout=None,
                                       stderr=None,
                                       shell=False,
                                       env=env,
                                       preexec_fn=on_parent_exit('SIGTERM'))
        except Exception as e:
            cmd = ' '.join(args)
            message = ('Failed to spawn process for sensor %s ("%s"): %s' %
                       (sensor_id, cmd, six.text_type(e)))
            raise Exception(message)

        self._processes[sensor_id] = process
        self._sensors[sensor_id] = sensor
        self._sensor_start_times[sensor_id] = int(time.time())

        self._dispatch_trigger_for_sensor_spawn(sensor=sensor,
                                                process=process,
                                                cmd=cmd)

        return process
Example #6
0
    def _spawn_sensor_process(self, sensor):
        """
        Spawn a new process for the provided sensor.

        New process uses isolated Python binary from a virtual environment
        belonging to the sensor pack.
        """
        sensor_id = self._get_sensor_id(sensor=sensor)
        pack_ref = sensor['pack']

        virtualenv_path = get_sandbox_virtualenv_path(pack=pack_ref)
        python_path = get_sandbox_python_binary_path(pack=pack_ref)

        if virtualenv_path and not os.path.isdir(virtualenv_path):
            format_values = {'pack': sensor['pack'], 'virtualenv_path': virtualenv_path}
            msg = PACK_VIRTUALENV_DOESNT_EXIST % format_values
            raise Exception(msg)

        # NOTE: Running sensors using Python 3 virtual environments is not supported
        uses_python3, _ = is_pack_virtualenv_using_python3(pack=sensor['pack'])

        if uses_python3 and not six.PY3:
            format_values = {'pack': sensor['pack'], 'virtualenv_path': virtualenv_path}
            msg = PACK_VIRTUALENV_USES_PYTHON3 % format_values
            raise Exception(msg)

        trigger_type_refs = sensor['trigger_types'] or []
        trigger_type_refs = ','.join(trigger_type_refs)

        parent_args = json.dumps(sys.argv[1:])

        args = [
            python_path,
            WRAPPER_SCRIPT_PATH,
            '--pack=%s' % (sensor['pack']),
            '--file-path=%s' % (sensor['file_path']),
            '--class-name=%s' % (sensor['class_name']),
            '--trigger-type-refs=%s' % (trigger_type_refs),
            '--parent-args=%s' % (parent_args)
        ]

        if sensor['poll_interval']:
            args.append('--poll-interval=%s' % (sensor['poll_interval']))

        sandbox_python_path = get_sandbox_python_path(inherit_from_parent=True,
                                                      inherit_parent_virtualenv=True)

        if self._enable_common_pack_libs:
            pack_common_libs_path = get_pack_common_libs_path_for_pack_ref(pack_ref=pack_ref)
        else:
            pack_common_libs_path = None

        env = os.environ.copy()

        if self._enable_common_pack_libs and pack_common_libs_path:
            env['PYTHONPATH'] = pack_common_libs_path + ':' + sandbox_python_path
        else:
            env['PYTHONPATH'] = sandbox_python_path

        # Include full api URL and API token specific to that sensor
        ttl = cfg.CONF.auth.service_token_ttl
        metadata = {
            'service': 'sensors_container',
            'sensor_path': sensor['file_path'],
            'sensor_class': sensor['class_name']
        }
        temporary_token = create_token(username='******', ttl=ttl, metadata=metadata,
                                       service=True)

        env[API_URL_ENV_VARIABLE_NAME] = get_full_public_api_url()
        env[AUTH_TOKEN_ENV_VARIABLE_NAME] = temporary_token.token

        # TODO 1: Purge temporary token when service stops or sensor process dies
        # TODO 2: Store metadata (wrapper process id) with the token and delete
        # tokens for old, dead processes on startup
        cmd = ' '.join(args)
        LOG.debug('Running sensor subprocess (cmd="%s")', cmd)

        # TODO: Intercept stdout and stderr for aggregated logging purposes
        try:
            process = subprocess.Popen(args=args, stdin=None, stdout=None,
                                       stderr=None, shell=False, env=env,
                                       preexec_fn=on_parent_exit('SIGTERM'))
        except Exception as e:
            cmd = ' '.join(args)
            message = ('Failed to spawn process for sensor %s ("%s"): %s' %
                       (sensor_id, cmd, six.text_type(e)))
            raise Exception(message)

        self._processes[sensor_id] = process
        self._sensors[sensor_id] = sensor
        self._sensor_start_times[sensor_id] = int(time.time())

        self._dispatch_trigger_for_sensor_spawn(sensor=sensor, process=process, cmd=cmd)

        return process