Merge "virt: convert VFS API to use nova.virt.image.model"
This commit is contained in:
commit
879f060e7a
|
@ -196,7 +196,8 @@ def _get_virt_name(regex, data):
|
|||
driver = m.group(1)
|
||||
# Ignore things we mis-detect as virt drivers in the regex
|
||||
if driver in ["test_virt_drivers", "driver", "firewall",
|
||||
"disk", "api", "imagecache", "cpu", "hardware"]:
|
||||
"disk", "api", "imagecache", "cpu", "hardware",
|
||||
"image"]:
|
||||
return None
|
||||
return driver
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ from nova import test
|
|||
from nova.tests.unit.virt.disk.vfs import fakeguestfs
|
||||
from nova.virt.disk import api as diskapi
|
||||
from nova.virt.disk.vfs import guestfs as vfsguestfs
|
||||
from nova.virt.image import model as imgmodel
|
||||
|
||||
|
||||
class VirtDiskTest(test.NoDBTestCase):
|
||||
|
@ -30,6 +31,8 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
self.useFixture(
|
||||
fixtures.MonkeyPatch('nova.virt.disk.vfs.guestfs.guestfs',
|
||||
fakeguestfs))
|
||||
self.file = imgmodel.LocalFileImage("/some/file",
|
||||
imgmodel.FORMAT_QCOW2)
|
||||
|
||||
def test_inject_data(self):
|
||||
self.assertTrue(diskapi.inject_data("/some/file", use_cow=True))
|
||||
|
@ -54,7 +57,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
|
||||
def test_inject_data_key(self):
|
||||
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
diskapi._inject_key_into_fs("mysshkey", vfs)
|
||||
|
@ -75,7 +78,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
|
||||
def test_inject_data_key_with_selinux(self):
|
||||
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
vfs.make_path("etc/selinux")
|
||||
|
@ -109,7 +112,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
|
||||
def test_inject_data_key_with_selinux_append_with_newline(self):
|
||||
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
vfs.replace_file("/etc/rc.d/rc.local", "#!/bin/sh\necho done")
|
||||
|
@ -131,7 +134,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
|
||||
def test_inject_net(self):
|
||||
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
diskapi._inject_net_into_fs("mynetconfig", vfs)
|
||||
|
@ -146,7 +149,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_inject_metadata(self):
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
metadata = {"foo": "bar", "eek": "wizz"}
|
||||
metadata = OrderedDict(sorted(metadata.items()))
|
||||
|
@ -163,7 +166,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_inject_admin_password(self):
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
def fake_salt():
|
||||
|
@ -219,7 +222,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_inject_files_into_fs(self):
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
diskapi._inject_files_into_fs([("/path/to/not/exists/file",
|
||||
|
@ -244,7 +247,7 @@ class VirtDiskTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_inject_files_into_fs_dir_exists(self):
|
||||
vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2")
|
||||
vfs = vfsguestfs.VFSGuestFS(self.file)
|
||||
vfs.setup()
|
||||
|
||||
called = {'make_path': False}
|
||||
|
|
|
@ -61,7 +61,7 @@ class GuestFS(object):
|
|||
if file == "/some/fail/file":
|
||||
raise RuntimeError("%s: No such file or directory", file)
|
||||
|
||||
self.drives.append((file, kwargs['format']))
|
||||
self.drives.append((file, kwargs))
|
||||
|
||||
def add_drive(self, file, format=None, *args, **kwargs):
|
||||
self.add_drive_opts(file, format=None, *args, **kwargs)
|
||||
|
|
|
@ -19,6 +19,7 @@ from nova import exception
|
|||
from nova import test
|
||||
from nova.tests.unit.virt.disk.vfs import fakeguestfs
|
||||
from nova.virt.disk.vfs import guestfs as vfsimpl
|
||||
from nova.virt.image import model as imgmodel
|
||||
|
||||
|
||||
class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
||||
|
@ -28,15 +29,25 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
fixtures.MonkeyPatch('nova.virt.disk.vfs.guestfs.guestfs',
|
||||
fakeguestfs))
|
||||
|
||||
def _do_test_appliance_setup_inspect(self, forcetcg):
|
||||
self.qcowfile = imgmodel.LocalFileImage("/dummy.qcow2",
|
||||
imgmodel.FORMAT_QCOW2)
|
||||
self.rawfile = imgmodel.LocalFileImage("/dummy.img",
|
||||
imgmodel.FORMAT_RAW)
|
||||
self.lvmfile = imgmodel.LocalBlockImage("/dev/volgroup/myvol")
|
||||
self.rbdfile = imgmodel.RBDImage("myvol", "mypool",
|
||||
"cthulu",
|
||||
"arrrrrgh",
|
||||
["server1:123", "server2:123"])
|
||||
|
||||
def _do_test_appliance_setup_inspect(self, image, drives, forcetcg):
|
||||
if forcetcg:
|
||||
vfsimpl.force_tcg()
|
||||
else:
|
||||
vfsimpl.force_tcg(False)
|
||||
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2",
|
||||
imgfmt="qcow2",
|
||||
partition=-1)
|
||||
vfs = vfsimpl.VFSGuestFS(
|
||||
image,
|
||||
partition=-1)
|
||||
vfs.setup()
|
||||
|
||||
if forcetcg:
|
||||
|
@ -46,6 +57,8 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertIsNone(vfs.handle.backend_settings)
|
||||
|
||||
self.assertTrue(vfs.handle.running)
|
||||
self.assertEqual(drives,
|
||||
vfs.handle.drives)
|
||||
self.assertEqual(3, len(vfs.handle.mounts))
|
||||
self.assertEqual("/dev/mapper/guestvgf-lv_root",
|
||||
vfs.handle.mounts[0][1])
|
||||
|
@ -66,14 +79,32 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertEqual(0, len(handle.mounts))
|
||||
|
||||
def test_appliance_setup_inspect_auto(self):
|
||||
self._do_test_appliance_setup_inspect(False)
|
||||
drives = [("/dummy.qcow2", {"format": "qcow2"})]
|
||||
self._do_test_appliance_setup_inspect(self.qcowfile, drives, False)
|
||||
|
||||
def test_appliance_setup_inspect_tcg(self):
|
||||
self._do_test_appliance_setup_inspect(True)
|
||||
drives = [("/dummy.qcow2", {"format": "qcow2"})]
|
||||
self._do_test_appliance_setup_inspect(self.qcowfile, drives, True)
|
||||
|
||||
def test_appliance_setup_inspect_raw(self):
|
||||
drives = [("/dummy.img", {"format": "raw"})]
|
||||
self._do_test_appliance_setup_inspect(self.rawfile, drives, True)
|
||||
|
||||
def test_appliance_setup_inspect_lvm(self):
|
||||
drives = [("/dev/volgroup/myvol", {"format": "raw"})]
|
||||
self._do_test_appliance_setup_inspect(self.lvmfile, drives, True)
|
||||
|
||||
def test_appliance_setup_inspect_rbd(self):
|
||||
drives = [("mypool/myvol", {"format": "raw",
|
||||
"protocol": "rbd",
|
||||
"username": "cthulu",
|
||||
"secret": "arrrrrgh",
|
||||
"server": ["server1:123",
|
||||
"server2:123"]})]
|
||||
self._do_test_appliance_setup_inspect(self.rbdfile, drives, True)
|
||||
|
||||
def test_appliance_setup_inspect_no_root_raises(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2",
|
||||
imgfmt="qcow2",
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile,
|
||||
partition=-1)
|
||||
# call setup to init the handle so we can stub it
|
||||
vfs.setup()
|
||||
|
@ -87,8 +118,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertRaises(exception.NovaException, vfs.setup_os_inspect)
|
||||
|
||||
def test_appliance_setup_inspect_multi_boots_raises(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2",
|
||||
imgfmt="qcow2",
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile,
|
||||
partition=-1)
|
||||
# call setup to init the handle so we can stub it
|
||||
vfs.setup()
|
||||
|
@ -102,8 +132,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertRaises(exception.NovaException, vfs.setup_os_inspect)
|
||||
|
||||
def test_appliance_setup_static_nopart(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2",
|
||||
imgfmt="qcow2",
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile,
|
||||
partition=None)
|
||||
vfs.setup()
|
||||
|
||||
|
@ -122,8 +151,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertEqual(0, len(handle.mounts))
|
||||
|
||||
def test_appliance_setup_static_part(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2",
|
||||
imgfmt="qcow2",
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile,
|
||||
partition=2)
|
||||
vfs.setup()
|
||||
|
||||
|
@ -142,7 +170,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
self.assertEqual(0, len(handle.mounts))
|
||||
|
||||
def test_makepath(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.make_path("/some/dir")
|
||||
vfs.make_path("/other/dir")
|
||||
|
@ -155,7 +183,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_append_file(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.append_file("/some/file", " Goodbye")
|
||||
|
||||
|
@ -166,7 +194,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_replace_file(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.replace_file("/some/file", "Goodbye")
|
||||
|
||||
|
@ -177,14 +205,14 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_read_file(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertEqual("Hello World", vfs.read_file("/some/file"))
|
||||
|
||||
vfs.teardown()
|
||||
|
||||
def test_has_file(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -194,7 +222,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_set_permissions(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -206,7 +234,7 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_set_ownership(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -228,29 +256,29 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
vfs.teardown()
|
||||
|
||||
def test_close_on_error(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertFalse(vfs.handle.kwargs['close_on_exit'])
|
||||
vfs.teardown()
|
||||
self.stubs.Set(fakeguestfs.GuestFS, 'SUPPORT_CLOSE_ON_EXIT', False)
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertNotIn('close_on_exit', vfs.handle.kwargs)
|
||||
vfs.teardown()
|
||||
|
||||
def test_python_return_dict(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertFalse(vfs.handle.kwargs['python_return_dict'])
|
||||
vfs.teardown()
|
||||
self.stubs.Set(fakeguestfs.GuestFS, 'SUPPORT_RETURN_DICT', False)
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertNotIn('python_return_dict', vfs.handle.kwargs)
|
||||
vfs.teardown()
|
||||
|
||||
def test_setup_debug_disable(self):
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertFalse(vfs.handle.trace_enabled)
|
||||
self.assertFalse(vfs.handle.verbose_enabled)
|
||||
|
@ -258,14 +286,14 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
|
||||
def test_setup_debug_enabled(self):
|
||||
self.flags(debug=True, group='guestfs')
|
||||
vfs = vfsimpl.VFSGuestFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertTrue(vfs.handle.trace_enabled)
|
||||
self.assertTrue(vfs.handle.verbose_enabled)
|
||||
self.assertIsNotNone(vfs.handle.event_callback)
|
||||
|
||||
def test_get_format_fs(self):
|
||||
vfs = vfsimpl.VFSGuestFS("dummy.img")
|
||||
vfs = vfsimpl.VFSGuestFS(self.rawfile)
|
||||
vfs.setup()
|
||||
self.assertIsNotNone(vfs.handle)
|
||||
self.assertTrue('ext3', vfs.get_image_fs())
|
||||
|
@ -273,12 +301,12 @@ class VirtDiskVFSGuestFSTest(test.NoDBTestCase):
|
|||
|
||||
@mock.patch.object(vfsimpl.VFSGuestFS, 'setup_os')
|
||||
def test_setup_mount(self, setup_os):
|
||||
vfs = vfsimpl.VFSGuestFS("img.qcow2", imgfmt='qcow2')
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup()
|
||||
self.assertTrue(setup_os.called)
|
||||
|
||||
@mock.patch.object(vfsimpl.VFSGuestFS, 'setup_os')
|
||||
def test_setup_mount_false(self, setup_os):
|
||||
vfs = vfsimpl.VFSGuestFS("img.qcow2", imgfmt='qcow2')
|
||||
vfs = vfsimpl.VFSGuestFS(self.qcowfile)
|
||||
vfs.setup(mount=False)
|
||||
self.assertFalse(setup_os.called)
|
||||
|
|
|
@ -22,6 +22,7 @@ from nova import exception
|
|||
from nova import test
|
||||
from nova.tests.unit import utils as tests_utils
|
||||
import nova.utils
|
||||
from nova.virt.disk.mount import nbd
|
||||
from nova.virt.disk.vfs import localfs as vfsimpl
|
||||
from nova.virt.image import model as imgmodel
|
||||
|
||||
|
@ -134,11 +135,13 @@ class VirtDiskVFSLocalFSTestPaths(test.NoDBTestCase):
|
|||
return real_execute(*cmd_parts, **kwargs)
|
||||
|
||||
self.stubs.Set(processutils, 'execute', nonroot_execute)
|
||||
self.rawfile = imgmodel.LocalFileImage("/dummy.img",
|
||||
imgmodel.FORMAT_RAW)
|
||||
|
||||
def test_check_safe_path(self):
|
||||
if not tests_utils.coreutils_readlink_available():
|
||||
self.skipTest("coreutils readlink(1) unavailable")
|
||||
vfs = vfsimpl.VFSLocalFS("dummy.img")
|
||||
vfs = vfsimpl.VFSLocalFS(self.rawfile)
|
||||
vfs.imgdir = "/foo"
|
||||
ret = vfs._canonical_path('etc/something.conf')
|
||||
self.assertEqual(ret, '/foo/etc/something.conf')
|
||||
|
@ -146,7 +149,7 @@ class VirtDiskVFSLocalFSTestPaths(test.NoDBTestCase):
|
|||
def test_check_unsafe_path(self):
|
||||
if not tests_utils.coreutils_readlink_available():
|
||||
self.skipTest("coreutils readlink(1) unavailable")
|
||||
vfs = vfsimpl.VFSLocalFS("dummy.img")
|
||||
vfs = vfsimpl.VFSLocalFS(self.rawfile)
|
||||
vfs.imgdir = "/foo"
|
||||
self.assertRaises(exception.Invalid,
|
||||
vfs._canonical_path,
|
||||
|
@ -154,13 +157,21 @@ class VirtDiskVFSLocalFSTestPaths(test.NoDBTestCase):
|
|||
|
||||
|
||||
class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(VirtDiskVFSLocalFSTest, self).setUp()
|
||||
|
||||
self.qcowfile = imgmodel.LocalFileImage("/dummy.qcow2",
|
||||
imgmodel.FORMAT_QCOW2)
|
||||
self.rawfile = imgmodel.LocalFileImage("/dummy.img",
|
||||
imgmodel.FORMAT_RAW)
|
||||
|
||||
def test_makepath(self):
|
||||
global dirs, commands
|
||||
dirs = []
|
||||
commands = []
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.make_path("/some/dir")
|
||||
vfs.make_path("/other/dir")
|
||||
|
@ -193,7 +204,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
commands = []
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.append_file("/some/file", " Goodbye")
|
||||
|
||||
|
@ -219,7 +230,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
commands = []
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.replace_file("/some/file", "Goodbye")
|
||||
|
||||
|
@ -244,7 +255,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
commands = []
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
self.assertEqual(vfs.read_file("/some/file"), "Hello World")
|
||||
|
||||
|
@ -264,7 +275,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
commands = []
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -304,7 +315,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
files = {}
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -335,7 +346,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
files = {}
|
||||
self.stubs.Set(processutils, 'execute', fake_execute)
|
||||
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile="/dummy.qcow2", imgfmt="qcow2")
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
vfs.imgdir = "/scratch/dir"
|
||||
vfs.read_file("/some/file")
|
||||
|
||||
|
@ -390,7 +401,7 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
|
||||
@mock.patch.object(nova.utils, 'execute')
|
||||
def test_get_format_fs(self, execute):
|
||||
vfs = vfsimpl.VFSLocalFS("dummy.img")
|
||||
vfs = vfsimpl.VFSLocalFS(self.rawfile)
|
||||
vfs.setup = mock.MagicMock()
|
||||
vfs.teardown = mock.MagicMock()
|
||||
|
||||
|
@ -421,9 +432,9 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
check_exit_code=[0, 2])
|
||||
|
||||
@mock.patch.object(tempfile, 'mkdtemp')
|
||||
@mock.patch.object(nova.virt.disk.mount.nbd, 'NbdMount')
|
||||
@mock.patch.object(nbd, 'NbdMount')
|
||||
def test_setup_mount(self, NbdMount, mkdtemp):
|
||||
vfs = vfsimpl.VFSLocalFS("img.qcow2", imgfmt='qcow2')
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
|
||||
mounter = mock.MagicMock()
|
||||
mkdtemp.return_value = 'tmp/'
|
||||
|
@ -432,16 +443,13 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
vfs.setup()
|
||||
|
||||
self.assertTrue(mkdtemp.called)
|
||||
NbdMount.assert_called_once_with(
|
||||
imgmodel.LocalFileImage('img.qcow2',
|
||||
imgmodel.FORMAT_QCOW2),
|
||||
'tmp/', None)
|
||||
NbdMount.assert_called_once_with(self.qcowfile, "tmp/", None)
|
||||
mounter.do_mount.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(tempfile, 'mkdtemp')
|
||||
@mock.patch.object(nova.virt.disk.mount.nbd, 'NbdMount')
|
||||
@mock.patch.object(nbd, 'NbdMount')
|
||||
def test_setup_mount_false(self, NbdMount, mkdtemp):
|
||||
vfs = vfsimpl.VFSLocalFS("img.qcow2", imgfmt='qcow2')
|
||||
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
|
||||
|
||||
mounter = mock.MagicMock()
|
||||
mkdtemp.return_value = 'tmp/'
|
||||
|
@ -450,8 +458,5 @@ class VirtDiskVFSLocalFSTest(test.NoDBTestCase):
|
|||
vfs.setup(mount=False)
|
||||
|
||||
self.assertTrue(mkdtemp.called)
|
||||
NbdMount.assert_called_once_with(
|
||||
imgmodel.LocalFileImage('img.qcow2',
|
||||
imgmodel.FORMAT_QCOW2),
|
||||
'tmp/', None)
|
||||
NbdMount.assert_called_once_with(self.qcowfile, "tmp/", None)
|
||||
self.assertFalse(mounter.do_mount.called)
|
||||
|
|
|
@ -240,7 +240,9 @@ def is_image_extendable(image, use_cow=False):
|
|||
if use_cow:
|
||||
fs = None
|
||||
try:
|
||||
fs = vfs.VFS.instance_for_image(image, 'qcow2', None)
|
||||
fs = vfs.VFS.instance_for_image(
|
||||
imgmodel.LocalFileImage(image, imgmodel.FORMAT_QCOW2),
|
||||
None)
|
||||
fs.setup(mount=False)
|
||||
if fs.get_image_fs() in SUPPORTED_FS_TO_EXTEND:
|
||||
return True
|
||||
|
@ -384,6 +386,16 @@ def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
|
|||
files=None, partition=None, use_cow=False, mandatory=()):
|
||||
"""Inject the specified items into a disk image.
|
||||
|
||||
:param image: the local file path
|
||||
:param key: the SSH public key to inject
|
||||
:param net: the network configuration to inject
|
||||
:param metadata: the user metadata to inject
|
||||
:param admin_password: the root password to set
|
||||
:param files: the files to copy into the image
|
||||
:param partition: the partition number to access
|
||||
:param use_cow: whether the image is in qcow2 format
|
||||
:param mandatory: the list of parameters which must not fail to inject
|
||||
|
||||
If an item name is not specified in the MANDATORY iterable, then a warning
|
||||
is logged on failure to inject that item, rather than raising an exception.
|
||||
|
||||
|
@ -400,11 +412,12 @@ def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
|
|||
"files=%(files)s partition=%(partition)s use_cow=%(use_cow)s",
|
||||
{'image': image, 'key': key, 'net': net, 'metadata': metadata,
|
||||
'files': files, 'partition': partition, 'use_cow': use_cow})
|
||||
fmt = "raw"
|
||||
fmt = imgmodel.FORMAT_RAW
|
||||
if use_cow:
|
||||
fmt = "qcow2"
|
||||
fmt = imgmodel.FORMAT_QCOW2
|
||||
try:
|
||||
fs = vfs.VFS.instance_for_image(image, fmt, partition)
|
||||
fs = vfs.VFS.instance_for_image(
|
||||
imgmodel.LocalFileImage(image, fmt), partition)
|
||||
fs.setup()
|
||||
except Exception as e:
|
||||
# If a mandatory item is passed to this function,
|
||||
|
|
|
@ -39,18 +39,23 @@ class VFS(object):
|
|||
guestfs_ready = False
|
||||
|
||||
@staticmethod
|
||||
def instance_for_image(imgfile, imgfmt, partition):
|
||||
LOG.debug("Instance for image imgfile=%(imgfile)s "
|
||||
"imgfmt=%(imgfmt)s partition=%(partition)s",
|
||||
{'imgfile': imgfile, 'imgfmt': imgfmt,
|
||||
'partition': partition})
|
||||
def instance_for_image(image, partition):
|
||||
"""Get a VFS instance for the image
|
||||
|
||||
:param image: instance of nova.virt.image.model.Image
|
||||
:param partition: the partition number to access
|
||||
"""
|
||||
|
||||
LOG.debug("Instance for image image=%(image)s "
|
||||
"partition=%(partition)s",
|
||||
{'image': image, 'partition': partition})
|
||||
|
||||
vfs = None
|
||||
try:
|
||||
LOG.debug("Using primary VFSGuestFS")
|
||||
vfs = importutils.import_object(
|
||||
"nova.virt.disk.vfs.guestfs.VFSGuestFS",
|
||||
imgfile, imgfmt, partition)
|
||||
image, partition)
|
||||
if not VFS.guestfs_ready:
|
||||
# Inspect for capabilities and keep
|
||||
# track of the result only if succeeded.
|
||||
|
@ -69,11 +74,16 @@ class VFS(object):
|
|||
|
||||
return importutils.import_object(
|
||||
"nova.virt.disk.vfs.localfs.VFSLocalFS",
|
||||
imgfile, imgfmt, partition)
|
||||
image, partition)
|
||||
|
||||
def __init__(self, imgfile, imgfmt, partition):
|
||||
self.imgfile = imgfile
|
||||
self.imgfmt = imgfmt
|
||||
def __init__(self, image, partition):
|
||||
"""Create a new local VFS instance
|
||||
|
||||
:param image: instance of nova.virt.image.model.Image
|
||||
:param partition: the partition number to access
|
||||
"""
|
||||
|
||||
self.image = image
|
||||
self.partition = partition
|
||||
|
||||
def setup(self, mount=True):
|
||||
|
|
|
@ -22,6 +22,7 @@ from nova import exception
|
|||
from nova.i18n import _
|
||||
from nova.i18n import _LW
|
||||
from nova.virt.disk.vfs import api as vfs
|
||||
from nova.virt.image import model as imgmodel
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -57,8 +58,14 @@ class VFSGuestFS(vfs.VFS):
|
|||
the host filesystem, thus avoiding any potential for symlink
|
||||
attacks from the guest filesystem.
|
||||
"""
|
||||
def __init__(self, imgfile, imgfmt='raw', partition=None):
|
||||
super(VFSGuestFS, self).__init__(imgfile, imgfmt, partition)
|
||||
def __init__(self, image, partition=None):
|
||||
"""Create a new local VFS instance
|
||||
|
||||
:param image: instance of nova.virt.image.model.Image
|
||||
:param partition: the partition number of access
|
||||
"""
|
||||
|
||||
super(VFSGuestFS, self).__init__(image, partition)
|
||||
|
||||
global guestfs
|
||||
if guestfs is None:
|
||||
|
@ -111,8 +118,8 @@ class VFSGuestFS(vfs.VFS):
|
|||
self.setup_os_static()
|
||||
|
||||
def setup_os_static(self):
|
||||
LOG.debug("Mount guest OS image %(imgfile)s partition %(part)s",
|
||||
{'imgfile': self.imgfile, 'part': str(self.partition)})
|
||||
LOG.debug("Mount guest OS image %(image)s partition %(part)s",
|
||||
{'image': self.image, 'part': str(self.partition)})
|
||||
|
||||
if self.partition:
|
||||
self.handle.mount_options("", "/dev/sda%d" % self.partition, "/")
|
||||
|
@ -120,18 +127,18 @@ class VFSGuestFS(vfs.VFS):
|
|||
self.handle.mount_options("", "/dev/sda", "/")
|
||||
|
||||
def setup_os_inspect(self):
|
||||
LOG.debug("Inspecting guest OS image %s", self.imgfile)
|
||||
LOG.debug("Inspecting guest OS image %s", self.image)
|
||||
roots = self.handle.inspect_os()
|
||||
|
||||
if len(roots) == 0:
|
||||
raise exception.NovaException(_("No operating system found in %s")
|
||||
% self.imgfile)
|
||||
% self.image)
|
||||
|
||||
if len(roots) != 1:
|
||||
LOG.debug("Multi-boot OS %(roots)s", {'roots': str(roots)})
|
||||
raise exception.NovaException(
|
||||
_("Multi-boot operating system found in %s") %
|
||||
self.imgfile)
|
||||
self.image)
|
||||
|
||||
self.setup_os_root(roots[0])
|
||||
|
||||
|
@ -141,8 +148,8 @@ class VFSGuestFS(vfs.VFS):
|
|||
|
||||
if len(mounts) == 0:
|
||||
raise exception.NovaException(
|
||||
_("No mount points found in %(root)s of %(imgfile)s") %
|
||||
{'root': root, 'imgfile': self.imgfile})
|
||||
_("No mount points found in %(root)s of %(image)s") %
|
||||
{'root': root, 'image': self.image})
|
||||
|
||||
# the root directory must be mounted first
|
||||
mounts.sort(key=lambda mount: mount[0])
|
||||
|
@ -156,8 +163,8 @@ class VFSGuestFS(vfs.VFS):
|
|||
root_mounted = True
|
||||
except RuntimeError as e:
|
||||
msg = _("Error mounting %(device)s to %(dir)s in image"
|
||||
" %(imgfile)s with libguestfs (%(e)s)") % \
|
||||
{'imgfile': self.imgfile, 'device': mount[1],
|
||||
" %(image)s with libguestfs (%(e)s)") % \
|
||||
{'image': self.image, 'device': mount[1],
|
||||
'dir': mount[0], 'e': e}
|
||||
if root_mounted:
|
||||
LOG.debug(msg)
|
||||
|
@ -165,8 +172,8 @@ class VFSGuestFS(vfs.VFS):
|
|||
raise exception.NovaException(msg)
|
||||
|
||||
def setup(self, mount=True):
|
||||
LOG.debug("Setting up appliance for %(imgfile)s %(imgfmt)s",
|
||||
{'imgfile': self.imgfile, 'imgfmt': self.imgfmt})
|
||||
LOG.debug("Setting up appliance for %(image)s",
|
||||
{'image': self.image})
|
||||
try:
|
||||
self.handle = tpool.Proxy(
|
||||
guestfs.GuestFS(python_return_dict=False,
|
||||
|
@ -195,7 +202,21 @@ class VFSGuestFS(vfs.VFS):
|
|||
pass
|
||||
|
||||
try:
|
||||
self.handle.add_drive_opts(self.imgfile, format=self.imgfmt)
|
||||
if isinstance(self.image, imgmodel.LocalImage):
|
||||
self.handle.add_drive_opts(self.image.path,
|
||||
format=self.image.format)
|
||||
elif isinstance(self.image, imgmodel.RBDImage):
|
||||
self.handle.add_drive_opts("%s/%s" % (self.image.pool,
|
||||
self.image.name),
|
||||
protocol="rbd",
|
||||
format=imgmodel.FORMAT_RAW,
|
||||
server=self.image.servers,
|
||||
username=self.image.user,
|
||||
secret=self.image.password)
|
||||
else:
|
||||
raise exception.UnsupportedImageModel(
|
||||
self.image.__class__.__name__)
|
||||
|
||||
self.handle.launch()
|
||||
|
||||
if mount:
|
||||
|
@ -208,8 +229,8 @@ class VFSGuestFS(vfs.VFS):
|
|||
# close() is not enough
|
||||
self.teardown()
|
||||
raise exception.NovaException(
|
||||
_("Error mounting %(imgfile)s with libguestfs (%(e)s)") %
|
||||
{'imgfile': self.imgfile, 'e': e})
|
||||
_("Error mounting %(image)s with libguestfs (%(e)s)") %
|
||||
{'image': self.image, 'e': e})
|
||||
except Exception:
|
||||
# explicitly teardown instead of implicit close()
|
||||
# to prevent orphaned VMs in cases when an implicit
|
||||
|
|
|
@ -21,10 +21,8 @@ from oslo_utils import excutils
|
|||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import utils
|
||||
from nova.virt.disk.mount import loop
|
||||
from nova.virt.disk.mount import nbd
|
||||
from nova.virt.disk.mount import api as mount_api
|
||||
from nova.virt.disk.vfs import api as vfs
|
||||
from nova.virt.image import model as imgmodel
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -55,8 +53,15 @@ class VFSLocalFS(vfs.VFS):
|
|||
raw, it will use the loopback mount impl, otherwise it will
|
||||
use the qemu-nbd impl.
|
||||
"""
|
||||
def __init__(self, imgfile, imgfmt="raw", partition=None, imgdir=None):
|
||||
super(VFSLocalFS, self).__init__(imgfile, imgfmt, partition)
|
||||
def __init__(self, image, partition=None, imgdir=None):
|
||||
"""Create a new local VFS instance
|
||||
|
||||
:param image: instance of nova.virt.image.model.Image
|
||||
:param partition: the partition number of access
|
||||
:param imgdir: the directory to mount the image at
|
||||
"""
|
||||
|
||||
super(VFSLocalFS, self).__init__(image, partition)
|
||||
|
||||
self.imgdir = imgdir
|
||||
self.mount = None
|
||||
|
@ -64,20 +69,9 @@ class VFSLocalFS(vfs.VFS):
|
|||
def setup(self, mount=True):
|
||||
self.imgdir = tempfile.mkdtemp(prefix="openstack-vfs-localfs")
|
||||
try:
|
||||
if self.imgfmt == "raw":
|
||||
LOG.debug("Using LoopMount")
|
||||
mnt = loop.LoopMount(
|
||||
imgmodel.LocalFileImage(self.imgfile,
|
||||
imgmodel.FORMAT_RAW),
|
||||
self.imgdir,
|
||||
self.partition)
|
||||
else:
|
||||
LOG.debug("Using NbdMount")
|
||||
mnt = nbd.NbdMount(
|
||||
imgmodel.LocalFileImage(self.imgfile,
|
||||
imgmodel.FORMAT_QCOW2),
|
||||
self.imgdir,
|
||||
self.partition)
|
||||
mnt = mount_api.Mount.instance_for_format(self.image,
|
||||
self.imgdir,
|
||||
self.partition)
|
||||
if mount:
|
||||
if not mnt.do_mount():
|
||||
raise exception.NovaException(mnt.error)
|
||||
|
|
|
@ -54,11 +54,11 @@ from nova.virt import diagnostics
|
|||
from nova.virt.disk import api as disk
|
||||
from nova.virt.disk.vfs import localfs as vfsimpl
|
||||
from nova.virt import hardware
|
||||
from nova.virt.image import model as imgmodel
|
||||
from nova.virt import netutils
|
||||
from nova.virt.xenapi import agent
|
||||
from nova.virt.xenapi.image import utils as image_utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
xenapi_vm_utils_opts = [
|
||||
|
@ -2462,9 +2462,15 @@ def _mounted_processing(device, key, net, metadata):
|
|||
try:
|
||||
# This try block ensures that the umount occurs
|
||||
if not agent.find_guest_agent(tmpdir):
|
||||
vfs = vfsimpl.VFSLocalFS(imgfile=None,
|
||||
imgfmt=None,
|
||||
imgdir=tmpdir)
|
||||
# TODO(berrange) passing in a None filename is
|
||||
# rather dubious. We shouldn't be re-implementing
|
||||
# the mount/unmount logic here either, when the
|
||||
# VFSLocalFS impl has direct support for mount
|
||||
# and unmount handling if it were passed a
|
||||
# non-None filename
|
||||
vfs = vfsimpl.VFSLocalFS(
|
||||
imgmodel.LocalFileImage(None, imgmodel.FORMAT_RAW),
|
||||
imgdir=tmpdir)
|
||||
LOG.info(_LI('Manipulating interface files directly'))
|
||||
# for xenapi, we don't 'inject' admin_password here,
|
||||
# it's handled at instance startup time, nor do we
|
||||
|
|
Loading…
Reference in New Issue