%PDF-1.5 %���� ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµù Õ5sLOšuY donat Was Here
donatShell
Server IP : 188.40.95.74  /  Your IP : 216.73.216.205
Web Server : Apache
System : Linux cp01.striminghost.net 3.10.0-1160.119.1.el7.tuxcare.els13.x86_64 #1 SMP Fri Nov 22 06:29:45 UTC 2024 x86_64
User : vlasotin ( 1054)
PHP Version : 5.6.40
Disable Function : NONE
MySQL : ON  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /lib/python2.7/site-packages/leapp/repository/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME SHELL ]     

Current File : /lib/python2.7/site-packages/leapp/repository/actor_definition.py
import contextlib
import linecache
import logging
import os
import pkgutil
import sys
import traceback
import warnings
from io import UnsupportedOperation
from multiprocessing import Process, Queue, Pipe

import leapp.libraries.actor  # noqa # pylint: disable=unused-import
from leapp.actors import get_actor_metadata, get_actors
from leapp.compat import load_module
from leapp.exceptions import (ActorInspectionFailedError, LeappRuntimeError, MultipleActorsError,
                              UnsupportedDefinitionKindError)
from leapp.repository.definition import DefinitionKind
from leapp.utils.audit import create_audit_entry
from leapp.utils.deprecation import _LeappDeprecationWarning
from leapp.utils.libraryfinder import LeappLibrariesFinder


def inspect_actor(definition, result_queue):
    """
    Retrieves the actor information in a child process and returns the results back through `result_queue`.

    :param definition: the actor definition to load
    :type definition: :py:class:`ActorDefinition`
    :param result_queue: queue to pass results back to the calling process
    :type result_queue: :py:class:`multiprocessing.Queue`
    """
    definition.load()
    result = [get_actor_metadata(actor) for actor in get_actors()]
    result = [entry for entry in result if entry['path'] in definition.full_path]
    result_queue.put(result)


class ActorCallContext(object):
    """
    Wraps the actor execution into child process.
    """

    def __init__(self, definition, logger, messaging, config_model, skip_dialogs):
        """
        :param definition: Actor definition
        :type definition: :py:class:`leapp.repository.actor_definition.ActorDefinition`
        :param logger: Logger
        :type logger: :py:class:`logging.Logger`
        :param messaging: Leapp Messaging
        :type messaging: :py:class:`leapp.messaging.BaseMessaging`
        :param config_model: Workflow provided configuration model
        :type config_model: :py:class:`leapp.models.Model` derived class
        """
        self.definition = definition
        self.logger = logger
        self.messaging = messaging
        self.config_model = config_model
        self.skip_dialogs = skip_dialogs

    @staticmethod
    def _do_run(stdin, logger, messaging, definition, config_model, skip_dialogs, error_pipe, args, kwargs):
        if stdin is not None:
            try:
                sys.stdin = os.fdopen(stdin)
            except OSError:
                pass
        with warnings.catch_warnings(record=True) as recording:
            warnings.simplefilter(action="always", category=_LeappDeprecationWarning)
            definition.load()
            with definition.injected_context():
                target_actor = [actor for actor in get_actors() if actor.name == definition.name][0]
                actor_instance = target_actor(logger=logger, messaging=messaging, config_model=config_model,
                                              skip_dialogs=skip_dialogs)
                try:
                    actor_instance.run(*args, **kwargs)
                except Exception:
                    # Send the exception data string to the parent process
                    # and reraise.
                    error_pipe.send(traceback.format_exc())
                    raise
            try:
                # By this time this is no longer set, so we have to get it back
                os.environ['LEAPP_CURRENT_ACTOR'] = actor_instance.name
                for rec in recording:
                    if issubclass(rec.category, _LeappDeprecationWarning):
                        entry = {
                            'message': str(rec.message),
                            'filename': rec.filename,
                            'line': linecache.getline(rec.filename, rec.lineno) if rec.line is None else rec.line,
                            'lineno': rec.lineno,
                            'since': rec.category.since,
                            'reason': rec.category.msg
                        }
                        create_audit_entry('deprecation', entry)
            finally:
                # Remove it again
                os.environ.pop('LEAPP_CURRENT_ACTOR')

    def run(self, *args, **kwargs):
        """
        Performs the actor execution in the child process.
        """
        try:
            stdin = sys.stdin.fileno()
        except UnsupportedOperation:
            stdin = None

        pipe_receiver, pipe_sender = Pipe()
        p = Process(target=self._do_run,
                    args=(stdin, self.logger, self.messaging, self.definition, self.config_model,
                          self.skip_dialogs, pipe_sender, args, kwargs))
        p.start()
        p.join()
        if p.exitcode != 0:
            err_message = "Actor {actorname} unexpectedly terminated with exit code: {exitcode}".format(
                actorname=self.definition.name, exitcode=p.exitcode)

            exception_info = None
            # If there's data in the pipe, it's formatted exception info.
            if pipe_receiver.poll():
                exception_info = pipe_receiver.recv()

            # This LeappRuntimeError will contain an exception traceback
            # in addition to the above message.
            raise LeappRuntimeError(err_message, exception_info)


class ActorDefinition(object):
    """
    Defines actor resources.

    """

    def __init__(self, directory, repo_dir, log=None):
        """
        :param log: Logger
        :type log: :py:class:`logging.Logger`
        :param directory: Actor directory
        :type directory: str
        :param repo_dir: Repository directory
        :type repo_dir: str
        """
        self.log = log or logging.getLogger('leapp.actor')
        self._directory = directory
        self._repo_dir = repo_dir
        self._definitions = {}
        self._module = None
        self._discovery = None

    @property
    def full_path(self):
        return os.path.realpath(os.path.join(self._repo_dir, self._directory))

    def add(self, kind, path):
        """
        Adds any kind of actor resource to the Definition

        :param kind: kind of resource added
        :type kind: str
        :param path: path to the added resource
        :type path: str
        """
        if kind not in DefinitionKind.ACTOR_WHITELIST:
            self.log.error("Attempt to add item type %s to actor that is not supported", kind.name)
            raise UnsupportedDefinitionKindError('Actors do not support {kind}.'.format(kind=kind.name))
        self._definitions.setdefault(kind, []).append(path)

    def serialize(self):
        """
        :return: dump of actor resources (path, name, tools, files, libraries, tests)
        """
        return {
            'path': self.directory,
            'name': self.name,
            'class_name': self.class_name,
            'description': self.description,
            'tags': self.tags,
            'config_schemas': self.config_schemas,
            'consumes': self.consumes,
            'produces': self.produces,
            'apis': self.apis,
            'dialogs': [dialog.serialize() for dialog in self.dialogs],
            'tools': self.tools,
            'files': self.files,
            'libraries': self.libraries,
            'configs': self.configs,
            'tests': self.tests
        }

    def load(self):
        """
        Loads the actor module to be introspectable.
        """
        if not self._module:
            with self.injected_context():
                path = os.path.abspath(os.path.join(self._repo_dir, self.directory))
                for importer, name, is_pkg in pkgutil.iter_modules((path,)):
                    if not is_pkg:
                        self._module = load_module(importer, name)
                        break

    def discover(self):
        """
        Performs introspection through a subprocess.

        :return: Dictionary with discovered items.
        """
        if not self._discovery:
            self.log.debug("Starting actor discovery in %s", self.directory)
            q = Queue(1)
            p = Process(target=inspect_actor, args=(self, q))
            p.start()
            p.join()
            if p.exitcode != 0:
                self.log.error("Process inspecting actor in %s failed with %d", self.directory, p.exitcode)
                raise ActorInspectionFailedError('Inspection of actor in {path} failed'.format(path=self.directory))

            # Note (dkubek): The use of injected_context() here is necessary
            # when retrieving the discovered actor. This is because
            # configuration schemas are defined within the actor's scope, and
            # how Leapp manages imports. Configuration schemas, being scoped
            # within each actor, are accessible internally by the actor itself.
            # However, attempting to return a configuration schema outside this
            # scope results in an error. This occurs because the schema class
            # definition is no longer accessible in the path, making it
            # unavailable for importint. The injected_context() here ensures
            # the path to the actor level code remains in scope while accessing
            # it.
            with self.injected_context():
                result = q.get()

            if not result:
                self.log.error("Process inspecting actor in %s returned no result", self.directory)
                raise ActorInspectionFailedError(
                    'Inspection of actor in {path} produced no results'.format(path=self.directory))
            if len(result) > 1:
                self.log.error("Actor in %s returned multiple actors", self.directory)
                raise MultipleActorsError(self.directory)
            self._discovery = result[0]
            for tag in self._discovery['tags']:
                if self not in tag.actors:
                    tag.actors += (self,)
        return self._discovery

    def __call__(self, messaging=None, logger=None, config_model=None, skip_dialogs=False):
        return ActorCallContext(definition=self, messaging=messaging, logger=logger, config_model=config_model,
                                skip_dialogs=skip_dialogs)

    @property
    def dialogs(self):
        """
        :return: Tuple of defined dialogs
        """
        return self.discover()['dialogs']

    @property
    def consumes(self):
        """
        :return: Tuple of consumed models
        """
        return self.discover()['consumes']

    @property
    def produces(self):
        """
        :return: Tuple of produced models
        """
        return self.discover()['produces']

    @property
    def tags(self):
        """
        :return: Tuple of tags assigned to the actor
        """
        return self.discover()['tags']

    @property
    def class_name(self):
        """
        :return: Actor class name
        """
        return self.discover()['class_name']

    @property
    def name(self):
        """
        :return: Actor internal name
        """
        return self.discover()['name']

    @property
    def description(self):
        """
        :return: Actor description
        """
        return self.discover()['description']

    @property
    def config_schemas(self):
        """
        :return: Actor config_schemas
        """
        return self.discover()['config_schemas']

    @contextlib.contextmanager
    def injected_context(self):
        """
        Prepares the actor environment for running the actor.
        This includes injecting actor private libraries into :py:mod:`leapp.libraries.actor`
        and setting environment variables for private tools and files.

        :note: Use with caution.
        """
        # Backup of the path variable
        path_backup = os.environ.get('PATH', '')
        os.environ['PATH'] = ':'.join(path_backup.split(':') + list(
            os.path.join(self._repo_dir, self._directory, path) for path in self.tools))

        files_backup = os.environ.get('LEAPP_FILES', None)
        if self.files:
            os.environ['LEAPP_FILES'] = os.path.join(self._repo_dir, self._directory, self.files[0])

        tools_backup = os.environ.get('LEAPP_TOOLS', None)
        if self.tools:
            os.environ['LEAPP_TOOLS'] = os.path.join(self._repo_dir, self._directory, self.tools[0])

        meta_path_backup = sys.meta_path[:]

        sys.meta_path.append(
            LeappLibrariesFinder(
                module_prefix='leapp.libraries.actor',
                paths=[os.path.join(self._repo_dir, self.directory, x) for x in self.libraries]))

        sys.meta_path.append(
            LeappLibrariesFinder(
                module_prefix='leapp.configs.actor',
                paths=[os.path.join(self._repo_dir, self.directory, x) for x in self.configs]))

        previous_path = os.getcwd()
        os.chdir(os.path.join(self._repo_dir, self._directory))
        try:
            yield
        finally:
            os.chdir(previous_path)

            # Restoration of the PATH environment variable
            os.environ['PATH'] = path_backup
            # Restoration of the LEAPP_FILES environment variable
            if files_backup is not None:
                os.environ['LEAPP_FILES'] = files_backup
            else:
                os.environ.pop('LEAPP_FILES', None)

            if tools_backup is not None:
                os.environ['LEAPP_TOOLS'] = tools_backup
            else:
                os.environ.pop('LEAPP_TOOLS', None)

            sys.meta_path = meta_path_backup

    @property
    def apis(self):
        """
        :return: names of APIs used by this actor
        """
        return tuple(self.discover()['apis'])

    @property
    def directory(self):
        """
        :return: The folder path of the actor
        """
        return self._directory

    @property
    def tools(self):
        """
        :return: Tuple with path to the tools folder of the actor, empty tuple if none
        """
        return tuple(self._definitions.get(DefinitionKind.TOOLS, ()))

    @property
    def libraries(self):
        """
        :return: Tuple with path to the libraries folder of the actor, empty tuple if none
        """
        return tuple(self._definitions.get(DefinitionKind.LIBRARIES, ()))

    @property
    def files(self):
        """
        :return: Tuple with path to the files folder of the actor, empty tuple if none
        """
        return tuple(self._definitions.get(DefinitionKind.FILES, ()))

    @property
    def configs(self):
        """
        :return: Tuple with path to the configs folder of the actor, empty tuple if none
        """
        return tuple(self._definitions.get(DefinitionKind.CONFIGS, ()))

    @property
    def tests(self):
        """
        :return: Tuple with path to the tests folder of the actor, empty tuple if none
        """
        return tuple(self._definitions.get(DefinitionKind.TESTS, ()))

Anon7 - 2022
AnonSec Team