Esempio n. 1
0
    def start(self):
        """
        запустить дочерний процесс консоли
        self.env - переоперделенные переменные окружения
        read_output_thread - поток читатель из std_out
        check_idle_thread - поток, проверяет активное ли соединение,
                            JavaScript делает переодически запросы к консоли для получить новые буквы ответа,
                            и если давно небыло опроса, то пора выходить
        """
        self.process = subprocess.Popen(
            'cmd.exe',
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=self.env,
            bufsize=1,
            cwd=self.physical_path
        )

        self.stdout_reader = OutputReader(self.process.stdout)
        self.stderr_reader = OutputReader(self.process.stderr)

        read_output_thread = Thread(target=self.read_output)
        read_output_thread.daemon = True
        read_output_thread.start()

        check_idle_thread = Thread(target=self.check_idle_thread)
        check_idle_thread.daemon = True
        check_idle_thread.start()
Esempio n. 2
0
    def start(self):
        """
        запустить дочерний процесс консоли
        self.env - переоперделенные переменные окружения
        read_output_thread - поток читатель из std_out
        check_idle_thread - поток, проверяет активное ли соединение,
                            JavaScript делает переодически запросы к консоли для получить новые буквы ответа,
                            и если давно небыло опроса, то пора выходить
        """
        self.process = subprocess.Popen(
            'cmd.exe',
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=self.env,
            bufsize=1,
            cwd=self.physical_path
        )

        self.stdout_reader = OutputReader(self.process.stdout)
        self.stderr_reader = OutputReader(self.process.stderr)

        read_output_thread = Thread(target=self.read_output)
        read_output_thread.daemon = True
        read_output_thread.start()

        check_idle_thread = Thread(target=self.check_idle_thread)
        check_idle_thread.daemon = True
        check_idle_thread.start()
Esempio n. 3
0
class WebConsole(object):
    """
    реализация веб-консоли
    1 экземпляра

    после запуска проверяет активно ли соединение с клиентом, если он не опрашивал консоль в течении IDLE_INTERVAL, то надо все закрыть
    """

    _consoles = {}  # активные консоли. для разных узлов в дереве

    IDLE_INTERVAL = 30

    @classmethod
    def get_console(cls, path):
        """
        получить консоль для указанного пути. если нет - None
        :param path:
        :return:
        """
        return cls._consoles.get(path, None)

    @classmethod
    def create_console(cls, path):
        """
        если нет в активных. то создать WebConsole и добавить в активные, по указанному пути

        :param path:
        :return:
        """
        if not path in cls._consoles:
            console = WebConsole(path)
            cls._consoles[path] = console

        return cls._consoles[path]

    def __init__(self, path):
        """
        подготовить окружение к запуску дочернего процесса
        нужно
        - загрузить .zoo
        - найти на каком энжайне он работает
        - найти энжайн
        - взять текущие переменные окружения
        - взять переменные окружения энжайна
        - взять переменные окружения .zoo
        - раскрыть все переменные окружения

        запустить дочерний процесс

        :param path:
        """
        self.path = path
        self.core = Core.get_instance()
        self.physical_path = self.core.api.os.web_server.map_webserver_path(self.path)
        self.zoo_config = self.core.api.os.web_server.get_zoo_config(self.physical_path)
        self.env = os.environ.copy()


        # emulate zoo module variables

        self.env["INSTANCE_ID"] = "0"
        self.env["APPL_PHYSICAL_PATH"] = self.physical_path
        self.env["APPL_PHYSICAL_SHORT_PATH"] = self.core.api.os.shell.get_short_path_name(self.physical_path)
        self.env["APPL_VIRTUAL_PATH"] = self.path
        self.env["APPL_ID"] = self.env["APPL_VIRTUAL_PATH"].replace("/","")
        #self.env["IIS_BINDNGS"] = self.core.api.os.web_server.get_site()


        if self.zoo_config:
            if self.zoo_config['engine']:
                engine_config = self.core.engine_storage.get_product(self.zoo_config['engine']).config
                if engine_config:
                    if 'environment_variables' in engine_config:
                        engine_env = engine_config.get('environment_variables')
                        self.update_env(self.env, engine_env)

            if 'environment_variables' in self.zoo_config:
                app_env = self.zoo_config.get('environment_variables')
                self.update_env(self.env, app_env)

        self.env = self.expand_variables_in_dict(self.env)



        self.process = None
        self.std_out = ""
        self.std_err = ""
        self.stdout_reader = None
        self.stderr_reader = None
        self.timestamp = 0
        self.start()

    def expand_variables_in_dict(self, envs):
        """
        развернуть переменные окружения в словаре для каждого значения
         - сначала системные
         - затем зу
        :param envs:
        :return:
        """
        result = dict()
        for (key, value) in envs.items():
            result[key.upper()] = os.path.expandvars(envs[key])
            result[key.upper()] = self.expand_zoo_variables(envs[key])

        return result

    def expand_zoo_variables(self, string_to_process):
        """
        развернуть в строке переменные окружения zoo
        поискать в строке '%KEY%' если есть то заменить на соответсвующее значение из словаря
        и так для каждого ключа в словаре

        :param string_to_process:
        :return:
        """
        result = string_to_process
        for (key, value) in self.env.items():
            if string_to_process.lower() != key.lower():
                result = result.lower().replace("%" + key.lower() + "%", value)

        if result.lower().find("%") != -1:
            #repeat if nested expand needed
            for (key, value) in self.env.items():
                if string_to_process.lower() != key.lower():
                    result = result.lower().replace("%" + key.lower() + "%", value)


        if result.lower() != string_to_process.lower():
            logging.info("expand_zoo_variables > {0} --> {1}".format( string_to_process, result.lower()))
        return result.lower()


    def __repr__(self):
        return 'WebConsole({0})'.format(self.path)

    def to_dict(self):
        return object_attrs_to_dict(self, ['path', 'physical_path'])

    def start(self):
        """
        запустить дочерний процесс консоли
        self.env - переоперделенные переменные окружения
        read_output_thread - поток читатель из std_out
        check_idle_thread - поток, проверяет активное ли соединение,
                            JavaScript делает переодически запросы к консоли для получить новые буквы ответа,
                            и если давно небыло опроса, то пора выходить
        """
        self.process = subprocess.Popen(
            'cmd.exe',
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=self.env,
            bufsize=1,
            cwd=self.physical_path
        )

        self.stdout_reader = OutputReader(self.process.stdout)
        self.stderr_reader = OutputReader(self.process.stderr)

        read_output_thread = Thread(target=self.read_output)
        read_output_thread.daemon = True
        read_output_thread.start()

        check_idle_thread = Thread(target=self.check_idle_thread)
        check_idle_thread.daemon = True
        check_idle_thread.start()

    def read_output(self):
        """
        читать все что выдала консоль.
        запомнить в self.std_out, self.std_er

        """
        while True:
            if not self.process or self.process.poll() is not None:
                break

            out = self.stdout_reader.read_nowait()
            self.std_out += out

            err = self.stderr_reader.read_nowait()
            self.std_err += err

            # if not out and not err:
            time.sleep(0.1)
        logging.debug('read_output_thread completed')

    def write(self, command):
        """
        просто записать строку в консоль

        :param command:
        :return:
        """
        logging.debug(command)
        self.process.stdin.write(str.encode(command))
        self.process.stdin.flush()

        self.timestamp = time.time()

        resp = {}
        return resp

    def read(self):
        """
        прочитать из консоли,
        кажется не используется

        :return:
        """
        out = self.std_out
        self.std_out = ''

        err = self.std_err
        self.std_err = ''

        if out:
            logging.debug('stdout: {0}'.format(out))
        if err:
            logging.debug('stderr: {0}'.format(err))

        self.timestamp = time.time()

        return {
            'stdout': out,
            'stderr': err,
        }

    def check_idle_thread(self):
        """
        тело потока, проверка на активность клиента консоли
        вечный цикл
        если давно небыло запроса к консоли, то закрыть ее

        """
        self.timestamp = time.time()
        while True:
            time.sleep(10)
            if self.check_idle():
                break
        logging.debug('check_idle_thread completed')

    def check_idle(self):
        """
        поверить наступило ли условие для выхода
        если ппроцесс умер
        если небыло давно запросов в веб консоли

        :return:
        """
        logging.debug('check idle console')
        if not self.process or self.process.poll() is not None:
            return True
        if time.time() - self.timestamp >= self.IDLE_INTERVAL:
            # console is idle for IDLE_INTERVAL second
            logging.info('{0} is idle, close it'.format(self))
            WebConsole.cancel_console(self)
            return True
        return False

    def cancel(self):
        """
        убить процесс

        """
        self.process.terminate()
        self.process = None

    @classmethod
    def cancel_console(cls, console):
        """
        хендлер. закрытия консоли
        :param console:
        """
        logging.debug('Canceling {0}'.format(console))
        console.cancel()
        del cls._consoles[console.path]

    def update_env(self, env, env2):
        for (key, value) in env2.items():
            env[key.upper()] = os.path.expandvars(value)
Esempio n. 4
0
class WebConsole(object):
    """
    реализация веб-консоли
    1 экземпляра

    после запуска проверяет активно ли соединение с клиентом, если он не опрашивал консоль в течении IDLE_INTERVAL, то надо все закрыть
    """

    _consoles = {}  # активные консоли. для разных узлов в дереве

    IDLE_INTERVAL = 30

    @classmethod
    def get_console(cls, path):
        """
        получить консоль для указанного пути. если нет - None
        :param path:
        :return:
        """
        return cls._consoles.get(path, None)

    @classmethod
    def create_console(cls, path):
        """
        если нет в активных. то создать WebConsole и добавить в активные, по указанному пути

        :param path:
        :return:
        """
        if not path in cls._consoles:
            console = WebConsole(path)
            cls._consoles[path] = console

        return cls._consoles[path]

    def __init__(self, path):
        """
        подготовить окружение к запуску дочернего процесса
        нужно
        - загрузить .zoo
        - найти на каком энжайне он работает
        - найти энжайн
        - взять текущие переменные окружения
        - взять переменные окружения энжайна
        - взять переменные окружения .zoo
        - раскрыть все переменные окружения

        запустить дочерний процесс

        :param path:
        """
        self.path = path
        self.core = Core.get_instance()
        self.physical_path = self.core.api.os.web_server.map_webserver_path(self.path)
        self.zoo_config = self.core.api.os.web_server.get_zoo_config(self.physical_path)
        self.env = os.environ.copy()
        # emulate zoo module variables
        self.env["INSTANCE_ID"] = "0"
        self.env["APPL_PHYSICAL_PATH"] = self.physical_path
        self.env["APPL_PHYSICAL_SHORT_PATH"] = self.core.api.os.shell.get_short_path_name(self.physical_path)
        self.env["APPL_VIRTUAL_PATH"] = self.path
        self.env["APPL_ID"] = self.env["APPL_VIRTUAL_PATH"].replace("/", "")

        if self.zoo_config:
            zoo_env = self.core.api.os.web_server.create_environment(self.zoo_config, self.env)
            self.env = zoo_env

        self.process = None

        self.pipe_stdin = None
        self.pipe_stdout = None
        self.pipe_stderr = None

        self.std_out = ""
        self.std_err = ""
        self.stdout_reader = None
        self.stderr_reader = None
        self.timestamp = 0
        self.start()




    def __repr__(self):
        return 'WebConsole({0})'.format(self.path)

    def to_dict(self):
        return object_attrs_to_dict(self, ['path', 'physical_path'])

    def start(self):
        """
        запустить дочерний процесс консоли
        self.env - переоперделенные переменные окружения
        read_output_thread - поток читатель из std_out
        check_idle_thread - поток, проверяет активное ли соединение,
                            JavaScript делает переодически запросы к консоли для получить новые буквы ответа,
                            и если давно небыло опроса, то пора выходить
        """
        self.process = subprocess.Popen(
            'cmd.exe',
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=self.env,
            bufsize=1,
            cwd=self.physical_path
        )

        self.stdout_reader = OutputReader(self.process.stdout)
        self.stderr_reader = OutputReader(self.process.stderr)

        read_output_thread = Thread(target=self.read_output)
        read_output_thread.daemon = True
        read_output_thread.start()

        check_idle_thread = Thread(target=self.check_idle_thread)
        check_idle_thread.daemon = True
        check_idle_thread.start()

    def read_output(self):
        """
        читать все что выдала консоль.
        запомнить в self.std_out, self.std_er

        """
        while True:
            if not self.process or self.process.poll() is not None:
                break

            out = self.stdout_reader.read_nowait()
            self.std_out += out

            err = self.stderr_reader.read_nowait()
            self.std_err += err
       #    logging.debug(" from output %s" % out)
            # if not out and not err:
            time.sleep(0.1)
        logging.debug('read_output_thread completed')

    def write(self, command):
        """
        просто записать строку в консоль

        :param command:
        :return:
        """
        logging.debug(command)
        self.process.stdin.write(str.encode(command))
        self.process.stdin.flush()

        self.timestamp = time.time()

        resp = {}
        return resp

    def read(self):
        """
        прочитать из консоли,
        кажется не используется

        :return:
        """
        out = self.std_out
        self.std_out = ''

        err = self.std_err
        self.std_err = ''
        logging.debug('ping connection: ')

        if out:
            logging.debug('stdout: {0}'.format(out))
        if err:
            logging.debug('stderr: {0}'.format(err))

        self.timestamp = time.time()

        return {
            'stdout': out,
            'stderr': err,
        }

    def check_idle_thread(self):
        """
        тело потока, проверка на активность клиента консоли
        вечный цикл
        если давно небыло запроса к консоли, то закрыть ее

        """
        self.timestamp = time.time()
        while True:
            time.sleep(10)
            if self.check_idle():
                break
        logging.debug('check_idle_thread completed')

    def check_idle(self):
        """
        поверить наступило ли условие для выхода
        если ппроцесс умер
        если небыло давно запросов в веб консоли

        :return:
        """
        logging.debug('check idle console')
        if not self.process or self.process.poll() is not None:
            return True
        if time.time() - self.timestamp >= self.IDLE_INTERVAL:
            # console is idle for IDLE_INTERVAL second
            logging.info('{0} is idle, close it'.format(self))
            WebConsole.cancel_console(self)
            return True
        return False

    def cancel(self):
        """
        убить процесс

        """
        self.process.terminate()
        self.process = None

    @classmethod
    def cancel_console(cls, console):
        """
        хендлер. закрытия консоли
        :param console:
        """
        logging.debug('Canceling {0}'.format(console))
        console.cancel()
        del cls._consoles[console.path]

    def update_env(self, env, env2):
        for (key, value) in env2.items():
            env[key.upper()] = os.path.expandvars(value)