
Fuel agent is a bunch of tools which are supposed to be placed on bootstrap image and used for node discovering and image based provisioning. Implements: blueprint image-based-provisioning Change-Id: I946decd50c51e6db767401682d9effbe3cf42bed
288 lines
12 KiB
Python
288 lines
12 KiB
Python
# Copyright 2014 Mirantis, 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 mock
|
|
from oslotest import base as test_base
|
|
|
|
from fuel_agent import errors
|
|
from fuel_agent.utils import lvm_utils as lu
|
|
from fuel_agent.utils import utils
|
|
|
|
|
|
class TestLvmUtils(test_base.BaseTestCase):
|
|
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_pvdisplay(self, mock_exec):
|
|
# should run os command pvdisplay
|
|
# in order to get actual pv configuration
|
|
mock_exec.return_value = (
|
|
'/dev/fake1;vg;892.00m;1024.00m;'
|
|
'123456-1234-1234-1234-1234-1234-000000\n'
|
|
'/dev/fake2;;1024.00m;1024.00m;'
|
|
'123456-1234-1234-1234-1234-1234-111111\n',
|
|
''
|
|
)
|
|
expected = [
|
|
{
|
|
'uuid': '123456-1234-1234-1234-1234-1234-000000',
|
|
'vg': 'vg',
|
|
'devsize': 1024,
|
|
'psize': 892,
|
|
'name': '/dev/fake1',
|
|
},
|
|
{
|
|
'uuid': '123456-1234-1234-1234-1234-1234-111111',
|
|
'vg': None,
|
|
'devsize': 1024,
|
|
'psize': 1024,
|
|
'name': '/dev/fake2',
|
|
}
|
|
]
|
|
|
|
pvs = lu.pvdisplay()
|
|
mock_exec.assert_called_once_with(
|
|
'pvdisplay',
|
|
'-C',
|
|
'--noheading',
|
|
'--units', 'm',
|
|
'--options', 'pv_name,vg_name,pv_size,dev_size,pv_uuid',
|
|
'--separator', ';',
|
|
check_exit_code=[0]
|
|
)
|
|
key = lambda x: x['name']
|
|
self.assertEqual(sorted(expected, key=key), sorted(pvs, key=key))
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_pvcreate_ok(self, mock_exec, mock_pvdisplay):
|
|
# should set metadatasize=64 and metadatacopies=2 if they are not set
|
|
# should run pvcreate command
|
|
mock_pvdisplay.return_value = [{'name': '/dev/another'}]
|
|
|
|
lu.pvcreate('/dev/fake1', metadatasize=32, metadatacopies=1)
|
|
lu.pvcreate('/dev/fake2', metadatacopies=1)
|
|
lu.pvcreate('/dev/fake3', metadatasize=32)
|
|
lu.pvcreate('/dev/fake4')
|
|
|
|
expected_calls = [
|
|
mock.call('pvcreate',
|
|
'--metadatacopies', '1',
|
|
'--metadatasize', '32m',
|
|
'/dev/fake1',
|
|
check_exit_code=[0]),
|
|
mock.call('pvcreate',
|
|
'--metadatacopies', '1',
|
|
'--metadatasize', '64m',
|
|
'/dev/fake2',
|
|
check_exit_code=[0]),
|
|
mock.call('pvcreate',
|
|
'--metadatacopies', '2',
|
|
'--metadatasize', '32m',
|
|
'/dev/fake3',
|
|
check_exit_code=[0]),
|
|
mock.call('pvcreate',
|
|
'--metadatacopies', '2',
|
|
'--metadatasize', '64m',
|
|
'/dev/fake4',
|
|
check_exit_code=[0])
|
|
]
|
|
self.assertEqual(mock_exec.call_args_list, expected_calls)
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
def test_pvcreate_duplicate(self, mock_pvdisplay):
|
|
# should check if pv exists
|
|
# then raise exception if it exists
|
|
mock_pvdisplay.return_value = [{'name': '/dev/fake'}]
|
|
self.assertRaises(
|
|
errors.PVAlreadyExistsError, lu.pvcreate, '/dev/fake')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_pvremove_ok(self, mock_exec, mock_pvdisplay):
|
|
# should check if pv exists and is not attached to some vg
|
|
# then should run pvremove command
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake'}]
|
|
lu.pvremove('/dev/fake')
|
|
mock_exec.assert_called_once_with('pvremove', '-ff', '-y', '/dev/fake',
|
|
check_exit_code=[0])
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
def test_pvremove_attached_to_vg(self, mock_pvdisplay):
|
|
# should check if pv exists and is not attached to some vg
|
|
# then raise exception if it is attached to some vg
|
|
mock_pvdisplay.return_value = [{'vg': 'some', 'name': '/dev/fake'}]
|
|
self.assertRaises(errors.PVBelongsToVGError, lu.pvremove, '/dev/fake')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
def test_pvremove_notfound(self, mock_pvdisplay):
|
|
# should check if pv exists
|
|
# then should raise exception if it does not exist
|
|
mock_pvdisplay.return_value = [{'name': '/dev/another'}]
|
|
self.assertRaises(errors.PVNotFoundError, lu.pvremove, '/dev/fake')
|
|
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgdisplay(self, mock_exec):
|
|
# should run os command vgdisplay
|
|
# in order to get actual vg configuration
|
|
mock_exec.return_value = (
|
|
'vg1;123456-1234-1234-1234-1234-1234-000000;2040.00m;2040.00m\n'
|
|
'vg2;123456-1234-1234-1234-1234-1234-111111;2040.00m;1020.00m\n',
|
|
''
|
|
)
|
|
expected = [
|
|
{
|
|
'uuid': '123456-1234-1234-1234-1234-1234-000000',
|
|
'size': 2040,
|
|
'free': 2040,
|
|
'name': 'vg1',
|
|
},
|
|
{
|
|
'uuid': '123456-1234-1234-1234-1234-1234-111111',
|
|
'size': 2040,
|
|
'free': 1020,
|
|
'name': 'vg2',
|
|
}
|
|
]
|
|
|
|
vg = lu.vgdisplay()
|
|
mock_exec.assert_called_once_with(
|
|
'vgdisplay',
|
|
'-C',
|
|
'--noheading',
|
|
'--units', 'm',
|
|
'--options', 'vg_name,vg_uuid,vg_size,vg_free',
|
|
'--separator', ';',
|
|
check_exit_code=[0]
|
|
)
|
|
key = lambda x: x['name']
|
|
self.assertEqual(sorted(expected, key=key), sorted(vg, key=key))
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgcreate_ok(self, mock_exec, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if vg already exists
|
|
# should check if all necessary pv exist
|
|
# should run vgcreate command
|
|
mock_vgdisplay.return_value = [{'name': 'some'}, {'name': 'another'}]
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': None, 'name': '/dev/fake2'}]
|
|
|
|
# one pvname
|
|
lu.vgcreate('vgname', '/dev/fake1')
|
|
# several pvnames
|
|
lu.vgcreate('vgname', '/dev/fake1', '/dev/fake2')
|
|
|
|
expected_calls = [
|
|
mock.call('vgcreate', 'vgname', '/dev/fake1',
|
|
check_exit_code=[0]),
|
|
mock.call('vgcreate', 'vgname', '/dev/fake1', '/dev/fake2',
|
|
check_exit_code=[0])
|
|
]
|
|
self.assertEqual(mock_exec.call_args_list, expected_calls)
|
|
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
def test_vgcreate_duplicate(self, mock_vgdisplay):
|
|
# should check if vg exists
|
|
# should raise exception if it exists
|
|
mock_vgdisplay.return_value = [{'name': 'vgname'}, {'name': 'some'}]
|
|
self.assertRaises(errors.VGAlreadyExistsError,
|
|
lu.vgcreate, 'vgname', '/dev/fake')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
def test_vgcreate_pv_not_found(self, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if all necessary pv exist
|
|
# should raise error if at least one pv does not
|
|
mock_vgdisplay.return_value = []
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': None, 'name': '/dev/fake2'}]
|
|
self.assertRaises(errors.PVNotFoundError,
|
|
lu.vgcreate, 'vgname', '/dev/fake', '/dev/fake2')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
def test_vgcreate_pv_attached(self, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if all necessary pv are not attached to some vg
|
|
# should raise error if at least one pv is attached
|
|
mock_vgdisplay.return_value = []
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': 'some', 'name': '/dev/fake2'}]
|
|
self.assertRaises(errors.PVBelongsToVGError,
|
|
lu.vgcreate, 'vgname', '/dev/fake1', '/dev/fake2')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgextend_ok(self, mock_exec, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if vg exists
|
|
# should check if all necessary pv exist and not attached to any vg
|
|
# should run vgextend command
|
|
mock_vgdisplay.return_value = [{'name': 'some'}, {'name': 'another'}]
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': None, 'name': '/dev/fake2'}]
|
|
lu.vgextend('some', '/dev/fake1', '/dev/fake2')
|
|
mock_exec.assert_called_once_with(
|
|
'vgextend', 'some', '/dev/fake1', '/dev/fake2',
|
|
check_exit_code=[0])
|
|
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgextend_not_found(self, mock_exec, mock_vgdisplay):
|
|
# should check if vg exists
|
|
# should raise error if it does not
|
|
mock_vgdisplay.return_value = [{'name': 'some'}]
|
|
self.assertRaises(errors.VGNotFoundError,
|
|
lu.vgextend, 'vgname', '/dev/fake1')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
def test_vgextend_pv_not_found(self, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if all necessary pv exist
|
|
# should raise error if at least one pv does not
|
|
mock_vgdisplay.return_value = [{'name': 'vgname'}]
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': None, 'name': '/dev/fake2'}]
|
|
self.assertRaises(errors.PVNotFoundError,
|
|
lu.vgextend, 'vgname', '/dev/fake', '/dev/fake2')
|
|
|
|
@mock.patch.object(lu, 'pvdisplay')
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
def test_vgextend_pv_attached(self, mock_vgdisplay, mock_pvdisplay):
|
|
# should check if all necessary pv are not attached to some vg
|
|
# should raise error if at least one pv is attached
|
|
mock_vgdisplay.return_value = [{'name': 'vgname'}]
|
|
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
|
{'vg': 'some', 'name': '/dev/fake2'}]
|
|
self.assertRaises(errors.PVBelongsToVGError,
|
|
lu.vgextend, 'vgname', '/dev/fake1', '/dev/fake2')
|
|
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgremove_ok(self, mock_exec, mock_vgdisplay):
|
|
# should check if vg exists
|
|
# then run vgremove command if it exists
|
|
mock_vgdisplay.return_value = [{'name': 'vgname'}, {'name': 'some'}]
|
|
lu.vgremove('vgname')
|
|
mock_exec.assert_called_once_with('vgremove', '-f', 'vgname',
|
|
check_exit_code=[0])
|
|
|
|
@mock.patch.object(lu, 'vgdisplay')
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_vgremove_not_found(self, mock_exec, mock_vgdisplay):
|
|
# should check if vg exists
|
|
# then raise error if it doesn't
|
|
mock_vgdisplay.return_value = [{'name': 'some'}]
|
|
self.assertRaises(errors.VGNotFoundError, lu.vgremove, 'vgname')
|