Repository: conda/conda

Issue:
[Regression] Conda create environment fails on lock if root environment is not under user control
This is "funny", but it seems that Conda managed to break this thing the second time in a month... #2681 was the previous one.

This time, I get the following error:

```
$ conda create -n _root --yes --use-index-cache python=3 
...
    Traceback (most recent call last):
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/exceptions.py", line 442, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/main.py", line 144, in _main
        exit_code = args.func(args, p)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/main_create.py", line 66, in execute
        install(args, parser, 'create')
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/install.py", line 399, in install
        execute_actions(actions, index, verbose=not args.quiet)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/plan.py", line 640, in execute_actions
        inst.execute_instructions(plan, index, verbose)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/instructions.py", line 132, in execute_instructions
        cmd(state, arg)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/instructions.py", line 77, in LINK_CMD
        link(state['prefix'], dist, lt, index=state['index'])
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/install.py", line 1060, in link
        with DirectoryLock(prefix), FileLock(source_dir):
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 86, in __enter__
        touch(self.lock_file_path)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
    PermissionError: [Errno 13] Permission denied: '/usr/local/miniconda/pkgs/openssl-1.0.2h-1.pid34.conda_lock'
```

```
Current conda install:

               platform : linux-64
          conda version : 4.2.2
       conda is private : False
      conda-env version : 2.6.0
    conda-build version : 1.21.11+0.g5b44ab3.dirty
         python version : 3.5.2.final.0
       requests version : 2.10.0
       root environment : /usr/local/miniconda  (read only)
    default environment : /usr/local/miniconda
       envs directories : /home/gitlab-ci/.conda/envs
                          /usr/local/miniconda/envs
          package cache : /home/gitlab-ci/.conda/envs/.pkgs
                          /usr/local/miniconda/pkgs
           channel URLs : defaults
            config file : None
           offline mode : False
```

/CC @kalefranz

[Regression] Conda create environment fails on lock if root environment is not under user control
This is "funny", but it seems that Conda managed to break this thing the second time in a month... #2681 was the previous one.

This time, I get the following error:

```
$ conda create -n _root --yes --use-index-cache python=3 
...
    Traceback (most recent call last):
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/exceptions.py", line 442, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/main.py", line 144, in _main
        exit_code = args.func(args, p)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/main_create.py", line 66, in execute
        install(args, parser, 'create')
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/cli/install.py", line 399, in install
        execute_actions(actions, index, verbose=not args.quiet)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/plan.py", line 640, in execute_actions
        inst.execute_instructions(plan, index, verbose)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/instructions.py", line 132, in execute_instructions
        cmd(state, arg)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/instructions.py", line 77, in LINK_CMD
        link(state['prefix'], dist, lt, index=state['index'])
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/install.py", line 1060, in link
        with DirectoryLock(prefix), FileLock(source_dir):
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 86, in __enter__
        touch(self.lock_file_path)
      File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
    PermissionError: [Errno 13] Permission denied: '/usr/local/miniconda/pkgs/openssl-1.0.2h-1.pid34.conda_lock'
```

```
Current conda install:

               platform : linux-64
          conda version : 4.2.2
       conda is private : False
      conda-env version : 2.6.0
    conda-build version : 1.21.11+0.g5b44ab3.dirty
         python version : 3.5.2.final.0
       requests version : 2.10.0
       root environment : /usr/local/miniconda  (read only)
    default environment : /usr/local/miniconda
       envs directories : /home/gitlab-ci/.conda/envs
                          /usr/local/miniconda/envs
          package cache : /home/gitlab-ci/.conda/envs/.pkgs
                          /usr/local/miniconda/pkgs
           channel URLs : defaults
            config file : None
           offline mode : False
```

/CC @kalefranz



Discussion:
@frol, First, **thanks for using canary**!!  Do you know if a previous run of conda crashed, exited prematurely, or you sent a signal (i.e. ctrl-c) for it to exit early?  Something made that lock file stick around...

```
conda clean --yes --lock
```

should take care of it for you.  If it doesn't, that's definitely a bug.

We're still working on tuning the locking in conda.  It's (hopefully) better in 4.2 than it was in 4.1, and I know for sure it will be better yet in 4.3 with @HugoTian's work in #3197.

@kalefranz The error message is quite informative:

```
     File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
   PermissionError: [Errno 13] Permission denied: '/usr/local/miniconda/pkgs/openssl-1.0.2h-1.pid34.conda_lock'
```

`/usr/local/miniconda` is a read-only directory, so there is no way `open(mode='a')` will ever succeed there.

Ahh. This then is what I generally call "multi-user support." That is, install conda as one user, and use the executable as another but without write permissions to the conda executable's root environment. 

This used case has always been problematic, and it's s high priority to tackle and "get right" in the next several months. 

I think I just ran into this, created a env in a central install area, then from a user account tried to clone the environment, but it failed with something similar, doing

`conda create --offline -n myrel --clone anarel-1.0.0
`
caused

```
...
WARNING conda.install:warn_failed_remove(178): Cannot remove, permission denied: /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/psana-conda-1.0.0-py27_1/bin
WARNING conda.install:warn_failed_remove(178): Cannot remove, permission denied: /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/psana-conda-1.0.0-py27_1
Pruning fetched packages from the cache ...
An unexpected error has occurred.
Please consider posting the following information to the
conda GitHub issue tracker at:

    https://github.com/conda/conda/issues



Current conda install:

               platform : linux-64
          conda version : 4.2.3
       conda is private : False
      conda-env version : 2.6.0
    conda-build version : 1.21.11+0.g5b44ab3.dirty
         python version : 2.7.12.final.0
       requests version : 2.10.0
       root environment : /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7  (read only)
    default environment : /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs/anarel-1.0.0
       envs directories : /reg/neh/home/davidsch/.conda/envs
                          /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs
          package cache : /reg/neh/home/davidsch/.conda/envs/.pkgs
                          /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs
           channel URLs : file:///reg/g/psdm/sw/conda/channels/system-rhel7
                          file:///reg/g/psdm/sw/conda/channels/external-rhel7
                          defaults
                          file:///reg/g/psdm/sw/conda/channels/psana-rhel7
                          scikit-beam
                          file:///reg/g/psdm/sw/conda/channels/testing-rhel7
            config file : /reg/neh/home/davidsch/.condarc
           offline mode : False



`$ /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs/anarel-1.0.0/bin/conda create --offline -n myrel --clone anarel-1.0.0`




    Traceback (most recent call last):
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/exceptions.py", line 442, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/main.py", line 144, in _main
        exit_code = args.func(args, p)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/main_create.py", line 66, in execute
        install(args, parser, 'create')
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/install.py", line 225, in install
        clone(args.clone, prefix, json=args.json, quiet=args.quiet, index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/install.py", line 90, in clone
        index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/misc.py", line 388, in clone_env
        force_extract=False, index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/misc.py", line 188, in explicit
        execute_actions(actions, index=index, verbose=verbose)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/plan.py", line 639, in execute_actions
        inst.execute_instructions(plan, index, verbose)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/instructions.py", line 132, in execute_instructions
        cmd(state, arg)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/instructions.py", line 66, in RM_FETCHED_CMD
        rm_fetched(arg)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/install.py", line 801, in rm_fetched
        with FileLock(fname):
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/lock.py", line 86, in __enter__
        touch(self.lock_file_path)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
    IOError: [Errno 13] Permission denied: u'/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/openmpi-1.10.3-lsf_verbs_100.tar.bz2.pid17825.conda_lock'

```

@HugoTian As part of the 4.2 release, I think we need a lock cleanup step in the exception handler that just attempts to clean up any lock files for the current pid before it ultimately exits.  Do you agree?

@kalefranz , Moreover,  I think some how we need to bring back the try/except block when we create the lock file.

Something like : 

```
         try:
            touch(****)
        except OSError:
            pass
```

@frol, First, **thanks for using canary**!!  Do you know if a previous run of conda crashed, exited prematurely, or you sent a signal (i.e. ctrl-c) for it to exit early?  Something made that lock file stick around...

```
conda clean --yes --lock
```

should take care of it for you.  If it doesn't, that's definitely a bug.

We're still working on tuning the locking in conda.  It's (hopefully) better in 4.2 than it was in 4.1, and I know for sure it will be better yet in 4.3 with @HugoTian's work in #3197.

@kalefranz The error message is quite informative:

```
     File "/usr/local/miniconda/lib/python3.5/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
   PermissionError: [Errno 13] Permission denied: '/usr/local/miniconda/pkgs/openssl-1.0.2h-1.pid34.conda_lock'
```

`/usr/local/miniconda` is a read-only directory, so there is no way `open(mode='a')` will ever succeed there.

Ahh. This then is what I generally call "multi-user support." That is, install conda as one user, and use the executable as another but without write permissions to the conda executable's root environment. 

This used case has always been problematic, and it's s high priority to tackle and "get right" in the next several months. 

I think I just ran into this, created a env in a central install area, then from a user account tried to clone the environment, but it failed with something similar, doing

`conda create --offline -n myrel --clone anarel-1.0.0
`
caused

```
...
WARNING conda.install:warn_failed_remove(178): Cannot remove, permission denied: /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/psana-conda-1.0.0-py27_1/bin
WARNING conda.install:warn_failed_remove(178): Cannot remove, permission denied: /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/psana-conda-1.0.0-py27_1
Pruning fetched packages from the cache ...
An unexpected error has occurred.
Please consider posting the following information to the
conda GitHub issue tracker at:

    https://github.com/conda/conda/issues



Current conda install:

               platform : linux-64
          conda version : 4.2.3
       conda is private : False
      conda-env version : 2.6.0
    conda-build version : 1.21.11+0.g5b44ab3.dirty
         python version : 2.7.12.final.0
       requests version : 2.10.0
       root environment : /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7  (read only)
    default environment : /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs/anarel-1.0.0
       envs directories : /reg/neh/home/davidsch/.conda/envs
                          /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs
          package cache : /reg/neh/home/davidsch/.conda/envs/.pkgs
                          /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs
           channel URLs : file:///reg/g/psdm/sw/conda/channels/system-rhel7
                          file:///reg/g/psdm/sw/conda/channels/external-rhel7
                          defaults
                          file:///reg/g/psdm/sw/conda/channels/psana-rhel7
                          scikit-beam
                          file:///reg/g/psdm/sw/conda/channels/testing-rhel7
            config file : /reg/neh/home/davidsch/.condarc
           offline mode : False



`$ /reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/envs/anarel-1.0.0/bin/conda create --offline -n myrel --clone anarel-1.0.0`




    Traceback (most recent call last):
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/exceptions.py", line 442, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/main.py", line 144, in _main
        exit_code = args.func(args, p)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/main_create.py", line 66, in execute
        install(args, parser, 'create')
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/install.py", line 225, in install
        clone(args.clone, prefix, json=args.json, quiet=args.quiet, index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/cli/install.py", line 90, in clone
        index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/misc.py", line 388, in clone_env
        force_extract=False, index_args=index_args)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/misc.py", line 188, in explicit
        execute_actions(actions, index=index, verbose=verbose)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/plan.py", line 639, in execute_actions
        inst.execute_instructions(plan, index, verbose)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/instructions.py", line 132, in execute_instructions
        cmd(state, arg)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/instructions.py", line 66, in RM_FETCHED_CMD
        rm_fetched(arg)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/install.py", line 801, in rm_fetched
        with FileLock(fname):
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/lock.py", line 86, in __enter__
        touch(self.lock_file_path)
      File "/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/lib/python2.7/site-packages/conda/lock.py", line 48, in touch
        with open(file_name, 'a'):
    IOError: [Errno 13] Permission denied: u'/reg/g/psdm/sw/conda/inst/miniconda2-dev-rhel7/pkgs/openmpi-1.10.3-lsf_verbs_100.tar.bz2.pid17825.conda_lock'

```

@HugoTian As part of the 4.2 release, I think we need a lock cleanup step in the exception handler that just attempts to clean up any lock files for the current pid before it ultimately exits.  Do you agree?

@kalefranz , Moreover,  I think some how we need to bring back the try/except block when we create the lock file.

Something like : 

```
         try:
            touch(****)
        except OSError:
            pass
```


Resolving patch:
diff --git a/conda/lock.py b/conda/lock.py
--- a/conda/lock.py
+++ b/conda/lock.py
@@ -45,8 +45,11 @@ def touch(file_name, times=None):
     Examples:
         touch("hello_world.py")
     """
-    with open(file_name, 'a'):
-        os.utime(file_name, times)
+    try:
+        with open(file_name, 'a'):
+            os.utime(file_name, times)
+    except (OSError, IOError) as e:
+        log.warn("Failed to create lock, do not run conda in parallel process\n")
 
 
 class FileLock(object):
@@ -111,11 +114,13 @@ def __init__(self, directory_path, retries=10):
         self.lock_file_path = "%s.pid{0}.%s" % (lock_path_pre, LOCK_EXTENSION)
         # e.g. if locking directory `/conda`, lock file will be `/conda/conda.pidXXXX.conda_lock`
         self.lock_file_glob_str = "%s.pid*.%s" % (lock_path_pre, LOCK_EXTENSION)
+        # make sure '/' exists
         assert isdir(dirname(self.directory_path)), "{0} doesn't exist".format(self.directory_path)
         if not isdir(self.directory_path):
-            os.makedirs(self.directory_path, exist_ok=True)
-            log.debug("forced to create %s", self.directory_path)
-        assert os.access(self.directory_path, os.W_OK), "%s not writable" % self.directory_path
-
+            try:
+                os.makedirs(self.directory_path)
+                log.debug("forced to create %s", self.directory_path)
+            except (OSError, IOError) as e:
+                log.warn("Failed to create directory %s" % self.directory_path)
 
 Locked = DirectoryLock


Test patch:
diff --git a/tests/test_lock.py b/tests/test_lock.py
--- a/tests/test_lock.py
+++ b/tests/test_lock.py
@@ -1,9 +1,12 @@
 import pytest
-from os.path import basename, join
-from conda.lock import FileLock, LOCKSTR, LOCK_EXTENSION, LockError
-from conda.install import on_win
+from os.path import basename, join, exists, isfile
+from conda.lock import FileLock, DirectoryLock, LockError
+
 
 def test_filelock_passes(tmpdir):
+    """
+        Normal test on file lock
+    """
     package_name = "conda_file1"
     tmpfile = join(tmpdir.strpath, package_name)
     with FileLock(tmpfile) as lock:
@@ -15,7 +18,10 @@ def test_filelock_passes(tmpdir):
 
 
 def test_filelock_locks(tmpdir):
-
+    """
+        Test on file lock, multiple lock on same file
+        Lock error should raised
+    """
     package_name = "conda_file_2"
     tmpfile = join(tmpdir.strpath, package_name)
     with FileLock(tmpfile) as lock1:
@@ -27,48 +33,42 @@ def test_filelock_locks(tmpdir):
                 assert False  # this should never happen
             assert lock2.path_to_lock == lock1.path_to_lock
 
-        if not on_win:
-            assert "LOCKERROR" in str(execinfo.value)
-            assert "conda is already doing something" in str(execinfo.value)
         assert tmpdir.join(path).exists() and tmpdir.join(path).isfile()
 
     # lock should clean up after itself
     assert not tmpdir.join(path).exists()
 
 
-def test_filelock_folderlocks(tmpdir):
-    import os
-    package_name = "conda_file_2"
+def test_folder_locks(tmpdir):
+    """
+        Test on Directory lock
+    """
+    package_name = "dir_1"
     tmpfile = join(tmpdir.strpath, package_name)
-    os.makedirs(tmpfile)
-    with FileLock(tmpfile) as lock1:
-        path = basename(lock1.lock_file_path)
-        assert tmpdir.join(path).exists() and tmpdir.join(path).isfile()
+    with DirectoryLock(tmpfile) as lock1:
+
+        assert exists(lock1.lock_file_path) and isfile(lock1.lock_file_path)
 
         with pytest.raises(LockError) as execinfo:
-            with FileLock(tmpfile, retries=1) as lock2:
+            with DirectoryLock(tmpfile, retries=1) as lock2:
                 assert False  # this should never happen
-            assert lock2.path_to_lock == lock1.path_to_lock
-
-        if not on_win:
-            assert "LOCKERROR" in str(execinfo.value)
-            assert "conda is already doing something" in str(execinfo.value)
-            assert lock1.path_to_lock in str(execinfo.value)
 
-        assert tmpdir.join(path).exists() and tmpdir.join(path).isfile()
+        assert exists(lock1.lock_file_path) and isfile(lock1.lock_file_path)
 
     # lock should clean up after itself
-    assert not tmpdir.join(path).exists()
-
-
-def lock_thread(tmpdir, file_path):
-    with FileLock(file_path) as lock1:
-        path = basename(lock1.lock_file_path)
-        assert tmpdir.join(path).exists() and tmpdir.join(path).isfile()
-    assert not tmpdir.join(path).exists()
+    assert not exists(lock1.lock_file_path)
 
 
 def test_lock_thread(tmpdir):
+    """
+        2 thread want to lock a file
+        One thread will have LockError Raised
+    """
+    def lock_thread(tmpdir, file_path):
+        with FileLock(file_path) as lock1:
+            path = basename(lock1.lock_file_path)
+            assert tmpdir.join(path).exists() and tmpdir.join(path).isfile()
+        assert not tmpdir.join(path).exists()
 
     from threading import Thread
     package_name = "conda_file_3"
@@ -85,13 +85,17 @@ def test_lock_thread(tmpdir):
     assert not tmpdir.join(path).exists()
 
 
-def lock_thread_retries(tmpdir, file_path):
-    with pytest.raises(LockError) as execinfo:
-        with FileLock(file_path, retries=0):
-            assert False  # should never enter here, since max_tires is 0
-        assert  "LOCKERROR" in str(execinfo.value)
-
 def test_lock_retries(tmpdir):
+    """
+        2 thread want to lock a same file
+        Lock has zero retries
+        One thread will have LockError raised
+    """
+    def lock_thread_retries(tmpdir, file_path):
+        with pytest.raises(LockError) as execinfo:
+            with FileLock(file_path, retries=0):
+                assert False  # should never enter here, since max_tires is 0
+            assert "LOCKERROR" in str(execinfo.value)
 
     from threading import Thread
     package_name = "conda_file_3"
@@ -106,3 +110,19 @@ def test_lock_retries(tmpdir):
     t.join()
     # lock should clean up after itself
     assert not tmpdir.join(path).exists()
+
+
+def test_permission_file():
+    """
+        Test when lock cannot be created due to permission
+        Make sure no exception raised
+    """
+    import tempfile
+    from conda.compat import text_type
+    with tempfile.NamedTemporaryFile(mode='r') as f:
+        if not isinstance(f.name, text_type):
+            return
+        with FileLock(f.name) as lock:
+
+            path = basename(lock.lock_file_path)
+            assert not exists(join(f.name, path))