Exemple #1
0
    def list(self):
        """ implements saga.adaptors.cpi.job.Service.list()
        """
        ids = []

        ret, out, _ = self.shell.run_sync("unset GREP_OPTIONS; %s | grep `whoami`"\
            % self._commands['condor_q']['path'])

        if ret != 0 and len(out) > 0:
            message = "failed to list jobs via 'condor_q': %s" % out
            log_error_and_raise(message, saga.NoSuccess, self._logger)
        elif ret != 0 and len(out) == 0:
            pass
        else:
            for line in out.split("\n"):
                # output looks like this:
                # 112059.svc.uc.futuregrid testjob oweidner 0 Q batch
                # 112061.svc.uc.futuregrid testjob oweidner 0 Q batch
                if len(line.split()) > 1:
                    rm_clone = surl.Url(self.rm)
                    rm_clone.query = ""
                    rm_clone.path = ""

                    jobid = "[%s]-[%s]" % (rm_clone, line.split()[0])
                    ids.append(str(jobid))

        return ids
Exemple #2
0
    def open_dir(self, path, flags=READ, ttype=None):
        """
        open_dir(path, flags=READ)

        Open a directory in the directory instance namespace. Returns 
        a new directory object.

        :param path:     The name/path of the directory to open
        :type path:      str()
        :param flags:    :ref:`filesystemflags`        

        Example::

            # create a subdir 'data' in /tmp
            dir = saga.namespace.Directory("sftp://localhost/tmp/")
            data = dir.open_dir ('data/', saga.namespace.Create)
        """
        if not flags: flags = 0

        url = surl.Url(path)

        if not url.schema:
            url.schema = 'file'

        if not url.host:
            url.host = 'localhost'

        return self._adaptor.open_dir(url, flags, ttype=ttype)
Exemple #3
0
    def acquire  (self, spec, ttype=None) :
        """
        acquire(desc)

        Create a new :class:`saga.resource.Resource` handle for a 
        resource specified by the description.

        :type  spec: :class:`Description`
        :param spec: specifies the resource

        Depending on the `RTYPE` attribute in the description, the
        returned resource may be a :class:`saga.resource.Compute`,
        :class:`saga.resource.Storage` or :class:`saga.resource.Network`
        instance.  The returned resource will be in NEW, PENDING or ACTIVE
        state.
        """

        if  isinstance (spec, surl.Url) or \
            isinstance (spec, basestring)  :

            id = surl.Url (spec)
            
            return self._adaptor.acquire_by_id (id, ttype=ttype)

        else :

            # make sure at least 'executable' is defined
            if spec.rtype is None:
                raise se.BadParameter ("No resource type defined in resource description")
    
            spec_copy = descr.Description ()
            spec._attributes_deep_copy (spec_copy)

            return self._adaptor.acquire (spec_copy, ttype=ttype)
    def init_instance(self, adaptor_state, rm_url, session):
        """ service instance constructor
        """
        self.rm = rm_url
        self.session = session
        self.ppn = None
        self.gpn = 1  # gpus per node  # FIXME: inspect system
        self.is_cray = ""
        self.queue = None
        self.shell = None
        self.jobs = dict()
        self.gres = None

        # the monitoring thread - one per service instance
        self.mt = _job_state_monitor(job_service=self)
        self.mt.start()

        rm_scheme = rm_url.scheme
        pty_url = surl.Url(rm_url)

        # this adaptor supports options that can be passed via the
        # 'query' component of the job service URL.
        if rm_url.query:
            for key, val in parse_qs(rm_url.query).iteritems():
                if key == 'queue':
                    self.queue = val[0]
                elif key == 'craytype':
                    self.is_cray = val[0]
                elif key == 'ppn':
                    self.ppn = int(val[0])
                elif key == 'gres':
                    self.gres = val[0]

        # we need to extract the scheme for PTYShell. That's basically the
        # job.Service Url without the pbs+ part. We use the PTYShell to execute
        # pbs commands either locally or via gsissh or ssh.
        if rm_scheme == "torque":
            pty_url.scheme = "fork"
        elif rm_scheme == "torque+ssh":
            pty_url.scheme = "ssh"
        elif rm_scheme == "torque+gsissh":
            pty_url.scheme = "gsissh"

        # these are the commands that we need in order to interact with PBS.
        # the adaptor will try to find them during initialize(self) and bail
        # out in case they are note available.
        self._commands = {
            'pbsnodes': dict(),
            'qstat': dict(),
            'qsub': dict(),
            'qdel': dict()
        }

        self.shell = sups.PTYShell(pty_url, self.session)

        # self.shell.set_initialize_hook(self.initialize)
        # self.shell.set_finalize_hook(self.finalize)

        self.initialize()
        return self.get_api()
Exemple #5
0
    def __init__(self,
                 url=None,
                 flags=READ,
                 session=None,
                 _adaptor=None,
                 _adaptor_state={},
                 _ttype=None):
        '''
        __init__(url=None, flags=READ, session=None)

        url:       saga.Url
        flags:     flags enum
        session:   saga.Session
        ret:       obj
        '''

        # param checks
        if not flags: flags = 0
        url = surl.Url(url)

        self._nsentry = super(LogicalFile, self)
        self._nsentry.__init__(url,
                               flags,
                               session,
                               _adaptor,
                               _adaptor_state,
                               _ttype=_ttype)
Exemple #6
0
    def __init__(self,
                 url=None,
                 session=None,
                 _adaptor=None,
                 _adaptor_state={},
                 _ttype=None):
        """
        __init__(url)

        Create a new Manager instance. Connect to a remote resource management endpoint.

        :type  url: :class:`saga.Url`
        :param url: resource management endpoint
        """

        # param checks
        _url = surl.Url(url)
        scheme = _url.scheme.lower()

        if not session:
            session = ss.Session(default=True)

        self._base = super(Manager, self)
        self._base.__init__(scheme,
                            _adaptor,
                            _adaptor_state,
                            _url,
                            session,
                            ttype=_ttype)
Exemple #7
0
    def init_instance(self, adaptor_state, rm_url, session):
        """ service instance constructor
        """

        self.rm      = rm_url
        self.session = session
        self.pe_list = list()
        self.jobs    = dict()
        self.queue   = None
        self.memreqs = None
        self.shell   = None
        self.mandatory_memreqs = list()
        self.accounting = False
        self.temp_path = "$HOME/.saga/adaptors/sge_job"


        rm_scheme = rm_url.scheme
        pty_url   = surl.Url (rm_url)

        # this adaptor supports options that can be passed via the
        # 'query' component of the job service URL.
        if rm_url.query is not None:
            for key, val in parse_qs(rm_url.query).iteritems():
                if key == 'queue':
                    self.queue = val[0]
                elif key == 'memreqs':
                    self.memreqs = val[0]

        # we need to extrac the scheme for PTYShell. That's basically the
        # job.Serivce Url withou the sge+ part. We use the PTYShell to execute
        # pbs commands either locally or via gsissh or ssh.
        if rm_scheme == "sge":
            pty_url.scheme = "fork"
        elif rm_scheme == "sge+ssh":
            pty_url.scheme = "ssh"
        elif rm_scheme == "sge+gsissh":
            pty_url.scheme = "gsissh"

        # these are the commands that we need in order to interact with SGE.
        # the adaptor will try to find them during initialize(self) and bail
        # out in case they are not available.
        self._commands = {'qstat': None,
                          'qsub':  None,
                          'qdel':  None,
                          'qconf': None,
                          'qacct': None}

        self.shell = saga.utils.pty_shell.PTYShell(pty_url, self.session)

      # self.shell.set_initialize_hook(self.initialize)
      # self.shell.set_finalize_hook(self.finalize)

        self.initialize()

        return self.get_api ()
Exemple #8
0
    def open (self, tgt, flags=READ, ttype=None) :
        '''
        open(tgt, flags=READ)

        tgt:      saga.Url
        flags:    saga.namespace.flags enum
        ttype:    saga.task.type enum
        ret:      saga.namespace.Entry / saga.Task
        '''
        if not flags : flags = 0
        tgt_url = surl.Url (tgt)
        return self._adaptor.open (tgt_url, flags, ttype=ttype)
    def __init__(self,
                 url=None,
                 flags=READ,
                 session=None,
                 _adaptor=None,
                 _adaptor_state={},
                 _ttype=None):
        """
        __init__(url, flags=READ, session)

        Construct a new directory object

        :param url:     Url of the (remote) directory
        :type  url:     :class:`saga.Url` 

        :param flags:   :ref:`filesystemflags`
        :param session: :class:`saga.Session`
        
        The specified directory is expected to exist -- otherwise
        a DoesNotExist exception is raised.  Also, the URL must point to
        a directory (not to a file), otherwise a BadParameter exception is
        raised.

        Example::

            # open some directory
            dir = saga.filesystem.Directory("sftp://localhost/tmp/")

            # and list its contents
            files = dir.list ()

        """

        # param checks
        if not flags: flags = 0
        url = surl.Url(url)

        if not url.schema:
            url.schema = 'file'

        if not url.host:
            url.host = 'localhost'

        self._nsdirec = super(Directory, self)
        self._nsdirec.__init__(url,
                               flags,
                               session,
                               _adaptor,
                               _adaptor_state,
                               _ttype=_ttype)
Exemple #10
0
    def __init__(self,
                 url=None,
                 flags=READ,
                 session=None,
                 _adaptor=None,
                 _adaptor_state={},
                 _ttype=None):
        """
        __init__(url, flags=READ, session)

        Construct a new file object

        :param url:     Url of the (remote) file
        :type  url:     :class:`saga.Url` 

        :fgs:   :ref:`filesystemflags`
        :param session: :class:`saga.Session`

        The specified file is expected to exist -- otherwise a DoesNotExist
        exception is raised.  Also, the URL must point to a file (not to
        a directory), otherwise a BadParameter exception is raised.

        Example::

            # get a file handle
            file = saga.filesystem.File("sftp://localhost/tmp/data/data.bin")
    
            # print the file's size
            print file.get_size ()
        """

        # param checks
        if not flags: flags = 0
        url = surl.Url(url)

        if not url.schema:
            url.schema = 'file'

        if not url.host:
            url.host = 'localhost'

        self._nsentry = super(File, self)
        self._nsentry.__init__(url,
                               flags,
                               session,
                               _adaptor,
                               _adaptor_state,
                               _ttype=_ttype)
Exemple #11
0
    def init_instance(self, adaptor_state, rm_url, session):
        """ service instance constructor
        """
        self.rm = rm_url
        self.session = session
        self.ppn = 0
        self.is_cray = False
        self.jobs = dict()
        self.query_options = dict()

        rm_scheme = rm_url.scheme
        pty_url = surl.Url(rm_url)

        # this adaptor supports options that can be passed via the
        # 'query' component of the job service URL.
        if rm_url.query is not None:
            for key, val in parse_qs(rm_url.query).iteritems():
                self.query_options[key] = val[0]

        # we need to extract the scheme for PTYShell. That's basically the
        # job.Service Url without the condor+ part. We use the PTYShell to
        # execute condor commands either locally or via gsissh or ssh.
        if rm_scheme == "condor":
            pty_url.scheme = "fork"
        elif rm_scheme == "condor+ssh":
            pty_url.scheme = "ssh"
        elif rm_scheme == "condor+gsissh":
            pty_url.scheme = "gsissh"

        # these are the commands that we need in order to interact with Condor.
        # the adaptor will try to find them during initialize(self) and bail
        # out in case they are not available.
        self._commands = {
            'condor_version': None,
            'condor_submit': None,
            'condor_q': None,
            'condor_history': None,
            'condor_rm': None
        }

        self.shell = saga.utils.pty_shell.PTYShell(pty_url, self.session)

        # self.shell.set_initialize_hook(self.initialize)
        # self.shell.set_finalize_hook(self.finalize)

        self.initialize()

        return self.get_api()
Exemple #12
0
    def __init__ (self, url=None, flags=READ, session=None, 
                  _adaptor=None, _adaptor_state={}, _ttype=None) : 
        '''
        __init__(url, flags=READ, session=None)

        Create a new Logical Directory instance.

        url:       saga.Url
        flags:     flags enum
        session:   saga.Session
        ret:       obj
        '''

        # param checks
        if not flags : flags = 0
        url = surl.Url (url)

        self._nsdirec = super  (LogicalDirectory, self)
        self._nsdirec.__init__ (url, flags, session, 
                                _adaptor, _adaptor_state, _ttype=_ttype)
Exemple #13
0
    def get_size (self, tgt, ttype=None) :
        '''
        get_size(tgt)

        tgt:     logical file to get size for
        ttype:    saga.task.type enum
        ret:      int / saga.Task
        
        Returns the size of the physical file represented by the given logical file (in bytes)

           Example::

               # get a logical directory handle
               lf = saga.replica.LogicalFile("irods://localhost/tmp/data/")
    
               # print a logical file's size
               print lf.get_size ('data.dat')

        '''
        tgt_url = surl.Url (tgt)
        return self._adaptor.get_size (tgt_url, ttype=ttype)
Exemple #14
0
    def open(self, path, flags=READ, ttype=None):
        """
        open(path, flags=READ)

        Open a file in the directory instance namespace. Returns
        a new file object.

        :param path:     The name/path of the file to open
        :type path:      str()
        :param flags:    :ref:`filesystemflags`
        """
        if not flags: flags = 0

        url = surl.Url(path)

        if not url.schema:
            url.schema = 'file'

        if not url.host:
            url.host = 'localhost'

        return self._adaptor.open(url, flags, ttype=ttype)
Exemple #15
0
    def __init__ (self, id=None, session=None,
                  _adaptor=None, _adaptor_state={}, _ttype=None) : 
        """
        __init__(id=None, session=None)

        Create / reconnect to a resource.

        :param id: id of the resource
        :type  id: :class:`saga.Url`
        
        :param session: :class:`saga.Session`

        Resource class instances are usually created by calling :func:`acquire`
        on the :class:`saga.resource.Manager` class.  Already acquired resources
        are identified by a string typed identifier.  This constructor accepts
        such an identifier to create another representation of the same
        resource.  As the resource itself is new newly acquired, it can be in
        any state.  In particular, it can be in a final state, and thus be
        unusable.  Further, the resource may already have expired or failed, and
        the information about it may have been purged -- in that case the id
        will not be valid any longer, and a :class:`saga.BadParameter` exception
        will be raised.

        The session parameter is interpreted exactly as the session parameter on
        the :class:`saga.resource.Manager` constructor.
        """

        # set attribute interface properties

        import saga.attributes as sa

        self._attributes_extensible  (False)
        self._attributes_camelcasing (True)

        # register properties with the attribute interface

        self._attributes_register  (const.ID          , None, sa.ENUM,   sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.RTYPE       , None, sa.ENUM,   sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.STATE       , None, sa.ENUM,   sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.STATE_DETAIL, None, sa.STRING, sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.ACCESS      , None, sa.URL,    sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.MANAGER     , None, sa.URL,    sa.SCALAR, sa.READONLY)
        self._attributes_register  (const.DESCRIPTION , None, sa.ANY,    sa.SCALAR, sa.READONLY)

        self._attributes_set_enums (const.STATE, [const.UNKNOWN ,
                                                  const.PENDING ,
                                                  const.ACTIVE  ,
                                                  const.CANCELED,
                                                  const.EXPIRED ,
                                                  const.FAILED  ,
                                                  const.FINAL   ])

        self._attributes_set_enums (const.RTYPE, [const.COMPUTE ,
                                                  const.STORAGE ,
                                                  const.NETWORK ])


        self._attributes_set_getter (const.ID          , self.get_id          )
        self._attributes_set_getter (const.RTYPE       , self.get_rtype       )
        self._attributes_set_getter (const.STATE       , self.get_state       )
        self._attributes_set_getter (const.STATE_DETAIL, self.get_state_detail)
        self._attributes_set_getter (const.ACCESS      , self.get_access      )
        self._attributes_set_getter (const.MANAGER     , self.get_manager     )
        self._attributes_set_getter (const.DESCRIPTION , self.get_description )


        # FIXME: we need the ID to be or to include an URL, as we don't have
        # a scheme otherwise, which means we can't select an adaptor.  Duh! :-/
        
        # FIXME: documentation for attributes is missing.

        # param checks
        scheme = None
        if  not id :
            if  not 'resource_schema' in _adaptor_state :
                raise se.BadParameter ("Cannot initialize resource without id" \
                                    % self.rtype)
            else :
                scheme = _adaptor_state['resource_schema']
        else :
            url    = surl.Url (id)
            scheme = url.scheme.lower ()


        if not session :
            session = ss.Session (default=True)

        self._base = super  (Resource, self)
        self._base.__init__ (scheme, _adaptor, _adaptor_state, 
                             id, session, ttype=_ttype)
Exemple #16
0
    def init_instance(self, adaptor_state, rm_url, session):
        """ service instance constructor
        """
        self.rm = rm_url
        self.session = session
        self.ppn = 0  # check for remove
        self.jobs = dict()
        self.cluster_option = ''
        self.energy_policy_tag = None
        self.island_count = None
        self.node_usage = None
        self.network_mpi = None
        self.blocking = None
        self.job_type = 'MPICH'  # TODO: Is this a sane default?
        self.enforce_resource_submission = False
        self.enforce_consumable_cpus = False
        self.enforce_consumable_memory = False
        self.enforce_consumable_virtual_memory = False
        self.enforce_consumable_large_page_memory = False
        self.temp_path = "$HOME/.saga/adaptors/loadl_job"

        # LoadLeveler has two ways of specifying the executable and arguments.
        # - Explicit: the executable and arguments are specified as parameters.
        # - Implicit: the (remainder of the) job script is the task.
        #
        # Currently we don't know how this policy can be detected at runtime.
        # We know that providing both will not work in all cases.
        #
        # As the IBM Red Book documents the explicit exec only,
        # we should use that as a default.
        # Currently we just use a hack to workaround Joule.
        #
        # Note: does this now simply become a Joule hack?
        #
        # TODO: Split script into submission file and script and use that for
        #       explicit exec?
        self.explicit_exec = False

        rm_scheme = rm_url.scheme
        pty_url = surl.Url(rm_url)

        # this adaptor supports options that can be passed via the
        # 'query' component of the job service URL.
        if rm_url.query is not None:
            for key, val in parse_qs(rm_url.query).iteritems():
                if key == 'cluster':
                    self.cluster_option = " -X %s" % val[0]
                elif key == 'energy_policy_tag':
                    self.energy_policy_tag = val[0]
                elif key == 'island_count':
                    self.island_count = val[0]
                elif key == 'node_usage':
                    self.node_usage = val[0]
                elif key == 'network_mpi':
                    self.network_mpi = val[0]
                elif key == 'blocking':
                    self.blocking = val[0]
                elif key == 'job_type':
                    self.job_type = val[0]
                elif key == 'enforce_consumable_cpus':
                    self.enforce_consumable_cpus = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_memory':
                    self.enforce_consumable_memory = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_virtual_memory':
                    self.enforce_consumable_virtual_memory = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_large_page_memory':
                    self.enforce_consumable_large_page_memory = True
                    self.enforce_resource_submission = True
                elif key == 'explicit_exec':
                    self.explicit_exec = True

        # we need to extract the scheme for PTYShell. That's basically the
        # job.Service Url without the loadl+ part. We use the PTYShell to execute
        # loadleveler commands either locally or via gsissh or ssh.
        if rm_scheme == "loadl":
            pty_url.scheme = "fork"
        elif rm_scheme == "loadl+ssh":
            pty_url.scheme = "ssh"
        elif rm_scheme == "loadl+gsissh":
            pty_url.scheme = "gsissh"

        # these are the commands that we need in order to interact with Load Leveler.
        # the adaptor will try to find them during initialize(self) and bail
        # out in case they are note avaialbe.
        self._commands = {'llq': None, 'llsubmit': None, 'llcancel': None}

        self.shell = saga.utils.pty_shell.PTYShell(pty_url, self.session)

        #self.shell.set_initialize_hook(self.initialize)
        #self.shell.set_finalize_hook(self.finalize)

        self.initialize()

        return self.get_api()
Exemple #17
0
    def _job_run(self, jd):
        """ runs a job via qsub
        """

        # Because we do funky shit with env and sh, we need to explicitly add
        # the executable to the transfer list.
        # (Of course not if the executable is already on the target systems,
        # defined by the fact that it starts with ./
        if jd.executable.startswith('./') and os.path.exists(jd.executable):

            # TODO: Check if the executable is already in the file_transfer list,
            # because then we don't need to implicitly add it anymore.
            # (For example, if the executable is not in the local directory, it needs
            # to be explicitly added.)

            exe = jd.executable[len('./'):]
            exe_transfer = '%s > %s' % (exe, exe)

            if jd.file_transfer:
                jd.file_transfer.append(exe_transfer)
            else:
                jd.file_transfer = [exe_transfer]

        if jd.file_transfer is not None:
            jd.transfer_directives = TransferDirectives(jd.file_transfer)

            self._handle_file_transfers(jd)

            td = jd.transfer_directives
            if not (hasattr(td, 'transfer_output_files')
                    or hasattr(td, 'transfer_input_files')):
                raise RuntimeError('One of them should be set!')

        # create a Condor job script from SAGA job description
        script = _condorscript_generator(url=self.rm,
                                         logger=self._logger,
                                         jd=jd,
                                         option_dict=self.query_options)
        self._logger.info("Generated Condor script: %s" % script)

        submit_file = NamedTemporaryFile(mode='w',
                                         suffix='.condor',
                                         prefix='tmp-saga-',
                                         delete=False)
        submit_file.write(script)
        submit_file.close()
        self._logger.info("Written Condor script locally: %s" %
                          submit_file.name)

        if self.shell.url.scheme == "ssh":
            self._logger.info("Transferring Condor script to: %s" %
                              self.shell.url)
            submit_file_name = os.path.basename(submit_file.name)
            self.shell.stage_to_remote(submit_file.name,
                                       submit_file_name,
                                       cp_flags="-P")

        elif self.shell.url.scheme == "gsissh":
            raise NotImplemented("GSISSH support for Condor not implemented.")
        else:
            submit_file_name = submit_file.name


        ret, out, _ = self.shell.run_sync('%s -verbose %s' \
            % (self._commands['condor_submit']['path'], submit_file_name))

        if ret != 0:
            # something went wrong
            message = "Error running job via 'condor_submit': %s. Script was: %s" \
                % (out, script)
            log_error_and_raise(message, saga.NoSuccess, self._logger)
        else:
            # stdout contains the job id
            for line in out.split("\n"):
                if "** Proc" in line:
                    pid = line.split()[2][:-1]

            # we don't want the 'query' part of the URL to be part of the ID,
            # simply because it can get terribly long (and ugly). to get rid
            # of it, we clone the URL and set the query part to None.
            rm_clone = surl.Url(self.rm)
            rm_clone.query = ""
            rm_clone.path = ""

            job_id = "[%s]-[%s]" % (rm_clone, pid)
            self._logger.info("Submitted Condor job with id: %s" % job_id)

            # add job to internal list of known jobs.
            self.jobs[job_id] = {
                'state': saga.job.PENDING,
                'exec_hosts': None,
                'returncode': None,
                'create_time': None,
                'start_time': None,
                'end_time': None,
                'gone': False,
                'transfers': None,
                'stdout': None,
                'stderr': None
            }

            # remove submit file(s)
            # XXX: maybe leave them in case of debugging?
            if self.shell.url.scheme == 'ssh':
                ret, out, _ = self.shell.run_sync('rm %s' % submit_file_name)
            elif self.shell.url.scheme == 'gsissh':
                raise NotImplemented(
                    "GSISSH support for Condor not implemented.")
            os.remove(submit_file.name)

            return job_id
Exemple #18
0
    def copy(self, tgt, flags=0, ttype=None):
        '''
        tgt:           saga.Url
        flags:         enum flags
        ttype:         saga.task.type enum
        ret:           None / saga.Task
        
        Copy the entry to another location
    
        :param target: Url of the copy target.
        :param flags: Flags to use for the operation.
    
        The entry is copied to the given target location.  The target URL must
        be an absolute path, and can be a target entry name or target
        directory name.  If the target entry exists, it is overwritten::
    
            # copy an entry
            entry = saga.namespace.Directory("sftp://localhost/tmp/data/data.bin")
            entry.copy ("sftp://localhost/tmp/data/data.bak")
        '''

        # parameter checks
        if not flags: flags = 0
        tgt_url = surl.Url(tgt)  # ensure valid and typed Url

        # async ops don't deserve a fallback (yet)
        if ttype != None:
            return self._adaptor.copy_self(tgt_url, flags, ttype=ttype)

        # we have only sync calls here - attempt a normal call to the bound
        # adaptor first (doh!)
        ret = self._adaptor.copy_self(tgt_url, flags, ttype=ttype)

        try:
            True

        except se.SagaException as e:
            # if we don't have a scheme for tgt, all is in vain (adaptor
            # should have handled a relative path...)
            if not tgt_url.scheme:
                raise e

            # So, the adaptor bound to the src URL did not manage to copy the # entry.
            # If the tgt has a scheme set, we try again with other matching # entry
            # adaptors,  by setting (a copy of) the *src* URL to the same scheme,
            # in the hope that other adaptors can copy from localhost.
            #
            # In principle that mechanism can also be used for remote copies, but
            # URL translation is way more fragile in those cases...

            # check recursion guard
            if self._is_recursive:
                self._logger.debug("fallback recursion detected - abort")

            else:
                # activate recursion guard
                self._is_recursive += 1

                import saga.engine
                engine = saga.engine.Engine()

                # find applicable adaptors we could fall back to, i.e. which
                # support the tgt schema
                adaptor_names = engine.find_adaptors('saga.namespace.Entry',
                                                     tgt_url.scheme)

                self._logger.debug("try fallback copy to these adaptors: %s" %
                                   adaptor_names)

                # build a new src url, by switching to the target schema
                tmp_url = self.get_url()
                tmp_url.scheme = tgt_url.scheme

                for adaptor_name in adaptor_names:

                    try:
                        self._logger.info("try fallback copy to %s" %
                                          adaptor_name)

                        adaptor_instance = engine.get_adaptor(adaptor_name)

                        # get an tgt-scheme'd adaptor for the new src url, and try copy again
                        adaptor = engine.bind_adaptor(self,
                                                      'saga.namespace.Entry',
                                                      tgt_url.scheme,
                                                      adaptor_instance)
                        adaptor.init_instance({}, tmp_url, None, self._session)
                        tmp = Entry(tmp_url,
                                    None,
                                    self._session,
                                    _adaptor=adaptor_instance)

                        ret = tmp.copy(tgt_url, flags)

                        # release recursion guard
                        self._is_recursive -= 1

                        # if nothing raised an exception so far, we are done.
                        return

                    except se.SagaException as e:

                        self._logger.info("fallback failed: %s" % e)

                        # didn't work, ignore this adaptor
                        pass

            # if all was in vain, we rethrow the original exception
            self._is_recursive -= 1
            raise e
Exemple #19
0
    def init_instance(self, adaptor_state, rm_url, session):
        """ service instance constructor
        """
        self.rm = rm_url
        self.session = session
        self.ppn = 0  # check for remove
        self.jobs = dict()
        self.cluster_option = ''
        self.energy_policy_tag = None
        self.island_count = None
        self.node_usage = None
        self.network_mpi = None
        self.blocking = None
        self.enforce_resource_submission = False
        self.enforce_consumable_cpus = False
        self.enforce_consumable_memory = False
        self.enforce_consumable_virtual_memory = False
        self.enforce_consumable_large_page_memory = False
        self.temp_path = "$HOME/.saga/adaptors/loadl_job"

        rm_scheme = rm_url.scheme
        pty_url = surl.Url(rm_url)

        # this adaptor supports options that can be passed via the
        # 'query' component of the job service URL.
        if rm_url.query is not None:
            for key, val in parse_qs(rm_url.query).iteritems():
                if key == 'cluster':
                    self.cluster_option = " -X %s" % val[0]
                elif key == 'energy_policy_tag':
                    self.energy_policy_tag = val[0]
                elif key == 'island_count':
                    self.island_count = val[0]
                elif key == 'node_usage':
                    self.node_usage = val[0]
                elif key == 'network_mpi':
                    self.network_mpi = val[0]
                elif key == 'blocking':
                    self.blocking = val[0]
                elif key == 'enforce_consumable_cpus':
                    self.enforce_consumable_cpus = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_memory':
                    self.enforce_consumable_memory = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_virtual_memory':
                    self.enforce_consumable_virtual_memory = True
                    self.enforce_resource_submission = True
                elif key == 'enforce_consumable_large_page_memory':
                    self.enforce_consumable_large_page_memory = True
                    self.enforce_resource_submission = True

        # we need to extract the scheme for PTYShell. That's basically the
        # job.Service Url without the loadl+ part. We use the PTYShell to execute
        # loadleveler commands either locally or via gsissh or ssh.
        if rm_scheme == "loadl":
            pty_url.scheme = "fork"
        elif rm_scheme == "loadl+ssh":
            pty_url.scheme = "ssh"
        elif rm_scheme == "loadl+gsissh":
            pty_url.scheme = "gsissh"

        # these are the commands that we need in order to interact with Load Leveler.
        # the adaptor will try to find them during initialize(self) and bail
        # out in case they are note avaialbe.
        self._commands = {'llq': None, 'llsubmit': None, 'llcancel': None}

        self.shell = saga.utils.pty_shell.PTYShell(pty_url, self.session)

        #self.shell.set_initialize_hook(self.initialize)
        #self.shell.set_finalize_hook(self.finalize)

        self.initialize()

        return self.get_api()