nova/nova/tests/unit/virt/disk/vfs/test_localfs.py

231 lines
8.2 KiB
Python

# Copyright (C) 2012 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import grp
import pwd
import tempfile
from collections import namedtuple
import mock
from nova import exception
from nova import test
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
class VirtDiskVFSLocalFSTestPaths(test.NoDBTestCase):
def setUp(self):
super(VirtDiskVFSLocalFSTestPaths, self).setUp()
self.rawfile = imgmodel.LocalFileImage('/dummy.img',
imgmodel.FORMAT_RAW)
# NOTE(mikal): mocking a decorator is non-trivial, so this is the
# best we can do.
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
def test_check_safe_path(self, read_link):
vfs = vfsimpl.VFSLocalFS(self.rawfile)
vfs.imgdir = '/foo'
read_link.return_value = '/foo/etc/something.conf'
ret = vfs._canonical_path('etc/something.conf')
self.assertEqual(ret, '/foo/etc/something.conf')
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
def test_check_unsafe_path(self, read_link):
vfs = vfsimpl.VFSLocalFS(self.rawfile)
vfs.imgdir = '/foo'
read_link.return_value = '/etc/something.conf'
self.assertRaises(exception.Invalid,
vfs._canonical_path,
'etc/../../../something.conf')
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)
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'makedirs')
def test_makepath(self, mkdir, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
vfs.make_path('/some/dir')
read_link.assert_called()
mkdir.assert_called_with(read_link.return_value)
read_link.reset_mock()
mkdir.reset_mock()
vfs.make_path('/other/dir')
read_link.assert_called()
mkdir.assert_called_with(read_link.return_value)
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'writefile')
def test_append_file(self, write_file, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
vfs.append_file('/some/file', ' Goodbye')
read_link.assert_called()
write_file.assert_called_with(read_link.return_value, 'a', ' Goodbye')
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'writefile')
def test_replace_file(self, write_file, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
vfs.replace_file('/some/file', 'Goodbye')
read_link.assert_called()
write_file.assert_called_with(read_link.return_value, 'w', 'Goodbye')
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'readfile')
def test_read_file(self, read_file, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
self.assertEqual(read_file.return_value, vfs.read_file('/some/file'))
read_link.assert_called()
read_file.assert_called()
@mock.patch.object(nova.privsep.dac_admin.path, 'exists')
def test_has_file(self, exists):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
has = vfs.has_file('/some/file')
self.assertEqual(exists.return_value, has)
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'chmod')
def test_set_permissions(self, chmod, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
vfs.set_permissions('/some/file', 0o777)
read_link.assert_called()
chmod.assert_called_with(read_link.return_value, 0o777)
@mock.patch.object(nova.privsep.dac_admin, 'readlink')
@mock.patch.object(nova.privsep.dac_admin, 'chown')
@mock.patch.object(pwd, 'getpwnam')
@mock.patch.object(grp, 'getgrnam')
def test_set_ownership(self, getgrnam, getpwnam, chown, read_link):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
vfs.imgdir = '/scratch/dir'
fake_passwd = namedtuple('fake_passwd', 'pw_uid')
getpwnam.return_value(fake_passwd(pw_uid=100))
fake_group = namedtuple('fake_group', 'gr_gid')
getgrnam.return_value(fake_group(gr_gid=101))
vfs.set_ownership('/some/file', 'fred', None)
read_link.assert_called()
chown.assert_called_with(read_link.return_value,
uid=getpwnam.return_value.pw_uid)
read_link.reset_mock()
chown.reset_mock()
vfs.set_ownership('/some/file', None, 'users')
read_link.assert_called()
chown.assert_called_with(read_link.return_value,
gid=getgrnam.return_value.gr_gid)
read_link.reset_mock()
chown.reset_mock()
vfs.set_ownership('/some/file', 'joe', 'admins')
read_link.assert_called()
chown.assert_called_with(read_link.return_value,
uid=getpwnam.return_value.pw_uid,
gid=getgrnam.return_value.gr_gid)
@mock.patch.object(nova.utils, 'execute')
def test_get_format_fs(self, execute):
vfs = vfsimpl.VFSLocalFS(self.rawfile)
vfs.setup = mock.MagicMock()
vfs.teardown = mock.MagicMock()
def fake_setup():
vfs.mount = mock.MagicMock()
vfs.mount.device = None
vfs.mount.get_dev.side_effect = fake_get_dev
def fake_teardown():
vfs.mount.device = None
def fake_get_dev():
vfs.mount.device = '/dev/xyz'
return True
vfs.setup.side_effect = fake_setup
vfs.teardown.side_effect = fake_teardown
execute.return_value = ('ext3\n', '')
vfs.setup()
self.assertEqual('ext3', vfs.get_image_fs())
vfs.teardown()
vfs.mount.get_dev.assert_called_once_with()
execute.assert_called_once_with('blkid', '-o',
'value', '-s',
'TYPE', '/dev/xyz',
run_as_root=True,
check_exit_code=[0, 2])
@mock.patch.object(tempfile, 'mkdtemp')
@mock.patch.object(nbd, 'NbdMount')
def test_setup_mount(self, NbdMount, mkdtemp):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
mounter = mock.MagicMock()
mkdtemp.return_value = 'tmp/'
NbdMount.return_value = mounter
vfs.setup()
self.assertTrue(mkdtemp.called)
NbdMount.assert_called_once_with(self.qcowfile, 'tmp/', None)
mounter.do_mount.assert_called_once_with()
@mock.patch.object(tempfile, 'mkdtemp')
@mock.patch.object(nbd, 'NbdMount')
def test_setup_mount_false(self, NbdMount, mkdtemp):
vfs = vfsimpl.VFSLocalFS(self.qcowfile)
mounter = mock.MagicMock()
mkdtemp.return_value = 'tmp/'
NbdMount.return_value = mounter
vfs.setup(mount=False)
self.assertTrue(mkdtemp.called)
NbdMount.assert_called_once_with(self.qcowfile, 'tmp/', None)
self.assertFalse(mounter.do_mount.called)