privsep: Add support for recursive chown, move_tree operations
We'll need these shortly to handle shuffling of vTPM files during cold migrations and resizes. Part of blueprint add-emulated-virtual-tpm Change-Id: I7c8dedc9e74117838db5d418dda1dcbe7143ad08 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
nova/compute/manager.py
|
||||
nova/crypto.py
|
||||
nova/privsep/path.py
|
||||
nova/virt/driver.py
|
||||
nova/virt/hardware.py
|
||||
nova/virt/libvirt/__init__.py
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import errno
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from oslo_utils import fileutils
|
||||
|
||||
@@ -48,11 +49,22 @@ def readlink(path):
|
||||
|
||||
|
||||
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||
def chown(path, uid=-1, gid=-1):
|
||||
def chown(
|
||||
path: str, uid: int = -1, gid: int = -1, recursive: bool = False,
|
||||
) -> None:
|
||||
if not os.path.exists(path):
|
||||
raise exception.FileNotFound(file_path=path)
|
||||
|
||||
if not recursive or os.path.isfile(path):
|
||||
return os.chown(path, uid, gid)
|
||||
|
||||
for root, dirs, files in os.walk(path):
|
||||
os.chown(root, uid, gid)
|
||||
for item in dirs:
|
||||
os.chown(os.path.join(root, item), uid, gid)
|
||||
for item in files:
|
||||
os.chown(os.path.join(root, item), uid, gid)
|
||||
|
||||
|
||||
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||
def makedirs(path):
|
||||
@@ -66,6 +78,11 @@ def chmod(path, mode):
|
||||
os.chmod(path, mode)
|
||||
|
||||
|
||||
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||
def move_tree(source_path: str, dest_path: str) -> None:
|
||||
shutil.move(source_path, dest_path)
|
||||
|
||||
|
||||
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||
def utime(path):
|
||||
if not os.path.exists(path):
|
||||
|
||||
@@ -83,7 +83,7 @@ class FileTestCase(test.NoDBTestCase):
|
||||
def test_chown(self, mock_chown, mock_exists):
|
||||
nova.privsep.path.chown('/fake/path', uid=42, gid=43)
|
||||
mock_exists.assert_called_with('/fake/path')
|
||||
mock_chown.assert_called_with('/fake/path', 42, 43)
|
||||
mock_chown.assert_called_once_with('/fake/path', 42, 43)
|
||||
|
||||
@mock.patch('os.path.exists', return_value=False)
|
||||
def test_chown_file_not_found(self, mock_exists):
|
||||
@@ -91,6 +91,36 @@ class FileTestCase(test.NoDBTestCase):
|
||||
nova.privsep.path.chown,
|
||||
'/fake/path')
|
||||
|
||||
@mock.patch('os.walk', return_value=[('.', ['foo'], ['bar.py'])])
|
||||
@mock.patch('os.path.isfile', return_value=False)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('os.chown')
|
||||
def test_chown_recursive(
|
||||
self, mock_chown, mock_exists, mock_isfile, mock_walk,
|
||||
):
|
||||
nova.privsep.path.chown('/fake/path', uid=42, gid=43, recursive=True)
|
||||
mock_exists.assert_called_with('/fake/path')
|
||||
mock_isfile.assert_called_once_with('/fake/path')
|
||||
mock_walk.assert_called_once_with('/fake/path')
|
||||
mock_chown.assert_has_calls([
|
||||
mock.call('.', 42, 43),
|
||||
mock.call('./foo', 42, 43),
|
||||
mock.call('./bar.py', 42, 43),
|
||||
])
|
||||
|
||||
@mock.patch('os.walk')
|
||||
@mock.patch('os.path.isfile', return_value=True)
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('os.chown')
|
||||
def test_chown_recursive_is_file(
|
||||
self, mock_chown, mock_exists, mock_isfile, mock_walk,
|
||||
):
|
||||
nova.privsep.path.chown('/fake/path', uid=42, gid=43, recursive=True)
|
||||
mock_exists.assert_called_with('/fake/path')
|
||||
mock_isfile.assert_called_once_with('/fake/path')
|
||||
mock_chown.assert_called_once_with('/fake/path', 42, 43)
|
||||
mock_walk.assert_not_called()
|
||||
|
||||
@mock.patch('oslo_utils.fileutils.ensure_tree')
|
||||
def test_makedirs(self, mock_ensure_tree):
|
||||
nova.privsep.path.makedirs('/fake/path')
|
||||
|
||||
Reference in New Issue
Block a user