From 6315eb5086a96e4ba614ba01c9bbfaec8bd8504b Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Mon, 27 Feb 2012 21:01:49 +0000 Subject: [PATCH] Adds temporary chown to sparse_copy. `sparse_copy` needs read and write access to the devices. Since we cannot shell out to a run-as-root command here, we temporarily take ownership of the device. Change-Id: I891c38dbcba7177286dca729684c88ac065bd085 --- nova/utils.py | 20 ++++++++++++++++++ nova/virt/xenapi/vm_utils.py | 39 ++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 0f3e61897707..6bb0dd0f269a 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 e000e4ab109d..3c5264f9750a 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 + # 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 + if left <= 0: + break - data = src.read(min(block_size, left)) + data = src.read(min(block_size, left)) duration = time.time() - start_time compression_pct = float(skipped_bytes) / bytes_read * 100