Пример #1
0
 def __init__(self, message_queue, machine_name, log_dir,
              minimized_gui=False):
     threading.Thread.__init__(self)
     self._message_queue = message_queue
     self._machine_name = machine_name
     self._log_dir = log_dir
     self._minimized_gui = minimized_gui
     self._running = False
     self.daemon = True
     self._vbox = None
     self._vbox_machine = None
     self._vbox_session = None
     self._chat_input = ChatInput(log_dir)
     self._frozen_checker = FrozenChecker()
Пример #2
0
class VMThread(threading.Thread):
    def __init__(self, message_queue, machine_name, log_dir,
                 minimized_gui=False):
        threading.Thread.__init__(self)
        self._message_queue = message_queue
        self._machine_name = machine_name
        self._log_dir = log_dir
        self._minimized_gui = minimized_gui
        self._running = False
        self.daemon = True
        self._vbox = None
        self._vbox_machine = None
        self._vbox_session = None
        self._chat_input = ChatInput(log_dir)
        self._frozen_checker = FrozenChecker()

    def run(self):
        _logger.info('Starting VM client.')

        self._running = True

        self._setup_virtualbox()

        while self._running:
            try:
                nick, message = self._message_queue.get(timeout=0.5)
            except queue.Empty:
                continue

            if not self._start_machine_if_needed():
                continue

            try:
                self._process_input(nick, message)
            except (ValueError, KeyError, TypeError, IndexError):
                _logger.exception('Error processing input')

        _logger.info('Stopped VM client.')

    def stop(self):
        _logger.info('Stopping VM client.')
        self._running = False

    def _setup_virtualbox(self):
        self._vbox = virtualbox.VirtualBox()
        self._vbox_machine = self._vbox.find_machine(self._machine_name)

    def _start_machine_if_needed(self):
        if self._vbox_machine.state in (MachineState.powered_off,
                                        MachineState.saved,
                                        MachineState.aborted):
            if self._vbox_session and \
                    self._vbox_session.state == SessionState.locked:
                _logger.info('Waiting for existing session to unlock.')
                self._vbox_session.unlock_machine()
                self._vbox_session = None
                time.sleep(5)

            _logger.info('Starting machine.')
            self._vbox_session = virtualbox.Session()
            progress = self._vbox_machine.launch_vm_process(self._vbox_session)
            progress.wait_for_completion()

            if self._minimized_gui:
                self._minimize_vm_window()

            return False
        else:
            if not self._vbox_session:
                self._vbox_session = self._vbox_machine.create_session()

            if self._vbox_machine.state == MachineState.stuck:
                _logger.warning('Machine is stuck.')
                self._vbox_session.console.power_down()
                time.sleep(5)
                return False
            elif self._vbox_machine.state != MachineState.running:
                _logger.info('Waiting for machine. Current: %s',
                              self._vbox_machine.state)
                time.sleep(5)
                return False
            else:
                return True

    def _process_input(self, nick, message):
        self._chat_input.process_input(nick, message,
                                       self._vbox_session.console)
        input_count = self._chat_input.input_counter

        if input_count % 100 == 0 or input_count == 5:
            try:
                image_data = self._screenshot()
            except VBoxErrorIprtError:
                _logger.exception('Screenshot error')
                self._frozen_checker.increment_screenshot_error()
            else:
                self._frozen_checker.add_image(image_data)

            if self._frozen_checker.is_frozen():
                _logger.warning('Machine appears frozen')
                self._reset_machine()

    def _screenshot(self):
        width, height, _, _, _ = self._vbox_session.console.display\
            .get_screen_resolution(0)
        data = self._vbox_session.console.display\
            .take_screen_shot_png_to_array(0, width, height)
        self._chat_input.input_logger.save_screenshot(data)

        return data

    def _reset_machine(self):
        _logger.debug('Reset machine')
        self._vbox_session.console.reset()

    def _minimize_vm_window(self):
        try:
            proc = subprocess.Popen(['wmctrl', '-l'], stdout=subprocess.PIPE)
        except OSError:
            return

        stdout_data = proc.communicate()[0].decode('utf-8', 'replace')

        match = re.search(
            r'^0x([a-f0-9]+) +\w+ +\S+ +{} +.* - Oracle VM VirtualBox$'
            .format(re.escape(self._machine_name)),
            stdout_data,
            re.MULTILINE
        )

        if match:
            proc = subprocess.Popen([
                'xdotool', 'windowminimize', '0x{}'.format(match.group(1)),
            ])
            proc.communicate()