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
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)
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()
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)
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)
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 ()
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)
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)
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()
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)
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)
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)
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)
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()
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
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
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()