From 3a71a1959224ce64bf06fd4908df08e65735574b Mon Sep 17 00:00:00 2001
From: vermeul <swen@ethz.ch>
Date: Tue, 11 Feb 2020 11:39:09 +0100
Subject: [PATCH] added more instructions for mount(), implemented _password()
 method

---
 pybis/src/python/pybis/pybis.py | 147 +++++++++++++++++++++++++-------
 1 file changed, 114 insertions(+), 33 deletions(-)

diff --git a/pybis/src/python/pybis/pybis.py b/pybis/src/python/pybis/pybis.py
index 4e655b0fe11..5b01f1fd2c2 100644
--- a/pybis/src/python/pybis/pybis.py
+++ b/pybis/src/python/pybis/pybis.py
@@ -565,21 +565,21 @@ def _subcriteria_for_code(code, entity):
     Example::
         _subcriteria_for_code("username", "space")
 
-	{
-	    "criteria": [
-		{
-		    "fieldType": "ATTRIBUTE",
-		    "@type": "as.dto.common.search.CodeSearchCriteria",
-		    "fieldName": "code",
-		    "fieldValue": {
-			"@type": "as.dto.common.search.StringEqualToValue",
-			"value": "USERNAME"
-		    }
-		}
-	    ],
-	    "operator": "AND",
-	    "@type": "as.dto.space.search.SpaceSearchCriteria"
-	}
+    {
+        "criteria": [
+            {
+                "fieldType": "ATTRIBUTE",
+                "@type": "as.dto.common.search.CodeSearchCriteria",
+                "fieldName": "code",
+                "fieldValue": {
+                    "@type": "as.dto.common.search.StringEqualToValue",
+                    "value": "USERNAME"
+                }
+            }
+        ],
+        "operator": "AND",
+        "@type": "as.dto.space.search.SpaceSearchCriteria"
+    }
     """
     if code is not None:
         if is_permid(code):
@@ -682,6 +682,13 @@ class Openbis:
             print("Session is no longer valid. Please log in again.")
 
 
+    def _get_username(self):
+        if self.token:
+            username, rest = self.token.split('-')
+            return username
+        return ''
+
+
     def __dir__(self):
         return [
             'url', 'port', 'hostname', 'token',
@@ -689,6 +696,8 @@ class Openbis:
             'logout()', 
             'is_session_active()', 
             'is_token_valid()',
+            "mount()",
+            "unmount()",
             "get_server_information()",
             "get_dataset()",
             "get_datasets()",
@@ -929,11 +938,26 @@ class Openbis:
 
             if save_token:
                 self.save_token()
+                self._password(password)
             # update the OPENBIS_TOKEN environment variable, if OPENBIS_URL is identical to self.url
             if os.environ.get('OPENBIS_URL') == self.url:
                 os.environ['OPENBIS_TOKEN'] = self.token
             return self.token
 
+    def _password(self, password=None, pstore={} ):
+        """An elegant way to store passwords which are used later
+        without giving the user an easy possibility to retrieve it.
+        """
+        import inspect
+        allowed_methods = ['mount']
+
+        if password is not None:
+            pstore['password'] = password
+        else:
+            if inspect.stack()[1][3] in allowed_methods:
+                return pstore.get('password')
+            else:
+                raise Exception("This method can only be called from these internal methods: {}".format(allowed_methods))
 
     def unmount(self, mountpoint=None):
         """Unmount a given mountpoint or unmount the stored mountpoint.
@@ -979,10 +1003,54 @@ class Openbis:
 
         return os.path.ismount(mountpoint)
 
+    def get_mountpoint(self):
+        """Returns the path to the active mountpoint.
+        Returns None if no mountpoint is found or if the mountpoint is not mounted anymore.
+        Experimental: Tries to figure out an existing mountpoint for a given hostname.
+        """
+
+        mountpoint = getattr(self, 'mountpoint', None)
+        if mountpoint:
+            if self.is_mounted(mountpoint):
+                return mountpoint
+            else:
+                return None
+
+        # try to find out the mountpoint
+        import subprocess
+        p1 = subprocess.Popen(["mount", "-d"], stdout=subprocess.PIPE)
+        p2 = subprocess.Popen(["grep", "--fixed-strings", self.hostname], stdin=p1.stdout, stdout=subprocess.PIPE)
+        p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
+        output = p2.communicate()[0]
+        output = output.decode()
+        # output will either be '' (=not mounted) or a string like this:
+        # {username}@{hostname}:{path} on {mountpoint} (osxfuse, nodev, nosuid, synchronous, mounted by vermeul)
+        try:
+            mountpoint = output.split()[2]
+            self.mountpoint = mountpoint
+            return mountpoint
+        except Exception:
+            return None
+
+
+    def mount(self,
+        username=None, password=None,
+        hostname=None, mountpoint=None,
+        volname=None, path='/', port=2222,
+        kex_algorithms ='+diffie-hellman-group1-sha1'
+    ):
+
+        """Mounts openBIS dataStore without being root, using sshfs and fuse. Both
+        SSHFS and FUSE must be installed on the system (see below)
+
+        Params:
+        username -- default: the currently used username
+        password -- default: the currently used password
+        hostname -- default: the current hostname
+        mountpoint -- default: ~/hostname
 
-    def mount(self, username, password, servername, mountpoint, volname=None, path='/', port=2222, kex_algorithms ='+diffie-hellman-group1-sha1'):
 
-        """Mounts openBIS dataStore without being root, using sshfs and fuse. Both SSHFS and FUSE must be installed on the system (the installation requires root privileges):
+        FUSE / SSHFS Installation (requires root privileges):
 
         Mac OS X
         ========
@@ -995,7 +1063,11 @@ class Openbis:
         $ sudo yum --enablerepo=epel -y install fuse-sshfs
         $ user="$(whoami)"
         $ usermod -a -G fuse "$user"
+
         """
+        if self.is_mounted():
+            if VERBOSE: print("openBIS dataStore is already mounted on {}".format(self.mountpoint))
+            return
 
         def check_sshfs_is_installed():
             import subprocess
@@ -1008,6 +1080,17 @@ class Openbis:
 
         check_sshfs_is_installed()
 
+        if username is None: username = self._get_username()
+        if not username: raise ValueError("no token available - pleas provide a username")
+        if password is None: password = self._password()
+        if not password: raise ValueError("please provide a password")
+
+        if hostname is None: hostname = self.hostname
+        if not hostname: raise ValueError("please provide a hostname")
+
+        if mountpoint is None: mountpoint = os.path.join('~', self.hostname)
+
+
         # check if mountpoint exists, otherwise create it
         full_mountpoint_path = os.path.abspath(os.path.expanduser(mountpoint))
         if not os.path.exists(full_mountpoint_path):
@@ -1022,18 +1105,18 @@ class Openbis:
 
 
         os_options = {
-            "darwin": "-oauto_cache,reconnect,defer_permissions,noappledouble,negative_vncache,volname={}".format(servername),
+            "darwin": "-oauto_cache,reconnect,defer_permissions,noappledouble,negative_vncache,volname={}".format(hostname),
             "linux": "-oauto_cache,reconnect",
         }
 
         if volname is None:
-            volname = servername
+            volname = hostname
 
         import subprocess
         args = {
             "username": username,
             "password": password,
-            "servername": servername,
+            "hostname": hostname,
             "port": port,
             "path": path,
             "mountpoint": mountpoint,
@@ -1043,7 +1126,7 @@ class Openbis:
         }
 
         cmd = 'echo "{password}" | sshfs'\
-              ' {username}@{servername}:{path} {mountpoint}' \
+              ' {username}@{hostname}:{path} {mountpoint}' \
               ' -o port={port} -o ssh_command="ssh -oKexAlgorithms={kex_algorithms}" -o password_stdin'\
               ' {os_options}'.format(**args)
 
@@ -1403,18 +1486,16 @@ class Openbis:
             "method": "createRoleAssignments",
             "params": [
                 self.token,
-                [
-	            {
-                        "role": role,
-                        "userId": userId,
-		        "authorizationGroupId": groupId,
-                        "spaceId": spaceId,
-		        "projectId": projectId,
-		        "@type": "as.dto.roleassignment.create.RoleAssignmentCreation",
-	            }
-	        ]
-	    ]
-	}
+                [ {
+                    "role": role,
+                    "userId": userId,
+                    "authorizationGroupId": groupId,
+                    "spaceId": spaceId,
+                    "projectId": projectId,
+                    "@type": "as.dto.roleassignment.create.RoleAssignmentCreation",
+                } ]
+            ]
+        }
         resp = self._post_request(self.as_v3, request)
         return
 
-- 
GitLab