python-irodsclient icon indicating copy to clipboard operation
python-irodsclient copied to clipboard

Nonexistent data object raises CollectionDoesNotExist

Open jpmcfarland opened this issue 3 years ago • 3 comments

Trying to instantiate a data object with a random string results in a terminal CollectionDoesNotExist exception:

import irods
import irods.session
import os
import ssl
env_file = os.path.expanduser('~/.irods/irods_environment.json')
ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)
ssl_settings = {'ssl_context': ssl_context}
sess =  irods.session.iRODSSession(irods_env_file=env_file, **ssl_settings)
data_obj = sess.data_objects.get('random string')
---------------------------------------------------------------------------
NoResultFound                             Traceback (most recent call last)
~/.local/lib/python3.9/site-packages/irods/manager/collection_manager.py in get(self, path)
     22             try:
---> 23                 result = query.one()
     24             except NoResultFound:

~/.local/lib/python3.9/site-packages/irods/query.py in one(self)
    223         if not len(results):
--> 224             raise NoResultFound()
    225         if len(results) > 1:

NoResultFound: 

During handling of the above exception, another exception occurred:

CollectionDoesNotExist                    Traceback (most recent call last)
<ipython-input-6-6527f0f3af7b> in <module>
----> 1 data_obj = sess.data_objects.get('random string')

~/.local/lib/python3.9/site-packages/irods/manager/data_object_manager.py in get(self, path, local_path, num_threads, **options)
    116         a path in the local filesystem to use as a destination file).
    117         """
--> 118         parent = self.sess.collections.get(irods_dirname(path))
    119 
    120         # TODO: optimize

~/.local/lib/python3.9/site-packages/irods/manager/collection_manager.py in get(self, path)
     26                     filters += [DataObject.id != 0]
     27                     continue
---> 28                 raise CollectionDoesNotExist()
     29             return iRODSCollection(self, result)
     30 

CollectionDoesNotExist:

Repeating this with the path of almost any existing collection results in a DataObjectDoesNotExist exception as expected:

data_obj = sess.data_objects.get('/testZone/home/irods')
---------------------------------------------------------------------------
DataObjectDoesNotExist                    Traceback (most recent call last)
<ipython-input-8-390920935936> in <module>
----> 1 data_obj = sess.data_objects.get('/testZone/home/irods')

~/.local/lib/python3.9/site-packages/irods/manager/data_object_manager.py in get(self, path, local_path, num_threads, **options)
    133         results = query.all() # get up to max_rows replicas
    134         if len(results) <= 0:
--> 135             raise ex.DataObjectDoesNotExist()
    136         return iRODSDataObject(self, parent, results)
    137 

DataObjectDoesNotExist:

But, using using the path to the existing collections /<zone> or /<zone>/home (I know they're special, but still) results in the terminal CollectionDoesNotExist exception as above.

This is inconsistent at best and confusing at worst.

print(irods.__version__)
1.1.4

jpmcfarland avatar Aug 10 '22 15:08 jpmcfarland

PRC has historically done a query to see if the collection component of the requested new data object exists, and of course the Genquery is unable to distinguish between a collection it cannot write and one that doesn't exist.

Interestingly, this is not a problem for itouch

$ itouch /tempZone/a
Level 0: no permission to update collection '/tempZone'
Level 1: CAT_NOT_A_DATAOBJ_AND_NOT_A_COLLECTION: Logical path does not point to a collection or data object.


vagrant@ubun18x:~$ itouch /tempZones/a
Level 0: collection '/tempZones' is unknown
Level 1: CAT_NOT_A_DATAOBJ_AND_NOT_A_COLLECTION: Logical path does not point to a collection or data object.

Perhaps @korydraughn or @alanking knows of a simple API that can distinguish the existence (as opposed to write-inaccessibility) of a path in iRODS. It would then only remain to teach the PRC to use that API....

d-w-moore avatar Aug 11 '22 12:08 d-w-moore

Those Level 0 messages are not specific to itouch. They come from the database plugin.

The touch API uses the filesystem library to do existence checks. Those calls fail if the user does not have the correct permissions. The Level 1 messages come from the touch API. Notice that both invocations result in the same message.

All of that to say, as a rodsuser, it is not possible to do existence checks on paths they don't have access to. Only rodsadmin users can do that.

korydraughn avatar Aug 11 '22 12:08 korydraughn

Well, in answer, @jpmcfarland , I'll have to say that the permission model in iRODS is widely one that opts for less information and more security, and at times that approach might yield less than an ideal amount of useful information (or, if you like, create more confusion than would be ideal ; ) ). A database query won't reveal the presence of a collection unless you've explicitly been granted permissions, at least at the level of read access, on it. By way of a counterexample, UNIX gives you read permission on almost everything, so it knows to tell you it's there but you don't have permission to write.

So if you - for example - ask to create an object called "a random data object" (which, I suppose scans to have a zero-length collection path component, and that by definition doesn't exist) or otherwise a collection path which iRODS won't let you query, my guess is "Collection Doesn't Exist" is the best de facto reasonable indication the Python client , or an icommand for that matter, could give you. (If you don't count the rError stack coming back with those clues for itouch).

If, within that model, you have an idea about a less confusing indication the Python client could give instead, I'd welcome and consider it.

d-w-moore avatar Aug 11 '22 16:08 d-w-moore