summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/utils.py20
-rw-r--r--nova/virt/xenapi/vm_utils.py43
2 files changed, 44 insertions, 19 deletions
diff --git a/nova/utils.py b/nova/utils.py
index 0f3e61897..6bb0dd0f2 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -1523,3 +1523,23 @@ def read_file_as_root(file_path):
return out
except exception.ProcessExecutionError:
raise exception.FileNotFound(file_path=file_path)
+
+
+@contextlib.contextmanager
+def temporary_chown(path, owner_uid=None):
+ """Temporarily chown a path.
+
+ :params owner_uid: UID of temporary owner (defaults to current user)
+ """
+ if owner_uid is None:
+ owner_uid = os.getuid()
+
+ orig_uid = os.stat(path).st_uid
+
+ if orig_uid != owner_uid:
+ execute('chown', owner_uid, path, run_as_root=True)
+ try:
+ yield
+ finally:
+ if orig_uid != owner_uid:
+ execute('chown', orig_uid, path, run_as_root=True)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index e000e4ab1..3c5264f97 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -1651,25 +1651,30 @@ def _sparse_copy(src_path, dst_path, virtual_size, block_size=4096):
"virtual_size=%(virtual_size)d block_size=%(block_size)d"),
locals())
- with open(src_path, "r") as src:
- with open(dst_path, "w") as dst:
- data = src.read(min(block_size, left))
- while data:
- if data == EMPTY_BLOCK:
- dst.seek(block_size, os.SEEK_CUR)
- left -= block_size
- bytes_read += block_size
- skipped_bytes += block_size
- else:
- dst.write(data)
- data_len = len(data)
- left -= data_len
- bytes_read += data_len
-
- if left <= 0:
- break
-
- data = src.read(min(block_size, left))
+ # NOTE(sirp): we need read/write access to the devices; since we don't have
+ # the luxury of shelling out to a sudo'd command, we temporarily take
+ # ownership of the devices.
+ with utils.temporary_chown(src_path):
+ with utils.temporary_chown(dst_path):
+ with open(src_path, "r") as src:
+ with open(dst_path, "w") as dst:
+ data = src.read(min(block_size, left))
+ while data:
+ if data == EMPTY_BLOCK:
+ dst.seek(block_size, os.SEEK_CUR)
+ left -= block_size
+ bytes_read += block_size
+ skipped_bytes += block_size
+ else:
+ dst.write(data)
+ data_len = len(data)
+ left -= data_len
+ bytes_read += data_len
+
+ if left <= 0:
+ break
+
+ data = src.read(min(block_size, left))
duration = time.time() - start_time
compression_pct = float(skipped_bytes) / bytes_read * 100