Repository: avocado-framework/avocado

Issue:
assets download raises FileExistsError when running in parallel
When running vmimage.get() multiple times in parallell, directory creation raises exception because any thread could have created the directory before:

```
15:10:37 INFO | INIT 1-TransientDomain.test_lifecycle
15:10:37 DEBUG| PARAMS (key=timeout, path=*, default=None) => None
15:10:37 DEBUG| Test metadata:
15:10:37 DEBUG|   filename: /home/local/src/beraldo/libvirt/tests/beraldo/tests/domain/test_transient.py
15:10:37 DEBUG|   teststmpdir: /var/tmp/avocado_38pvnn1o
15:10:37 DEBUG|   workdir: /var/tmp/tmpnaw2reze/test-results/tmp_dirq6834flz/1-TransientDomain.test_lifecycle
15:10:37 INFO | START 1-TransientDomain.test_lifecycle
15:10:37 DEBUG| DATA (filename=output.expected) => NOT FOUND (data sources: variant, test, file)
15:10:38 INFO | Asset not in cache, fetching it.
15:10:38 ERROR| 
15:10:38 ERROR| Reproduced traceback from: /home/local/src/beraldo/avocado/avocado/core/test.py:770
15:10:38 ERROR| Traceback (most recent call last):
15:10:38 ERROR|   File "/home/local/src/beraldo/libvirt/tests/beraldo/tests/domain/test_transient.py", line 27, in test_lifecycle
15:10:38 ERROR|     domain = self.create_domain(arguments={'image': self.image.path},
15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 447, in path
15:10:38 ERROR|     return self._path or self.get()
15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 482, in get
15:10:38 ERROR|     self.download()
15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 473, in download
15:10:38 ERROR|     metadata=metadata).fetch()
15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/asset.py", line 370, in fetch
15:10:38 ERROR|     os.makedirs(dirname)
15:10:38 ERROR|   File "/usr/lib64/python3.7/os.py", line 223, in makedirs
15:10:38 ERROR|     mkdir(name, mode)
15:10:38 ERROR| FileExistsError: [Errno 17] File exists: '/tmp/libvirt-scratch/by_location/67e23165d25d7f9934a909a12bc14277c9fb0b0d'
15:10:38 ERROR| 
15:10:38 DEBUG| Local variables:
15:10:38 DEBUG|  -> self <class 'test_transient.TransientDomain'>: 1-TransientDomain.test_lifecycle
15:10:38 ERROR| Traceback (most recent call last):

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/core/test.py", line 858, in _run_avocado
    raise test_exception

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/core/test.py", line 765, in _run_avocado
    testMethod()

15:10:38 ERROR|   File "/home/local/src/beraldo/libvirt/tests/beraldo/tests/domain/test_transient.py", line 27, in test_lifecycle
    domain = self.create_domain(arguments={'image': self.image.path},

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 447, in path
    return self._path or self.get()

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 482, in get
    self.download()

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/vmimage.py", line 473, in download
    metadata=metadata).fetch()

15:10:38 ERROR|   File "/home/local/src/beraldo/avocado/avocado/utils/asset.py", line 370, in fetch
    os.makedirs(dirname)

15:10:38 ERROR|   File "/usr/lib64/python3.7/os.py", line 223, in makedirs
    mkdir(name, mode)

15:10:38 ERROR| FileExistsError: [Errno 17] File exists: '/tmp/libvirt-scratch/by_location/67e23165d25d7f9934a909a12bc14277c9fb0b0d'

15:10:38 ERROR| ERROR 1-TransientDomain.test_lifecycle -> FileExistsError: [Errno 17] File exists: '/tmp/libvirt-scratch/by_location/67e23165d25d7f9934a909a12bc14277c9fb0b0d'

```

I have found the issue already, sending PR in a few minutes.


Discussion:

Resolving patch:
diff --git a/avocado/utils/asset.py b/avocado/utils/asset.py
--- a/avocado/utils/asset.py
+++ b/avocado/utils/asset.py
@@ -367,7 +367,7 @@ def fetch(self):
                                       self.relative_dir)
             dirname = os.path.dirname(asset_file)
             if not os.path.isdir(dirname):
-                os.makedirs(dirname)
+                os.makedirs(dirname, exist_ok=True)
             try:
                 if fetch(urlobj, asset_file):
                     if self.metadata is not None:


Test patch: