Beispiel #1
0
        def thread():
            """
            Run the shell in a normal synchronous thread.
            """
            # Set stdin/out pair for this thread.
            sys.stdout.set_handler(self.pty.stdout)
            sys.stdin.set_handler(self.pty.stdin)

            # Authentication
            try:
                self.username = pty_based_auth(
                    self.auth_backend, self.pty) if self.auth_backend else ''
                authenticated = True
            except NotAuthenticated:
                authenticated = False

            if authenticated:
                # Create loggers
                logger_interface = LoggerInterface()
                in_shell_logger = DefaultLogger(self.pty.stdout,
                                                print_group=False)

                # Create options.
                options = Options()

                # Run shell
                shell = WebShell(self.root_node,
                                 self.pty,
                                 options,
                                 logger_interface,
                                 username=self.username)

                shell.session = self  # Assign session to shell
                self.shell = shell

                with logger_interface.attach_in_block(in_shell_logger):
                    with nested(*[
                            logger_interface.attach_in_block(l)
                            for l in self.extra_loggers
                    ]):
                        shell.cmdloop()

                # Remove references (shell and session had circular reference)
                self.shell = None
                shell.session = None

            # Write last dummy character to trigger the session_closed.
            # (telnet session will otherwise wait for enter keypress.)
            sys.stdout.write(' ')

            # Remove std handlers for this thread.
            sys.stdout.del_handler()
            sys.stdin.del_handler()

            if self.doneCallback:
                self.doneCallback()

            # Stop IO reader
            reactor.callFromThread(self.reader.stopReading)
def start(root_node, interactive=True, cd_path=None, logfile=None,
                action_name=None, parameters=None, shell=StandaloneShell,
                extra_loggers=None):
    """
    Start the deployment shell in standalone modus. (No parrallel execution,
    no server/client. Just one interface, and everything sequential.)
    """
    parameters = parameters or []

    # Enable logging
    if logfile:
        logging.basicConfig(filename=logfile, level=logging.DEBUG)

    # Make sure that stdin and stdout are unbuffered
    # The alternative is to start Python with the -u option
    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    # Create Pty object
    pty = Pty(sys.stdin, sys.stdout, interactive=interactive)

    def sigwinch_handler(n, frame):
        pty.trigger_resize()
    signal.signal(signal.SIGWINCH, sigwinch_handler)

    # Initialize root node
    root_node = root_node()

    # Set process title
    setproctitle('deploy:%s run -s' % root_node.__class__.__name__)

    # Loggers
    in_shell_logger = DefaultLogger(print_group=False)

    logger_interface = LoggerInterface()
    extra_loggers = extra_loggers or []

    with logger_interface.attach_in_block(in_shell_logger):
        with nested(* [logger_interface.attach_in_block(l) for l in extra_loggers]):
            # Create shell
            print 'Running single threaded shell...'
            shell = shell(root_node, pty, logger_interface)
            if cd_path is not None:
                shell.cd(cd_path)

            if action_name:
                try:
                    return shell.run_action(action_name, *parameters)
                except ActionException, e:
                    sys.exit(1)
                except:
                    import traceback
                    traceback.print_exc()
                    sys.exit(1)
        def thread():
            """
            Run the shell in a normal synchronous thread.
            """
            # Set stdin/out pair for this thread.
            sys.stdout.set_handler(self.pty.stdout)
            sys.stdin.set_handler(self.pty.stdin)

            # Authentication
            try:
                self.username = pty_based_auth(self.auth_backend, self.pty) if self.auth_backend else ''
                authenticated = True
            except NotAuthenticated:
                authenticated = False

            if authenticated:
                # Create loggers
                logger_interface = LoggerInterface()
                in_shell_logger = DefaultLogger(self.pty.stdout, print_group=False)

                # Create options.
                options = Options()

                # Run shell
                shell = WebShell(self.root_node, self.pty, options, logger_interface, username=self.username)

                shell.session = self # Assign session to shell
                self.shell = shell

                with logger_interface.attach_in_block(in_shell_logger):
                    with nested(* [logger_interface.attach_in_block(l) for l in self.extra_loggers]):
                        shell.cmdloop()

                # Remove references (shell and session had circular reference)
                self.shell = None
                shell.session = None

            # Write last dummy character to trigger the session_closed.
            # (telnet session will otherwise wait for enter keypress.)
            sys.stdout.write(' ')

            # Remove std handlers for this thread.
            sys.stdout.del_handler()
            sys.stdin.del_handler()

            if self.doneCallback:
                self.doneCallback()

            # Stop IO reader
            reactor.callFromThread(self.reader.stopReading)
class ConnectionShell(object):
    """
    Start an interactive shell for a connection.
    (using a separate thread.)
    """

    def __init__(self, connection, clone_shell=None, cd_path=None):
        self.connection = connection

        # Create loggers
        self.logger_interface = LoggerInterface()

        # Run shell
        self.shell = SocketShell(
            connection.root_node,
            connection.pty,
            connection.runtime_options,
            self.logger_interface,
            clone_shell=clone_shell,
            connection=connection,
        )
        self.cd_path = cd_path

    def openNewShellFromThread(self):
        """
        Open new interactive shell in a new window.
        (Clone location of current shell.)
        """
        # Ask the client to open a new connection
        self.connection.openNewConnection(focus=True)

        try:
            # Blocking call to wait for a new incoming connection
            new_connection = PtyManager.getNewConnectionFromThread()

            # Start a new shell-thread into this connection.
            ConnectionShell(new_connection, clone_shell=self.shell).startThread()
        except PtyManager.NoPtyConnection as e:
            print "ERROR: could not open new terminal window..."

    def openNewShellFromReactor(self):
        self.connection.openNewConnection(focus=True)
        d = PtyManager.getNewConnection()

        @d.addCallback
        def openShell(new_connection):
            new_connection.startShell(clone_shell=self.shell)

        @d.addErrback
        def failed(failure):
            # Opening a new shell failed.
            pass

    def startThread(self, *a, **kw):
        threads.deferToThread(lambda: self.thread(*a, **kw))

    def thread(self, action_name=None, parameters=None, open_scp_shell=False):
        parameters = parameters or []

        # Set stdin/out pair for this thread.
        sys.stdout.set_handler(self.connection.pty.stdout)
        sys.stdin.set_handler(self.connection.pty.stdin)

        self.shell.session = self  # Assign session to shell

        # in_shell_logger: Displaying of events in shell
        with self.logger_interface.attach_in_block(DefaultLogger(print_group=False)):
            # Attach the extra loggers.
            with nested(*[self.logger_interface.attach_in_block(l) for l in self.connection.extra_loggers]):
                # Start at correct location
                if self.cd_path:
                    self.shell.cd(self.cd_path)

                if action_name and open_scp_shell:
                    print "Don't provide 'action_name' and 'open_scp_shell' at the same time"
                    exit_status = 1

                elif open_scp_shell:
                    self.shell.open_scp_shell()
                    exit_status = 0

                # When an action_name is given, call this action immediately,
                # otherwise, run the interactive cmdloop.
                elif action_name:
                    try:
                        self.shell.run_action(action_name, *parameters)
                        exit_status = 0
                    except ActionException:
                        exit_status = 1
                    except Exception:
                        import traceback

                        traceback.print_exc()
                        exit_status = 1
                else:
                    self.shell.cmdloop()
                    exit_status = 0

        # Remove references (shell and session have circular reference)
        self.shell.session = None
        self.shell = None

        # Remove std handlers for this thread.
        sys.stdout.del_handler()
        sys.stdin.del_handler()

        # Close connection
        reactor.callFromThread(lambda: self.connection.finish(exit_status=exit_status, always_close=True))
class ConnectionShell(object):
    """
    Start an interactive shell for a connection.
    (using a separate thread.)
    """
    def __init__(self, connection, clone_shell=None, cd_path=None):
        self.connection = connection

        # Create loggers
        self.logger_interface = LoggerInterface()

        # Run shell
        self.shell = SocketShell(connection.root_node, connection.pty, connection.runtime_options,
                                self.logger_interface, clone_shell=clone_shell, connection=connection)
        self.cd_path = cd_path

    def openNewShellFromThread(self):
        """
        Open new interactive shell in a new window.
        (Clone location of current shell.)
        """
        # Ask the client to open a new connection
        self.connection.openNewConnection(focus=True)

        try:
            # Blocking call to wait for a new incoming connection
            new_connection = PtyManager.getNewConnectionFromThread()

            # Start a new shell-thread into this connection.
            ConnectionShell(new_connection, clone_shell=self.shell).startThread()
        except PtyManager.NoPtyConnection as e:
            print 'ERROR: could not open new terminal window...'

    def openNewShellFromReactor(self):
        self.connection.openNewConnection(focus=True)
        d = PtyManager.getNewConnection()

        @d.addCallback
        def openShell(new_connection):
            new_connection.startShell(clone_shell=self.shell)

        @d.addErrback
        def failed(failure):
            # Opening a new shell failed.
            pass

    def startThread(self, *a, **kw):
        threads.deferToThread(lambda: self.thread(*a, **kw))

    def thread(self, action_name=None, parameters=None, open_scp_shell=False):
        parameters = parameters or []

        # Set stdin/out pair for this thread.
        sys.stdout.set_handler(self.connection.pty.stdout)
        sys.stdin.set_handler(self.connection.pty.stdin)

        self.shell.session = self # Assign session to shell

        # in_shell_logger: Displaying of events in shell
        with self.logger_interface.attach_in_block(DefaultLogger(print_group=False)):
            # Attach the extra loggers.
            with nested(* [ self.logger_interface.attach_in_block(l) for l in self.connection.extra_loggers]):
                # Start at correct location
                if self.cd_path:
                    self.shell.cd(self.cd_path)

                if action_name and open_scp_shell:
                    print "Don't provide 'action_name' and 'open_scp_shell' at the same time"
                    exit_status = 1

                elif open_scp_shell:
                    self.shell.open_scp_shell()
                    exit_status = 0

                # When an action_name is given, call this action immediately,
                # otherwise, run the interactive cmdloop.
                elif action_name:
                    try:
                        self.shell.run_action(action_name, *parameters)
                        exit_status = 0
                    except ActionException:
                        exit_status = 1
                    except Exception:
                        import traceback
                        traceback.print_exc()
                        exit_status = 1
                else:
                    self.shell.cmdloop()
                    exit_status = 0

        # Remove references (shell and session have circular reference)
        self.shell.session = None
        self.shell = None

        # Remove std handlers for this thread.
        sys.stdout.del_handler()
        sys.stdin.del_handler()

        # Close connection
        reactor.callFromThread(lambda: self.connection.finish(
                    exit_status=exit_status, always_close=True))
def start(root_node,
          interactive=True,
          cd_path=None,
          logfile=None,
          action_name=None,
          parameters=None,
          shell=StandaloneShell,
          extra_loggers=None,
          open_scp_shell=False):
    """
    Start the deployment shell in standalone modus. (No parrallel execution,
    no server/client. Just one interface, and everything sequential.)
    """
    parameters = parameters or []

    # Enable logging
    if logfile:
        logging.basicConfig(filename=logfile, level=logging.DEBUG)

    # Make sure that stdin and stdout are unbuffered
    # The alternative is to start Python with the -u option
    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    # Create Pty object
    pty = Pty(sys.stdin,
              sys.stdout,
              interactive=interactive,
              term_var=os.environ.get('TERM', ''))

    def sigwinch_handler(n, frame):
        pty.trigger_resize()

    signal.signal(signal.SIGWINCH, sigwinch_handler)

    # Create runtime options
    options = Options()

    # Initialize root node
    root_node = root_node()

    # Set process title
    setproctitle('deploy:%s run -s' % root_node.__class__.__name__)

    # Loggers
    in_shell_logger = DefaultLogger(print_group=False)

    logger_interface = LoggerInterface()
    extra_loggers = extra_loggers or []

    with logger_interface.attach_in_block(in_shell_logger):
        with nested(
                *[logger_interface.attach_in_block(l) for l in extra_loggers]):
            # Create shell
            print 'Running single threaded shell...'
            shell = shell(root_node, pty, options, logger_interface)
            if cd_path is not None:
                shell.cd(cd_path)

            if action_name and open_scp_shell:
                raise Exception(
                    "Don't provide 'action_name' and 'open_scp_shell' at the same time"
                )

            if open_scp_shell:
                shell.open_scp_shell()

            elif action_name:
                try:
                    return shell.run_action(action_name, *parameters)
                except ActionException as e:
                    sys.exit(1)
                except:
                    import traceback
                    traceback.print_exc()
                    sys.exit(1)

            else:
                shell.cmdloop()