Beispiel #1
0
def test_ptyprocess_suspend_resume () :
    """ Test pty_process which gets suspended/resumed """
    pty = supp.PTYProcess ("cat")
    os.kill (pty.child, signal.SIGSTOP)
    os.kill (pty.child, signal.SIGCONT)
    time.sleep (0.1)
    assert (pty.alive ())
Beispiel #2
0
def test_ptyprocess_stderr () :
    """ Test pty_process printing stderr messages"""
    txt = "______1______2_____3_____\n"
    pty = supp.PTYProcess ("sh -c 'printf \"%s\" 1>&2'" % txt)
    out = pty.read ()
  # print "--%s--%s--\n" % ( len(txt), txt)
  # print "--%s--%s--\n" % ( len(out), out)
    assert (str(txt) == str(out))
Beispiel #3
0
def test_ptyprocess_stdout () :
    """ Test pty_process printing stdout messages"""
    txt = "______1______2_____3_____\n"
    pty = supp.PTYProcess ("printf \"%s\"" % txt)
    out = pty.read (size=len(txt), timeout=1.0)
    pty.wait ()
    assert (str(txt) == str(out)), "'%s' == '%s'" % \
           (str(txt) ,  str(out))
Beispiel #4
0
def test_ptyprocess_kill () :
    """ Test pty_process which gets killed """
    pty = supp.PTYProcess ("cat")
    os.kill (pty.child, signal.SIGKILL)
    time.sleep (0.1)
    assert (not pty.alive ())
    assert (pty.exit_signal == signal.SIGKILL), "'%s' == '%s'" % \
           (pty.exit_signal ,  signal.SIGKILL)
Beispiel #5
0
def test_ptyprocess_find () :
    """ Test pty_process selecting stdout messages"""
    txt = "______1_____2______3_____"
    pty = supp.PTYProcess ("printf \"%s\"" % txt)
    out = pty.find ('2', '3')
  # print out
    assert (out == (0, '______1_____2')), "'%s' == '%s'" % \
           (out ,  (0, '______1_____2'))
Beispiel #6
0
    def get_cp_slave(self, s_cmd, info):

        with self.rlock:

            # print 'new cp  shell to %s' % s_cmd

            cp_slave = supp.PTYProcess(s_cmd, info['logger'])
            self._initialize_pty(cp_slave, info)

            return cp_slave
Beispiel #7
0
    def initialize(self, url, session=None, prompt=None, logger=None):

        with self.rlock:

            # make sure we have a valid url type
            url = saga.Url(url)

            if not prompt:
                prompt = "^(.*[\$#%>\]])\s*$"

            if not logger:
                logger = rul.getLogger('saga', 'PTYShellFactory')

            # collect all information we have/need about the requested master
            # connection
            info = self._create_master_entry(url, session, prompt, logger)

            # we got master info - register the master, and create the instance!
            type_s = str(info['type'])
            user_s = str(info['user'])
            host_s = str(info['host_str'])

            # Now, if we don't have that master, yet, we need to instantiate it
            if not host_s in self.registry: self.registry[host_s] = {}
            if not user_s in self.registry[host_s]:
                self.registry[host_s][user_s] = {}
            if not type_s in self.registry[host_s][user_s]:

                # new master: create an instance, and register it
                m_cmd = info['scripts'][info['type']]['master'] % info

                logger.debug ("open master pty for [%s] [%s] %s: %s'" \
                                % (type_s, host_s, user_s, m_cmd))

                info['pty'] = supp.PTYProcess(m_cmd, logger=logger)
                if not info['pty'].alive():
                    raise se.NoSuccess._log (logger, \
                          "Shell not connected to %s" % info['host_str'])

                # authorization, prompt setup, etc
                self._initialize_pty(info['pty'], info, is_shell=True)

                # master was created - register it
                self.registry[host_s][user_s][type_s] = info

            else:
                # we already have a master: make sure it is alive, and restart as
                # needed
                info = self.registry[host_s][user_s][type_s]

                if not info['pty'].alive(recover=True):
                    raise se.IncorrectState._log (logger, \
                          "Lost shell connection to %s" % info['host_str'])

            return info
Beispiel #8
0
def test_ptyprocess_write () :
    """ Test pty_process reading stdin, printing stdout messages"""
    # cat is line buffered, thus need \n
    txt = "______1______2_____3_____\n"
    pty = supp.PTYProcess ("cat")
    pty.write (txt)
    out = pty.read (size=len(txt), timeout=1.0)
  # print "--%s--%s--\n" % ( len(txt), txt)
  # print "--%s--%s--\n" % ( len(out), out)
    assert (txt == out), "'%s' == '%s'" % \
           (txt ,  out)
Beispiel #9
0
    def get_cp_slave(self, s_cmd, info, posix=None):

        with self.rlock:

            if posix == None:
                posix = info.get('copy_is_posix')

        # print '> -- new cp  shell to %s' % s_cmd

            cp_slave = supp.PTYProcess(s_cmd, info['logger'])
            self._initialize_pty(cp_slave, info, posix)

            return cp_slave
Beispiel #10
0
def test_ptyprocess_restart () :
    """ Test pty_process restart"""
    pty = supp.PTYProcess ("cat")
    assert (pty.alive ())

    pty.finalize ()
    assert (not pty.alive ())

    pty.initialize ()
    assert (pty.alive ())

    pty.finalize ()
    assert (not pty.alive ())
Beispiel #11
0
    def run_shell(self, info):
        """
        This initiates a master connection.  If there is a suitable master
        connection in the registry, it is re-used, and no new master connection
        is created.  If needed, the existing master connection is revived.
        """

        # if True :
        with self.rlock:

            s_cmd = info['scripts'][info['shell_type']]['shell'] % info

            # at this point, we do have a valid, living master
            sh_slave = supp.PTYProcess(s_cmd, info['logger'])

            # authorization, prompt setup, etc
            self._initialize_pty(sh_slave, info)

            return sh_slave
Beispiel #12
0
    def run_copy_to (self, src, tgt, cp_flags="") :
        """ 
        This initiates a slave copy connection.   Src is interpreted as local
        path, tgt as path on the remote host.

        Now, this is ugly when over sftp: sftp supports recursive copy, and
        wildcards, all right -- but for recursive copies, it wants the target
        dir to exist -- so, we have to check if the local src is a  dir, and if
        so, we first create the target before the copy.  Worse, for wildcards we
        have to do a local expansion, and the to do the same for each entry...
        """

        with self.pty_shell.rlock :

            self._trace ("copy  to  : %s -> %s" % (src, tgt))
            self.pty_shell.flush ()

            info = self.pty_info
            repl = dict ({'src'      : src, 
                          'tgt'      : tgt,
                          'cp_flags' : '' # cp_flags # TODO: needs to be "translated" for specific backend
                          }.items () + info.items ())

            # at this point, we do have a valid, living master
            s_cmd = info['scripts'][info['copy_mode']]['copy_to']    % repl
            s_in  = info['scripts'][info['copy_mode']]['copy_to_in'] % repl
            posix = info['scripts'][info['copy_mode']]['copy_is_posix']

            if  not s_in :
                # this code path does not use an interactive shell for copy --
                # so the above s_cmd is all we want to run, really.  We get
                # do not use the chached cp_slave in this case, but just run the
                # command.  We do not have a list of transferred files though,
                # yet -- that should be parsed from the proc output.

                cp_proc = supp.PTYProcess (s_cmd)
                out = cp_proc.wait ()
                if  cp_proc.exit_code :
                    raise ptye.translate_exception (se.NoSuccess ("file copy failed: %s" % out))

                return list()


            # this code path uses an interactive shell to transfer files, of
            # some form, such as sftp.  Get the shell cp_slave from cache, and
            # run the actual copy command.
            if  not self.cp_slave :
                self._trace ("get cp slave")
                self.cp_slave = self.factory.get_cp_slave (s_cmd, info, posix)

            self.cp_slave.flush ()
            if  'sftp' in s_cmd :
                # prepare target dirs for recursive copy, if needed
                import glob
                src_list = glob.glob (src)
                for s in src_list :
                    if  os.path.isdir (s) :
                        prep = "mkdir %s/%s\n" % (tgt, os.path.basename (s))
                        # TODO: this doesn't deal with multiple levels of creation

                        self.cp_slave.flush()
                        self.cp_slave.write("%s\n" % prep)
                        self.cp_slave.find(['[\$\>\]]\s*$'], -1)
                        # TODO: check return values

                if cp_flags == sfs.CREATE_PARENTS and os.path.split(tgt)[0]:
                    # TODO: this needs to be numeric and checking the flag
                    prep = "mkdir %s\n" % os.path.dirname(tgt)
                    # TODO: this doesn't deal with multiple levels of creation

                    self.cp_slave.flush()
                    self.cp_slave.write("%s\n" % prep)
                    self.cp_slave.find(['[\$\>\]]\s*$'], -1)
                    # TODO: check return values

            self.cp_slave.flush()
            _ = self.cp_slave.write("%s\n" % s_in)
            _, out = self.cp_slave.find(['[\$\>\]]\s*$'], -1)

            # FIXME: we don't really get exit codes from copy
            # if  self.cp_slave.exit_code != 0 :
            #     raise se.NoSuccess._log (info['logger'], "file copy failed: %s" % str(out))

            if 'Invalid flag' in out :
                raise se.NoSuccess._log (info['logger'], "sftp version not supported (%s)" % str(out))

            if 'No such file or directory' in out :
                raise se.DoesNotExist._log (info['logger'], "file copy failed: %s" % str(out))

            if 'is not a directory' in out :
                raise se.BadParameter._log (info['logger'], "File copy failed: %s" % str(out))

            if  'sftp' in s_cmd :
                if 'not found' in out :
                    raise se.BadParameter._log (info['logger'], "file copy failed: %s" % out)


            # we interpret the first word on the line as name of src file -- we
            # will return a list of those
            lines = out.split ('\n')
            files = []

            for line in lines :

                elems = line.split (' ', 2)

                if  elems :

                    f = elems[0]

                    # remove quotes
                    if  f :

                        if  f[ 0] in ["'", '"', '`'] : f = f[1:  ]
                        if  f[-1] in ["'", '"', '`'] : f = f[ :-1]

                    # ignore empty lines
                    if  f :

                        files.append (f)

            info['logger'].debug ("copy done: %s" % files)

            return files
Beispiel #13
0
    def run_copy_from (self, src, tgt, cp_flags="") :
        """ 
        This initiates a slave copy connection.   Src is interpreted as path on
        the remote host, tgt as local path.

        We have to do the same mkdir trick as for the run_copy_to, but here we
        need to expand wildcards on the *remote* side :/
        """

        with self.pty_shell.rlock :

            self._trace ("copy  from: %s -> %s" % (src, tgt))
            self.pty_shell.flush ()

            info = self.pty_info
            repl = dict ({'src'      : src, 
                          'tgt'      : tgt, 
                          'cp_flags' : cp_flags}.items() + info.items ())

            # at this point, we do have a valid, living master
            s_cmd = info['scripts'][info['copy_mode']]['copy_from']    % repl
            s_in  = info['scripts'][info['copy_mode']]['copy_from_in'] % repl
            posix = info['scripts'][info['copy_mode']]['copy_is_posix']

            if  not s_in :
                # this code path does not use an interactive shell for copy --
                # so the above s_cmd is all we want to run, really.  We get
                # do not use the chached cp_slave in this case, but just run the
                # command.  We do not have a list of transferred files though,
                # yet -- that should be parsed from the proc output.
                cp_proc = supp.PTYProcess (s_cmd)
                cp_proc.wait ()
                if  cp_proc.exit_code :
                    raise ptye.translate_exception (se.NoSuccess ("file copy failed: exit code %s" % cp_proc.exit_code))

                return list()

            if  not self.cp_slave :
                self._trace ("get cp slave")
                self.cp_slave = self.factory.get_cp_slave (s_cmd, info, posix)

            self.cp_slave.flush ()
            prep = ""

            if  'sftp' in s_cmd :
                # prepare target dirs for recursive copy, if needed
                self.cp_slave.write (" ls %s\n" % src)
                _, out = self.cp_slave.find (["^sftp> "], -1)

                src_list = out[1].split('\n')

                for s in src_list :
                    if  os.path.isdir (s) :
                        prep += "lmkdir %s/%s\n" % (tgt, os.path.basename (s))


            self.cp_slave.flush ()
            _      = self.cp_slave.write    ("%s%s\n" % (prep, s_in))
            _, out = self.cp_slave.find     (['[\$\>\]] *$'], -1)

            # FIXME: we don't really get exit codes from copy
          # if  self.cp_slave.exit_code != 0 :
          #     raise se.NoSuccess._log (info['logger'], "file copy failed: %s" % out)

            if 'Invalid flag' in out :
                raise se.NoSuccess._log (info['logger'], "sftp version not supported (%s)" % out)

            if 'No such file or directory' in out :
                raise se.DoesNotExist._log (info['logger'], "file copy failed: %s" % out)

            if 'is not a directory' in out :
                raise se.BadParameter._log (info['logger'], "file copy failed: %s" % out)

            if  'sftp' in s_cmd :
                if 'not found' in out :
                    raise se.BadParameter._log (info['logger'], "file copy failed: %s" % out)


            # we run copy with -v, so get a list of files which have been copied
            # -- we parse that list and return it.  we interpret the *second*
            # word on the line as name of src file.
            lines = out.split ('\n')
            files = []

            for line in lines :

                elems = line.split (' ', 3)
                
                if  elems and len(elems) > 1 and elems[0] == 'Fetching' :

                    f = elems[1]

                    # remove quotes
                    if  f :

                        if  f[ 0] in ["'", '"', '`']  :  f = f[1:  ]
                        if  f[-1] in ["'", '"', '`']  :  f = f[ :-1]

                    # ignore empty lines
                    if  f :
                        files.append (f)

            info['logger'].debug ("copy done: %s" % files)

            return files
Beispiel #14
0
def test_ptyprocess_nok () :
    """ Test pty_process which finishes unsuccessfully """
    pty = supp.PTYProcess ("false")
    pty.wait ()
    assert pty.exit_code != 0
Beispiel #15
0
def test_ptyprocess_ok () :
    """ Test pty_process which finishes successfully """
    pty = supp.PTYProcess ("true")
    pty.wait ()
    assert pty.exit_code == 0