Improve test coverage for fuel_agent
* should be 100% * also comes with fixups Partially implements: blueprint image-based-provisioning Change-Id: I73ff92f65c0872ad82917d22900c3f410986629d
This commit is contained in:
parent
7730a743bb
commit
291ef045f5
@ -67,7 +67,7 @@ class Nailgun(object):
|
||||
@property
|
||||
def ks_vgs(self):
|
||||
vg_filter = lambda x: x['type'] == 'vg'
|
||||
self.ks_vgs = filter(vg_filter, self.partition_data())
|
||||
return filter(vg_filter, self.partition_data())
|
||||
|
||||
@property
|
||||
def hu_disks(self):
|
||||
@ -107,7 +107,7 @@ class Nailgun(object):
|
||||
ks_spaces_validator.validate(data)
|
||||
partition_scheme = objects.PartitionScheme()
|
||||
|
||||
for disk in enumerate(self.ks_disks):
|
||||
for disk in self.ks_disks:
|
||||
parted = partition_scheme.add_parted(
|
||||
name=self._disk_dev(disk), label='gpt')
|
||||
# legacy boot partition
|
||||
@ -147,7 +147,7 @@ class Nailgun(object):
|
||||
if partition_scheme.configdrive_device() is None:
|
||||
parted.add_partition(size=20, configdrive=True)
|
||||
|
||||
for vg in enumerate(self.ks_vgs):
|
||||
for vg in self.ks_vgs:
|
||||
for volume in vg['volumes']:
|
||||
if volume['size'] <= 0:
|
||||
continue
|
||||
@ -172,7 +172,7 @@ class Nailgun(object):
|
||||
admin_interface = filter(
|
||||
lambda x: (x['mac_address'] ==
|
||||
data['kernel_options']['netcfg/choose_interface']),
|
||||
[spec.update(name=name) for name, spec
|
||||
[dict(name=name, **spec) for name, spec
|
||||
in data['interfaces'].iteritems()])[0]
|
||||
configdrive_scheme.set_common(
|
||||
ssh_auth_key=data['ks_meta']['auth_key'],
|
||||
@ -181,7 +181,7 @@ class Nailgun(object):
|
||||
name_servers=data['name_servers'],
|
||||
search_domain=data['name_servers_search'],
|
||||
master_ip=data['ks_meta']['master_ip'],
|
||||
master_url='http:/%s:8000/api' % self.data['master_ip'],
|
||||
master_url='http://%s:8000/api' % data['ks_meta']['master_ip'],
|
||||
udevrules=data['kernel_options']['udevrules'],
|
||||
admin_mac=data['kernel_options']['netcfg/choose_interface'],
|
||||
admin_ip=admin_interface['ip_address'],
|
||||
@ -198,7 +198,7 @@ class Nailgun(object):
|
||||
pskey=data['ks_meta']['mco_pskey'],
|
||||
vhost=data['ks_meta']['mco_vhost'],
|
||||
host=data['ks_meta']['mco_host'],
|
||||
user=data['ks_meta']['mco_host'],
|
||||
user=data['ks_meta']['mco_user'],
|
||||
password=data['ks_meta']['mco_password'],
|
||||
connector=data['ks_meta']['mco_connector']
|
||||
)
|
||||
|
@ -93,3 +93,7 @@ class WrongConfigDriveDataError(BaseError):
|
||||
|
||||
class WrongImageDataError(BaseError):
|
||||
pass
|
||||
|
||||
|
||||
class TemplateWriteError(BaseError):
|
||||
pass
|
||||
|
@ -65,7 +65,7 @@ class Manager(object):
|
||||
def do_partitioning(self):
|
||||
for parted in self.partition_scheme.parteds:
|
||||
pu.make_label(parted.name, parted.label)
|
||||
for prt in parted.partititons:
|
||||
for prt in parted.partitions:
|
||||
pu.make_partition(prt.device, prt.begin, prt.end, prt.type)
|
||||
for flag in prt.flags:
|
||||
pu.set_partition_flag(prt.device, prt.count, flag)
|
||||
@ -94,6 +94,7 @@ class Manager(object):
|
||||
cc_output_path = os.path.join(CONF.tmp_path, 'cloud_config.txt')
|
||||
bh_output_path = os.path.join(CONF.tmp_path, 'boothook.txt')
|
||||
# NOTE:file should be strictly named as 'user-data'
|
||||
# the same is for meta-data as well
|
||||
ud_output_path = os.path.join(CONF.tmp_path, 'user-data')
|
||||
md_output_path = os.path.join(CONF.tmp_path, 'meta-data')
|
||||
|
||||
@ -123,7 +124,7 @@ class Manager(object):
|
||||
raise errors.WrongPartitionSchemeError(
|
||||
'Error while trying to get configdrive device: '
|
||||
'configdrive device not found')
|
||||
self.image_scheme.add_configdrive_image(
|
||||
self.image_scheme.add_image(
|
||||
uri='file://%s' % CONF.config_drive_path,
|
||||
target_device=configdrive_device,
|
||||
image_format='iso9660',
|
||||
|
@ -15,6 +15,7 @@
|
||||
from fuel_agent.objects.configdrive import ConfigDriveCommon
|
||||
from fuel_agent.objects.configdrive import ConfigDriveMcollective
|
||||
from fuel_agent.objects.configdrive import ConfigDrivePuppet
|
||||
from fuel_agent.objects.configdrive import ConfigDriveScheme
|
||||
from fuel_agent.objects.image import Image
|
||||
from fuel_agent.objects.image import ImageScheme
|
||||
from fuel_agent.objects.partition import Fs
|
||||
|
@ -17,7 +17,8 @@ from fuel_agent import errors
|
||||
|
||||
class ConfigDriveCommon(object):
|
||||
def __init__(self, ssh_auth_key, hostname, fqdn, name_servers,
|
||||
search_domain, master_ip, master_url, timezone):
|
||||
search_domain, master_ip, master_url, udevrules, admin_mac,
|
||||
admin_ip, admin_mask, admin_iface_name, timezone):
|
||||
self.ssh_auth_key = ssh_auth_key
|
||||
self.hostname = hostname
|
||||
self.fqdn = fqdn
|
||||
@ -25,6 +26,11 @@ class ConfigDriveCommon(object):
|
||||
self.search_domain = search_domain
|
||||
self.master_ip = master_ip
|
||||
self.master_url = master_url
|
||||
self.udevrules = udevrules
|
||||
self.admin_mac = admin_mac
|
||||
self.admin_ip = admin_ip
|
||||
self.admin_mask = admin_mask
|
||||
self.admin_iface_name = admin_iface_name
|
||||
self.timezone = timezone
|
||||
|
||||
|
||||
|
@ -70,6 +70,7 @@ class Parted(object):
|
||||
return 'primary'
|
||||
elif len(self.partitions) == 3 and not self.extended:
|
||||
return 'extended'
|
||||
#NOTE(agordeev): how to reach that condition?
|
||||
else:
|
||||
return 'logical'
|
||||
|
||||
@ -90,7 +91,7 @@ class Parted(object):
|
||||
if self.next_type() == 'extended':
|
||||
return None
|
||||
separator = ''
|
||||
if self.name.find('cciss') >= 0 or self.name.find('loop') >= 0:
|
||||
if 'cciss' in self.name or 'loop' in self.name:
|
||||
separator = 'p'
|
||||
return '%s%s%s' % (self.name, separator, self.next_count())
|
||||
|
||||
@ -212,9 +213,10 @@ class PartitionScheme(object):
|
||||
return fs
|
||||
|
||||
def add_md(self, **kwargs):
|
||||
kwargs['name'] = kwargs.get('name') or self.md_next_name()
|
||||
kwargs['level'] = kwargs.get('level') or 'mirror'
|
||||
md = Md(**kwargs)
|
||||
mdkwargs = {}
|
||||
mdkwargs['name'] = kwargs.get('name') or self.md_next_name()
|
||||
mdkwargs['level'] = kwargs.get('level') or 'mirror'
|
||||
md = Md(**mdkwargs)
|
||||
self.mds.append(md)
|
||||
return md
|
||||
|
||||
@ -234,7 +236,7 @@ class PartitionScheme(object):
|
||||
md = self.add_md(**kwargs)
|
||||
fskwargs = {}
|
||||
fskwargs['device'] = md.name
|
||||
fskwargs['mount'] = kwargs.pop('mount')
|
||||
fskwargs['mount'] = mount
|
||||
fskwargs['fs_type'] = kwargs.pop('fs_type', None)
|
||||
fskwargs['fs_options'] = kwargs.pop('fs_options', None)
|
||||
fskwargs['fs_label'] = kwargs.pop('fs_label', None)
|
||||
@ -248,11 +250,12 @@ class PartitionScheme(object):
|
||||
name = '/dev/md%s' % count
|
||||
if name not in [md.name for md in self.mds]:
|
||||
return name
|
||||
if count > 127:
|
||||
if count >= 127:
|
||||
raise errors.MDAlreadyExistsError(
|
||||
'Error while generating md name: '
|
||||
'names from /dev/md0 to /dev/md127 seem to be busy, '
|
||||
'try to generate md name manually')
|
||||
count += 1
|
||||
|
||||
def vg_by_name(self, vgname):
|
||||
found = filter(lambda x: (x.name == vgname), self.vgs)
|
||||
@ -292,6 +295,6 @@ class PartitionScheme(object):
|
||||
# only if one uses cloud-init with configdrive.
|
||||
def configdrive_device(self):
|
||||
for parted in self.parteds:
|
||||
for prt in parted.partititons:
|
||||
for prt in parted.partitions:
|
||||
if prt.configdrive:
|
||||
return prt.name
|
||||
|
52
fuel_agent/tests/test_configdrive.py
Normal file
52
fuel_agent/tests/test_configdrive.py
Normal file
@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.objects import configdrive
|
||||
|
||||
|
||||
class TestConfigDriveScheme(test_base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestConfigDriveScheme, self).setUp()
|
||||
self.cd_scheme = configdrive.ConfigDriveScheme()
|
||||
|
||||
def test_template_name(self):
|
||||
actual = self.cd_scheme.template_name('what')
|
||||
expected = '%s_%s.jinja2' % ('what', self.cd_scheme._profile)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_template_data_no_common(self):
|
||||
self.assertRaises(errors.WrongConfigDriveDataError,
|
||||
self.cd_scheme.template_data)
|
||||
|
||||
def test_template_data_ok(self):
|
||||
cd_common = configdrive.ConfigDriveCommon(
|
||||
'ssh_auth_key', 'hostname', 'fqdn', 'name_servers',
|
||||
'search_domain', 'master_ip', 'master_url', 'udevrules',
|
||||
'admin_mac', 'admin_ip', 'admin_mask', 'admin_iface_name',
|
||||
'timezone')
|
||||
cd_puppet = configdrive.ConfigDrivePuppet('master')
|
||||
cd_mcollective = configdrive.ConfigDriveMcollective(
|
||||
'pskey', 'vhost', 'host', 'user', 'password', 'connector')
|
||||
self.cd_scheme.common = cd_common
|
||||
self.cd_scheme.puppet = cd_puppet
|
||||
self.cd_scheme.mcollective = cd_mcollective
|
||||
template_data = self.cd_scheme.template_data()
|
||||
self.assertEqual(cd_common, template_data['common'])
|
||||
self.assertEqual(cd_puppet, template_data['puppet'])
|
||||
self.assertEqual(cd_mcollective, template_data['mcollective'])
|
34
fuel_agent/tests/test_fs_utils.py
Normal file
34
fuel_agent/tests/test_fs_utils.py
Normal file
@ -0,0 +1,34 @@
|
||||
# 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.utils import fs_utils as fu
|
||||
from fuel_agent.utils import utils
|
||||
|
||||
|
||||
class TestFSUtils(test_base.BaseTestCase):
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_make_fs(self, mock_exec):
|
||||
fu.make_fs('ext4', ' -F ', ' -L fake_label ', '/dev/fake')
|
||||
mock_exec.assert_called_once_with('mkfs.ext4', '-F', '-L',
|
||||
'fake_label', '/dev/fake')
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_make_fs_swap(self, mock_exec):
|
||||
fu.make_fs('swap', ' -f ', ' -L fake_label ', '/dev/fake')
|
||||
mock_exec.assert_called_once_with('mkswap', '-f', '-L', 'fake_label',
|
||||
'/dev/fake')
|
@ -104,6 +104,7 @@ supports-statistics: yes
|
||||
supports-test: no
|
||||
supports-eeprom-access: no
|
||||
supports-register-dump: yes
|
||||
|
||||
"""]
|
||||
|
||||
expected = {'driver': 'r8169',
|
||||
@ -204,6 +205,12 @@ supports-register-dump: yes
|
||||
expected = {'removable': '0', 'state': 'running', 'timeout': '30'}
|
||||
self.assertEqual(expected, hu.extrareport('/dev/fake'))
|
||||
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_extrareport_exceptions(self, mock_open):
|
||||
mock_open.side_effect = Exception('foo')
|
||||
expected = {}
|
||||
self.assertEqual(expected, hu.extrareport('/dev/fake'))
|
||||
|
||||
@mock.patch.object(hu, 'blockdevreport')
|
||||
@mock.patch.object(hu, 'udevreport')
|
||||
def test_is_disk_uspec_bspec_none(self, mock_ureport, mock_breport):
|
||||
@ -371,3 +378,8 @@ supports-register-dump: yes
|
||||
uspec1 = {'ID_SERIAL_SHORT': 'fakeserial1'}
|
||||
uspec2 = {'ID_SERIAL_SHORT': 'fakeserial2'}
|
||||
self.assertFalse(hu.match_device(uspec1, uspec2))
|
||||
|
||||
def test_match_device_false(self):
|
||||
uspec1 = {'ID_WWN': 'fakewwn1', 'DEVTYPE': 'disk'}
|
||||
uspec2 = {'ID_WWN': 'fakewwn1', 'DEVTYPE': 'partition'}
|
||||
self.assertFalse(hu.match_device(uspec1, uspec2))
|
||||
|
26
fuel_agent/tests/test_image.py
Normal file
26
fuel_agent/tests/test_image.py
Normal file
@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.objects import image
|
||||
|
||||
|
||||
class TestImage(test_base.BaseTestCase):
|
||||
|
||||
def test_unsupported_container(self):
|
||||
self.assertRaises(errors.WrongImageDataError, image.Image, 'uri',
|
||||
'dev', 'format', 'unsupported')
|
204
fuel_agent/tests/test_ks_spaces_validator.py
Normal file
204
fuel_agent/tests/test_ks_spaces_validator.py
Normal file
@ -0,0 +1,204 @@
|
||||
# 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 copy
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from fuel_agent.drivers import ks_spaces_validator as kssv
|
||||
from fuel_agent import errors
|
||||
|
||||
SAMPLE_SCHEME = [
|
||||
{
|
||||
"name": "sda",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VB69050467-b385c7cd",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VB69050467-b385c7cd"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 0
|
||||
},
|
||||
{
|
||||
"size": 19438,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 45597,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "sda",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"name": "sdb",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VBf2923215-708af674",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VBf2923215-708af674"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 64
|
||||
},
|
||||
{
|
||||
"size": 0,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 0,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 64971,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "sdb",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"name": "sdc",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VB50ee61eb-84e74fdf",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VB50ee61eb-84e74fdf"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 64
|
||||
},
|
||||
{
|
||||
"size": 0,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 0,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 64971,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "disk/by-path/pci-0000:00:0d.0-scsi-0:0:0:0",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"_allocate_size": "min",
|
||||
"label": "Base System",
|
||||
"min_size": 19374,
|
||||
"volumes": [
|
||||
{
|
||||
"mount": "/",
|
||||
"size": 15360,
|
||||
"type": "lv",
|
||||
"name": "root",
|
||||
"file_system": "ext4"
|
||||
},
|
||||
{
|
||||
"mount": "swap",
|
||||
"size": 4014,
|
||||
"type": "lv",
|
||||
"name": "swap",
|
||||
"file_system": "swap"
|
||||
}
|
||||
],
|
||||
"type": "vg",
|
||||
"id": "os"
|
||||
},
|
||||
{
|
||||
"_allocate_size": "all",
|
||||
"label": "Image Storage",
|
||||
"min_size": 5120,
|
||||
"volumes": [
|
||||
{
|
||||
"mount": "/var/lib/glance",
|
||||
"size": 175347,
|
||||
"type": "lv",
|
||||
"name": "glance",
|
||||
"file_system": "xfs"
|
||||
}
|
||||
],
|
||||
"type": "vg",
|
||||
"id": "image"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
class TestKSSpacesValidator(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestKSSpacesValidator, self).setUp()
|
||||
self.fake_scheme = copy.deepcopy(SAMPLE_SCHEME)
|
||||
|
||||
def test_validate_ok(self):
|
||||
kssv.validate(self.fake_scheme)
|
||||
|
||||
def test_validate_jsoschema_fail(self):
|
||||
self.assertRaises(errors.WrongPartitionSchemeError, kssv.validate,
|
||||
[{}])
|
||||
|
||||
def test_validate_no_disks_fail(self):
|
||||
self.assertRaises(errors.WrongPartitionSchemeError, kssv.validate,
|
||||
self.fake_scheme[-2:])
|
||||
|
||||
def test_validate_16T_root_volume_fail(self):
|
||||
self.fake_scheme[3]['volumes'][0]['size'] = 16777216 + 1
|
||||
self.assertRaises(errors.WrongPartitionSchemeError, kssv.validate,
|
||||
self.fake_scheme)
|
@ -285,3 +285,101 @@ class TestLvmUtils(test_base.BaseTestCase):
|
||||
# then raise error if it doesn't
|
||||
mock_vgdisplay.return_value = [{'name': 'some'}]
|
||||
self.assertRaises(errors.VGNotFoundError, lu.vgremove, 'vgname')
|
||||
|
||||
@mock.patch.object(lu, 'lvdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvremove_ok(self, mock_exec, mock_lvdisplay):
|
||||
mock_lvdisplay.return_value = [{'name': 'lvname'}, {'name': 'some'}]
|
||||
lu.lvremove('lvname')
|
||||
mock_exec.assert_called_once_with('lvremove', '-f', 'lvname',
|
||||
check_exit_code=[0])
|
||||
|
||||
@mock.patch.object(lu, 'lvdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvremove_not_found(self, mock_exec, mock_lvdisplay):
|
||||
mock_lvdisplay.return_value = [{'name': 'some'}]
|
||||
self.assertRaises(errors.LVNotFoundError, lu.lvremove, 'lvname')
|
||||
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(lu, 'lvdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvcreate_ok(self, mock_exec, mock_lvdisplay, mock_vgdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'vgname', 'free': 2000},
|
||||
{'name': 'some'}]
|
||||
mock_lvdisplay.return_value = [{'name': 'some'}]
|
||||
lu.lvcreate('vgname', 'lvname', 1000)
|
||||
mock_exec.assert_called_once_with('lvcreate', '-L', '1000m', '-n',
|
||||
'lvname', 'vgname',
|
||||
check_exit_code=[0])
|
||||
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvcreate_not_found(self, mock_exec, mock_vgdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'some'}]
|
||||
self.assertRaises(errors.VGNotFoundError, lu.lvcreate, 'vgname',
|
||||
'lvname', 1)
|
||||
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvcreate_not_enough_space(self, mock_exec, mock_vgdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'vgname', 'free': 1},
|
||||
{'name': 'some'}]
|
||||
self.assertRaises(errors.NotEnoughSpaceError, lu.lvcreate, 'vgname',
|
||||
'lvname', 2)
|
||||
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(lu, 'lvdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvcreate_lv_already_exists(self, mock_exec, mock_lvdisplay,
|
||||
mock_vgdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'vgname', 'free': 2000},
|
||||
{'name': 'some'}]
|
||||
mock_lvdisplay.return_value = [{'name': 'lvname'}]
|
||||
self.assertRaises(errors.LVAlreadyExistsError, lu.lvcreate, 'vgname',
|
||||
'lvname', 1000)
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_lvdisplay(self, mock_exec):
|
||||
mock_exec.return_value = [
|
||||
' lv_name1;1234.12m;vg_name;lv_uuid1\n'
|
||||
' lv_name2;5678.79m;vg_name;lv_uuid2\n ']
|
||||
expected_lvs = [{'name': 'lv_name1', 'size': 1235, 'vg': 'vg_name',
|
||||
'uuid': 'lv_uuid1', 'path': '/dev/vg_name/lv_name1'},
|
||||
{'name': 'lv_name2', 'size': 5679, 'vg': 'vg_name',
|
||||
'uuid': 'lv_uuid2', 'path': '/dev/vg_name/lv_name2'}]
|
||||
actual_lvs = lu.lvdisplay()
|
||||
self.assertEqual(expected_lvs, actual_lvs)
|
||||
mock_exec.assert_called_once_with('lvdisplay', '-C', '--noheading',
|
||||
'--units', 'm', '--options',
|
||||
'lv_name,lv_size,vg_name,lv_uuid',
|
||||
'--separator', ';',
|
||||
check_exit_code=[0])
|
||||
|
||||
@mock.patch.object(lu, 'pvdisplay')
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_vgreduce_ok(self, mock_exec, mock_vgdisplay, mock_pvdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'vgname'}, {'name': 'some'}]
|
||||
mock_pvdisplay.return_value = [{'vg': 'vgname', 'name': '/dev/fake1'},
|
||||
{'vg': 'vgname', 'name': '/dev/fake2'}]
|
||||
lu.vgreduce('vgname', '/dev/fake1', '/dev/fake2')
|
||||
mock_exec.assert_called_once_with('vgreduce', '-f', 'vgname',
|
||||
'/dev/fake1', '/dev/fake2',
|
||||
check_exit_code=[0])
|
||||
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
def test_vgreduce_vg_not_found(self, mock_vgdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'some'}]
|
||||
self.assertRaises(errors.VGNotFoundError, lu.vgreduce, 'vgname1',
|
||||
'/dev/fake1', '/dev/fake2')
|
||||
|
||||
@mock.patch.object(lu, 'pvdisplay')
|
||||
@mock.patch.object(lu, 'vgdisplay')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_vgreduce_pv_not_attached(self, mock_exec, mock_vgdisplay,
|
||||
mock_pvdisplay):
|
||||
mock_vgdisplay.return_value = [{'name': 'vgname'}, {'name': 'some'}]
|
||||
mock_pvdisplay.return_value = [{'vg': None, 'name': '/dev/fake1'},
|
||||
{'vg': None, 'name': '/dev/fake2'}]
|
||||
self.assertRaises(errors.PVNotFoundError, lu.vgreduce, 'vgname',
|
||||
'/dev/fake1', '/dev/fake2')
|
||||
|
170
fuel_agent/tests/test_manager.py
Normal file
170
fuel_agent/tests/test_manager.py
Normal file
@ -0,0 +1,170 @@
|
||||
# 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 oslo.config import cfg
|
||||
from oslotest import base as test_base
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent import manager
|
||||
from fuel_agent.objects import partition
|
||||
from fuel_agent.tests import test_nailgun
|
||||
from fuel_agent.utils import fs_utils as fu
|
||||
from fuel_agent.utils import hardware_utils as hu
|
||||
from fuel_agent.utils import lvm_utils as lu
|
||||
from fuel_agent.utils import md_utils as mu
|
||||
from fuel_agent.utils import partition_utils as pu
|
||||
from fuel_agent.utils import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class TestManager(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestManager, self).setUp()
|
||||
self.mgr = manager.Manager(test_nailgun.PROVISION_SAMPLE_DATA)
|
||||
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_do_parsing(self, mock_lbd):
|
||||
mock_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
|
||||
self.mgr.do_parsing()
|
||||
#NOTE(agordeev): there's no need for deeper assertions as all schemes
|
||||
# thoroughly tested in test_nailgun
|
||||
self.assertFalse(self.mgr.partition_scheme is None)
|
||||
self.assertFalse(self.mgr.configdrive_scheme is None)
|
||||
self.assertFalse(self.mgr.image_scheme is None)
|
||||
|
||||
@mock.patch.object(fu, 'make_fs')
|
||||
@mock.patch.object(lu, 'lvcreate')
|
||||
@mock.patch.object(lu, 'vgcreate')
|
||||
@mock.patch.object(lu, 'pvcreate')
|
||||
@mock.patch.object(mu, 'mdcreate')
|
||||
@mock.patch.object(pu, 'set_partition_flag')
|
||||
@mock.patch.object(pu, 'make_partition')
|
||||
@mock.patch.object(pu, 'make_label')
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_do_partitioning(self, mock_hu_lbd, mock_pu_ml, mock_pu_mp,
|
||||
mock_pu_spf, mock_mu_m, mock_lu_p, mock_lu_v,
|
||||
mock_lu_l, mock_fu_mf):
|
||||
mock_hu_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
|
||||
self.mgr.do_parsing()
|
||||
self.mgr.do_partitioning()
|
||||
mock_pu_ml_expected_calls = [mock.call('/dev/sda', 'gpt'),
|
||||
mock.call('/dev/sdb', 'gpt'),
|
||||
mock.call('/dev/sdc', 'gpt')]
|
||||
self.assertEqual(mock_pu_ml_expected_calls, mock_pu_ml.call_args_list)
|
||||
|
||||
mock_pu_mp_expected_calls = [
|
||||
mock.call('/dev/sda', 0, 24, 'primary'),
|
||||
mock.call('/dev/sda', 24, 224, 'primary'),
|
||||
mock.call('/dev/sda', 224, 424, 'primary'),
|
||||
mock.call('/dev/sda', 424, 624, 'primary'),
|
||||
mock.call('/dev/sda', 624, 20062, 'primary'),
|
||||
mock.call('/dev/sda', 20062, 65659, 'primary'),
|
||||
mock.call('/dev/sda', 65659, 65679, 'primary'),
|
||||
mock.call('/dev/sdb', 0, 24, 'primary'),
|
||||
mock.call('/dev/sdb', 24, 224, 'primary'),
|
||||
mock.call('/dev/sdb', 224, 424, 'primary'),
|
||||
mock.call('/dev/sdb', 424, 65395, 'primary'),
|
||||
mock.call('/dev/sdc', 0, 24, 'primary'),
|
||||
mock.call('/dev/sdc', 24, 224, 'primary'),
|
||||
mock.call('/dev/sdc', 224, 424, 'primary'),
|
||||
mock.call('/dev/sdc', 424, 65395, 'primary')]
|
||||
self.assertEqual(mock_pu_mp_expected_calls, mock_pu_mp.call_args_list)
|
||||
|
||||
mock_pu_spf_expected_calls = [mock.call('/dev/sda', 1, 'bios_grub'),
|
||||
mock.call('/dev/sdb', 1, 'bios_grub'),
|
||||
mock.call('/dev/sdc', 1, 'bios_grub')]
|
||||
self.assertEqual(mock_pu_spf_expected_calls,
|
||||
mock_pu_spf.call_args_list)
|
||||
|
||||
mock_mu_m_expected_calls = [mock.call('/dev/md0', 'mirror',
|
||||
'/dev/sda3', '/dev/sdb3',
|
||||
'/dev/sdc3')]
|
||||
self.assertEqual(mock_mu_m_expected_calls, mock_mu_m.call_args_list)
|
||||
|
||||
mock_lu_p_expected_calls = [mock.call('/dev/sda5'),
|
||||
mock.call('/dev/sda6'),
|
||||
mock.call('/dev/sdb4'),
|
||||
mock.call('/dev/sdc4')]
|
||||
self.assertEqual(mock_lu_p_expected_calls, mock_lu_p.call_args_list)
|
||||
|
||||
mock_lu_v_expected_calls = [mock.call('os', '/dev/sda5'),
|
||||
mock.call('image', '/dev/sda6',
|
||||
'/dev/sdb4', '/dev/sdc4')]
|
||||
self.assertEqual(mock_lu_v_expected_calls, mock_lu_v.call_args_list)
|
||||
|
||||
mock_lu_l_expected_calls = [mock.call('os', 'root', 15360),
|
||||
mock.call('os', 'swap', 4014),
|
||||
mock.call('image', 'glance', 175347)]
|
||||
self.assertEqual(mock_lu_l_expected_calls, mock_lu_l.call_args_list)
|
||||
|
||||
mock_fu_mf_expected_calls = [
|
||||
mock.call('ext2', '', '', '/dev/md0'),
|
||||
mock.call('ext2', '', '', '/dev/sda4'),
|
||||
mock.call('ext4', '', '', '/dev/mapper/os-root'),
|
||||
mock.call('swap', '', '', '/dev/mapper/os-swap'),
|
||||
mock.call('xfs', '', '', '/dev/mapper/image-glance')]
|
||||
self.assertEqual(mock_fu_mf_expected_calls, mock_fu_mf.call_args_list)
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
@mock.patch.object(utils, 'render_and_save')
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_do_configdrive(self, mock_lbd, mock_u_ras, mock_u_e):
|
||||
mock_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
|
||||
self.mgr.do_parsing()
|
||||
self.assertEqual(1, len(self.mgr.image_scheme.images))
|
||||
self.mgr.do_configdrive()
|
||||
mock_u_ras_expected_calls = [
|
||||
mock.call(CONF.nc_template_path, 'cloud_config_ubuntu.jinja2',
|
||||
mock.ANY, '%s/%s' % (CONF.tmp_path, 'cloud_config.txt')),
|
||||
mock.call(CONF.nc_template_path, 'boothook_ubuntu.jinja2',
|
||||
mock.ANY, '%s/%s' % (CONF.tmp_path, 'boothook.txt')),
|
||||
mock.call(CONF.nc_template_path, 'meta-data_ubuntu.jinja2',
|
||||
mock.ANY, '%s/%s' % (CONF.tmp_path, 'meta-data'))]
|
||||
self.assertEqual(mock_u_ras_expected_calls, mock_u_ras.call_args_list)
|
||||
|
||||
mock_u_e_expected_calls = [
|
||||
mock.call('write-mime-multipart',
|
||||
'--output=%s' % ('%s/%s' % (CONF.tmp_path, 'user-data')),
|
||||
'%s:text/cloud-boothook' % ('%s/%s' % (CONF.tmp_path,
|
||||
'boothook.txt')),
|
||||
'%s:text/cloud-config' % ('%s/%s' % (CONF.tmp_path,
|
||||
'cloud_config.txt'))
|
||||
),
|
||||
mock.call('genisoimage', '-output', CONF.config_drive_path,
|
||||
'-volid', 'cidata', '-joliet', '-rock',
|
||||
'%s/%s' % (CONF.tmp_path, 'user-data'),
|
||||
'%s/%s' % (CONF.tmp_path, 'meta-data'))]
|
||||
self.assertEqual(mock_u_e_expected_calls, mock_u_e.call_args_list)
|
||||
self.assertEqual(2, len(self.mgr.image_scheme.images))
|
||||
cf_drv_img = self.mgr.image_scheme.images[-1]
|
||||
self.assertEqual('file://%s' % CONF.config_drive_path, cf_drv_img.uri)
|
||||
self.assertEqual('/dev/sda7',
|
||||
self.mgr.partition_scheme.configdrive_device())
|
||||
self.assertEqual('iso9660', cf_drv_img.image_format)
|
||||
self.assertEqual('raw', cf_drv_img.container)
|
||||
|
||||
@mock.patch.object(partition.PartitionScheme, 'configdrive_device')
|
||||
@mock.patch.object(utils, 'execute')
|
||||
@mock.patch.object(utils, 'render_and_save')
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_do_configdrive_no_configdrive_device(self, mock_lbd, mock_u_ras,
|
||||
mock_u_e, mock_p_ps_cd):
|
||||
mock_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
|
||||
self.mgr.do_parsing()
|
||||
mock_p_ps_cd.return_value = None
|
||||
self.assertRaises(errors.WrongPartitionSchemeError,
|
||||
self.mgr.do_configdrive)
|
@ -200,3 +200,10 @@ localhost.localdomain)
|
||||
mock_mddisplay.return_value = [{'name': '/dev/md0'}]
|
||||
self.assertRaises(
|
||||
errors.MDNotFoundError, mu.mdremove, '/dev/md1')
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_mdclean(self, mock_exec):
|
||||
mu.mdclean('/dev/md0')
|
||||
mock_exec.assert_called_once_with('mdadm', '--zero-superblock',
|
||||
'--force', '/dev/md0',
|
||||
check_exit_code=[0])
|
||||
|
487
fuel_agent/tests/test_nailgun.py
Normal file
487
fuel_agent/tests/test_nailgun.py
Normal file
@ -0,0 +1,487 @@
|
||||
# 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.drivers import nailgun
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.utils import hardware_utils as hu
|
||||
|
||||
|
||||
PROVISION_SAMPLE_DATA = {
|
||||
"profile": "ubuntu_1204_x86_64",
|
||||
"name_servers_search": "\"domain.tld\"",
|
||||
"uid": "1",
|
||||
"interfaces": {
|
||||
"eth2": {
|
||||
"static": "0",
|
||||
"mac_address": "08:00:27:b1:d7:15"
|
||||
},
|
||||
"eth1": {
|
||||
"static": "0",
|
||||
"mac_address": "08:00:27:46:43:60"
|
||||
},
|
||||
"eth0": {
|
||||
"ip_address": "10.20.0.3",
|
||||
"dns_name": "node-1.domain.tld",
|
||||
"netmask": "255.255.255.0",
|
||||
"static": "0",
|
||||
"mac_address": "08:00:27:79:da:80"
|
||||
}
|
||||
},
|
||||
"interfaces_extra": {
|
||||
"eth2": {
|
||||
"onboot": "no",
|
||||
"peerdns": "no"
|
||||
},
|
||||
"eth1": {
|
||||
"onboot": "no",
|
||||
"peerdns": "no"
|
||||
},
|
||||
"eth0": {
|
||||
"onboot": "yes",
|
||||
"peerdns": "no"
|
||||
}
|
||||
},
|
||||
"power_type": "ssh",
|
||||
"power_user": "root",
|
||||
"kernel_options": {
|
||||
"udevrules": "08:00:27:79:da:80_eth0,08:00:27:46:43:60_eth1,"
|
||||
"08:00:27:b1:d7:15_eth2",
|
||||
"netcfg/choose_interface": "08:00:27:79:da:80"
|
||||
},
|
||||
"power_address": "10.20.0.253",
|
||||
"name_servers": "\"10.20.0.2\"",
|
||||
"ks_meta": {
|
||||
"image_uri": "proto://fake_image_uri",
|
||||
"image_format": "fake_image_format",
|
||||
"image_container": "raw",
|
||||
"timezone": "America/Los_Angeles",
|
||||
"master_ip": "10.20.0.2",
|
||||
"mco_enable": 1,
|
||||
"mco_vhost": "mcollective",
|
||||
"mco_pskey": "unset",
|
||||
"mco_user": "mcollective",
|
||||
"puppet_enable": 0,
|
||||
"fuel_version": "5.0.1",
|
||||
"install_log_2_syslog": 1,
|
||||
"mco_password": "marionette",
|
||||
"puppet_auto_setup": 1,
|
||||
"puppet_master": "fuel.domain.tld",
|
||||
"mco_auto_setup": 1,
|
||||
"auth_key": "fake_auth_key",
|
||||
"pm_data": {
|
||||
"kernel_params": "console=ttyS0,9600 console=tty0 rootdelay=90 "
|
||||
"nomodeset",
|
||||
"ks_spaces": [
|
||||
{
|
||||
"name": "sda",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VB69050467-"
|
||||
"b385c7cd",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VB69050467-b385c7cd"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"mount": "/tmp",
|
||||
"size": 200,
|
||||
"type": "partition",
|
||||
"file_system": "ext2",
|
||||
"partition_guid": "fake_guid",
|
||||
"name": "TMP"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 0
|
||||
},
|
||||
{
|
||||
"size": 19438,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 45597,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "sda",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"name": "sdb",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VBf2923215-"
|
||||
"708af674",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VBf2923215-708af674"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 64
|
||||
},
|
||||
{
|
||||
"size": 0,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 0,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 64971,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "sdb",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"name": "sdc",
|
||||
"extra": [
|
||||
"disk/by-id/scsi-SATA_VBOX_HARDDISK_VB50ee61eb-"
|
||||
"84e74fdf",
|
||||
"disk/by-id/ata-VBOX_HARDDISK_VB50ee61eb-84e74fdf"
|
||||
],
|
||||
"free_space": 64907,
|
||||
"volumes": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 300
|
||||
},
|
||||
{
|
||||
"mount": "/boot",
|
||||
"size": 200,
|
||||
"type": "raid",
|
||||
"file_system": "ext2",
|
||||
"name": "Boot"
|
||||
},
|
||||
{
|
||||
"type": "lvm_meta_pool",
|
||||
"size": 64
|
||||
},
|
||||
{
|
||||
"size": 0,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 0,
|
||||
"vg": "os"
|
||||
},
|
||||
{
|
||||
"size": 64971,
|
||||
"type": "pv",
|
||||
"lvm_meta_size": 64,
|
||||
"vg": "image"
|
||||
}
|
||||
],
|
||||
"type": "disk",
|
||||
"id": "disk/by-path/pci-0000:00:0d.0-scsi-0:0:0:0",
|
||||
"size": 65535
|
||||
},
|
||||
{
|
||||
"_allocate_size": "min",
|
||||
"label": "Base System",
|
||||
"min_size": 19374,
|
||||
"volumes": [
|
||||
{
|
||||
"mount": "/",
|
||||
"size": 15360,
|
||||
"type": "lv",
|
||||
"name": "root",
|
||||
"file_system": "ext4"
|
||||
},
|
||||
{
|
||||
"mount": "swap",
|
||||
"size": 4014,
|
||||
"type": "lv",
|
||||
"name": "swap",
|
||||
"file_system": "swap"
|
||||
}
|
||||
],
|
||||
"type": "vg",
|
||||
"id": "os"
|
||||
},
|
||||
{
|
||||
"_allocate_size": "min",
|
||||
"label": "Zero size volume",
|
||||
"min_size": 0,
|
||||
"volumes": [
|
||||
{
|
||||
"mount": "none",
|
||||
"size": 0,
|
||||
"type": "lv",
|
||||
"name": "zero_size",
|
||||
"file_system": "xfs"
|
||||
}
|
||||
],
|
||||
"type": "vg",
|
||||
"id": "zero_size"
|
||||
},
|
||||
{
|
||||
"_allocate_size": "all",
|
||||
"label": "Image Storage",
|
||||
"min_size": 5120,
|
||||
"volumes": [
|
||||
{
|
||||
"mount": "/var/lib/glance",
|
||||
"size": 175347,
|
||||
"type": "lv",
|
||||
"name": "glance",
|
||||
"file_system": "xfs"
|
||||
}
|
||||
],
|
||||
"type": "vg",
|
||||
"id": "image"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mco_connector": "rabbitmq",
|
||||
"mco_host": "10.20.0.2"
|
||||
},
|
||||
"name": "node-1",
|
||||
"hostname": "node-1.domain.tld",
|
||||
"slave_name": "node-1",
|
||||
"power_pass": "/root/.ssh/bootstrap.rsa",
|
||||
"netboot_enabled": "1"
|
||||
}
|
||||
|
||||
LIST_BLOCK_DEVICES_SAMPLE = [
|
||||
{'uspec':
|
||||
{'DEVLINKS': [
|
||||
'disk/by-id/scsi-SATA_VBOX_HARDDISK_VB69050467-b385c7cd',
|
||||
'/dev/disk/by-id/ata-VBOX_HARDDISK_VB69050467-b385c7cd',
|
||||
'/dev/disk/by-id/wwn-fake_wwn_1',
|
||||
'/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0'],
|
||||
'ID_SERIAL_SHORT': 'fake_serial_1',
|
||||
'ID_WWN': 'fake_wwn_1',
|
||||
'DEVPATH': '/devices/pci0000:00/0000:00:1f.2/ata1/host0/'
|
||||
'target0:0:0/0:0:0:0/block/sda',
|
||||
'ID_MODEL': 'fake_id_model',
|
||||
'DEVNAME': '/dev/sda',
|
||||
'MAJOR': '8',
|
||||
'DEVTYPE': 'disk', 'MINOR': '0', 'ID_BUS': 'ata'
|
||||
},
|
||||
'startsec': '0',
|
||||
'device': '/dev/sda',
|
||||
'espec': {'state': 'running', 'timeout': '30', 'removable': '0'},
|
||||
'bspec': {
|
||||
'sz': '976773168', 'iomin': '4096', 'size64': '500107862016',
|
||||
'ss': '512', 'ioopt': '0', 'alignoff': '0', 'pbsz': '4096',
|
||||
'ra': '256', 'ro': '0', 'maxsect': '1024'
|
||||
},
|
||||
'size': 500107862016},
|
||||
{'uspec':
|
||||
{'DEVLINKS': [
|
||||
'/dev/disk/by-id/ata-VBOX_HARDDISK_VBf2923215-708af674',
|
||||
'/dev/disk/by-id/scsi-SATA_VBOX_HARDDISK_VBf2923215-708af674',
|
||||
'/dev/disk/by-id/wwn-fake_wwn_2'],
|
||||
'ID_SERIAL_SHORT': 'fake_serial_2',
|
||||
'ID_WWN': 'fake_wwn_2',
|
||||
'DEVPATH': '/devices/pci0000:00/0000:00:3f.2/ata2/host0/'
|
||||
'target0:0:0/0:0:0:0/block/sdb',
|
||||
'ID_MODEL': 'fake_id_model',
|
||||
'DEVNAME': '/dev/sdb',
|
||||
'MAJOR': '8',
|
||||
'DEVTYPE': 'disk', 'MINOR': '0', 'ID_BUS': 'ata'
|
||||
},
|
||||
'startsec': '0',
|
||||
'device': '/dev/sdb',
|
||||
'espec': {'state': 'running', 'timeout': '30', 'removable': '0'},
|
||||
'bspec': {
|
||||
'sz': '976773168', 'iomin': '4096', 'size64': '500107862016',
|
||||
'ss': '512', 'ioopt': '0', 'alignoff': '0', 'pbsz': '4096',
|
||||
'ra': '256', 'ro': '0', 'maxsect': '1024'},
|
||||
'size': 500107862016},
|
||||
{'uspec':
|
||||
{'DEVLINKS': [
|
||||
'/dev/disk/by-id/ata-VBOX_HARDDISK_VB50ee61eb-84e74fdf',
|
||||
'/dev/disk/by-id/scsi-SATA_VBOX_HARDDISK_VB50ee61eb-84e74fdf',
|
||||
'/dev/disk/by-id/wwn-fake_wwn_3',
|
||||
'/dev/disk/by-path/pci-0000:00:0d.0-scsi-0:0:0:0'],
|
||||
'ID_SERIAL_SHORT': 'fake_serial_3',
|
||||
'ID_WWN': 'fake_wwn_3',
|
||||
'DEVPATH': '/devices/pci0000:00/0000:00:0d.0/ata4/host0/target0:0:0/'
|
||||
'0:0:0:0/block/sdc',
|
||||
'ID_MODEL': 'fake_id_model',
|
||||
'DEVNAME': '/dev/sdc',
|
||||
'MAJOR': '8',
|
||||
'DEVTYPE': 'disk', 'MINOR': '0', 'ID_BUS': 'ata'},
|
||||
'startsec': '0',
|
||||
'device': '/dev/sdc',
|
||||
'espec': {'state': 'running', 'timeout': '30', 'removable': '0'},
|
||||
'bspec': {
|
||||
'sz': '976773168', 'iomin': '4096', 'size64': '500107862016',
|
||||
'ss': '512', 'ioopt': '0', 'alignoff': '0', 'pbsz': '4096',
|
||||
'ra': '256', 'ro': '0', 'maxsect': '1024'},
|
||||
'size': 500107862016},
|
||||
]
|
||||
|
||||
|
||||
class TestNailgun(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestNailgun, self).setUp()
|
||||
self.drv = nailgun.Nailgun(PROVISION_SAMPLE_DATA)
|
||||
|
||||
def test_match_device_by_id_matches(self):
|
||||
fake_ks_disk = {
|
||||
"extra": [
|
||||
"disk/by-id/fake_scsi_matches",
|
||||
"disk/by-id/fake_ata_dont_matches"
|
||||
]
|
||||
}
|
||||
fake_hu_disk = {
|
||||
"uspec": {
|
||||
"DEVLINKS": [
|
||||
"/dev/disk/by-id/fake_scsi_matches",
|
||||
"/dev/disk/by-path/fake_path"
|
||||
]
|
||||
}
|
||||
}
|
||||
self.assertTrue(nailgun.match_device(fake_hu_disk, fake_ks_disk))
|
||||
|
||||
def test_match_device_id_matches(self):
|
||||
fake_ks_disk = {
|
||||
"extra": [
|
||||
"disk/by-id/fake_scsi_dont_matches",
|
||||
"disk/by-id/fake_ata_dont_matches"
|
||||
],
|
||||
"id": "sdd"
|
||||
}
|
||||
fake_hu_disk = {
|
||||
"uspec": {
|
||||
"DEVLINKS": [
|
||||
"/dev/disk/by-id/fake_scsi_matches",
|
||||
"/dev/disk/by-path/fake_path",
|
||||
"/dev/sdd"
|
||||
]
|
||||
}
|
||||
}
|
||||
self.assertTrue(nailgun.match_device(fake_hu_disk, fake_ks_disk))
|
||||
|
||||
def test_match_device_dont_macthes(self):
|
||||
fake_ks_disk = {
|
||||
"extra": [
|
||||
"disk/by-id/fake_scsi_dont_matches",
|
||||
"disk/by-id/fake_ata_dont_matches"
|
||||
],
|
||||
"id": "sda"
|
||||
}
|
||||
fake_hu_disk = {
|
||||
"uspec": {
|
||||
"DEVLINKS": [
|
||||
"/dev/disk/by-id/fake_scsi_matches",
|
||||
"/dev/disk/by-path/fake_path",
|
||||
"/dev/sdd"
|
||||
]
|
||||
}
|
||||
}
|
||||
self.assertFalse(nailgun.match_device(fake_hu_disk, fake_ks_disk))
|
||||
|
||||
def test_configdrive_scheme(self):
|
||||
cd_scheme = self.drv.configdrive_scheme()
|
||||
self.assertEqual('fake_auth_key', cd_scheme.common.ssh_auth_key)
|
||||
self.assertEqual('node-1.domain.tld', cd_scheme.common.hostname)
|
||||
self.assertEqual('node-1.domain.tld', cd_scheme.common.fqdn)
|
||||
self.assertEqual('node-1.domain.tld', cd_scheme.common.fqdn)
|
||||
self.assertEqual('"10.20.0.2"', cd_scheme.common.name_servers)
|
||||
self.assertEqual('"domain.tld"', cd_scheme.common.search_domain)
|
||||
self.assertEqual('10.20.0.2', cd_scheme.common.master_ip)
|
||||
self.assertEqual('http://10.20.0.2:8000/api',
|
||||
cd_scheme.common.master_url)
|
||||
self.assertEqual('08:00:27:79:da:80_eth0,08:00:27:46:43:60_eth1,'
|
||||
'08:00:27:b1:d7:15_eth2', cd_scheme.common.udevrules)
|
||||
self.assertEqual('08:00:27:79:da:80', cd_scheme.common.admin_mac)
|
||||
self.assertEqual('10.20.0.3', cd_scheme.common.admin_ip)
|
||||
self.assertEqual('255.255.255.0', cd_scheme.common.admin_mask)
|
||||
self.assertEqual('eth0', cd_scheme.common.admin_iface_name)
|
||||
self.assertEqual('America/Los_Angeles', cd_scheme.common.timezone)
|
||||
self.assertEqual('fuel.domain.tld', cd_scheme.puppet.master)
|
||||
self.assertEqual('unset', cd_scheme.mcollective.pskey)
|
||||
self.assertEqual('mcollective', cd_scheme.mcollective.vhost)
|
||||
self.assertEqual('10.20.0.2', cd_scheme.mcollective.host)
|
||||
self.assertEqual('mcollective', cd_scheme.mcollective.user)
|
||||
self.assertEqual('marionette', cd_scheme.mcollective.password)
|
||||
self.assertEqual('rabbitmq', cd_scheme.mcollective.connector)
|
||||
self.assertEqual('ubuntu', cd_scheme.profile)
|
||||
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_partition_scheme(self, mock_lbd):
|
||||
mock_lbd.return_value = LIST_BLOCK_DEVICES_SAMPLE
|
||||
p_scheme = self.drv.partition_scheme()
|
||||
self.assertEqual(5, len(p_scheme.fss))
|
||||
self.assertEqual(4, len(p_scheme.pvs))
|
||||
self.assertEqual(3, len(p_scheme.lvs))
|
||||
self.assertEqual(2, len(p_scheme.vgs))
|
||||
self.assertEqual(1, len(p_scheme.mds))
|
||||
self.assertEqual(3, len(p_scheme.parteds))
|
||||
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_image_scheme(self, mock_lbd):
|
||||
mock_lbd.return_value = LIST_BLOCK_DEVICES_SAMPLE
|
||||
p_scheme = self.drv.partition_scheme()
|
||||
i_scheme = self.drv.image_scheme(p_scheme)
|
||||
self.assertEqual(1, len(i_scheme.images))
|
||||
img = i_scheme.images[0]
|
||||
self.assertEqual('raw', img.container)
|
||||
self.assertEqual('fake_image_format', img.image_format)
|
||||
self.assertEqual('/dev/mapper/os-root', img.target_device)
|
||||
self.assertEqual('proto://fake_image_uri', img.uri)
|
||||
self.assertEqual(None, img.size)
|
||||
|
||||
def test_getlabel(self):
|
||||
self.assertEqual('', self.drv._getlabel(None))
|
||||
long_label = '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
self.assertEqual(' -L %s ' % long_label[:12],
|
||||
self.drv._getlabel(long_label))
|
||||
|
||||
@mock.patch.object(hu, 'list_block_devices')
|
||||
def test_disk_dev_not_found(self, mock_lbd):
|
||||
mock_lbd.return_value = LIST_BLOCK_DEVICES_SAMPLE
|
||||
fake_ks_disk = {
|
||||
"name": "fake",
|
||||
"extra": [
|
||||
"disk/by-id/fake_scsi_matches",
|
||||
"disk/by-id/fake_ata_dont_matches"
|
||||
]
|
||||
}
|
||||
self.assertRaises(errors.DiskNotFoundError, self.drv._disk_dev,
|
||||
fake_ks_disk)
|
250
fuel_agent/tests/test_partition.py
Normal file
250
fuel_agent/tests/test_partition.py
Normal file
@ -0,0 +1,250 @@
|
||||
# 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.objects import partition
|
||||
|
||||
|
||||
class TestMD(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestMD, self).setUp()
|
||||
self.md = partition.Md('name', 'level')
|
||||
|
||||
def test_add_device_ok(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
self.md.add_device('device')
|
||||
self.assertEqual(1, len(self.md.devices))
|
||||
self.assertEqual('device', self.md.devices[0])
|
||||
|
||||
def test_add_device_in_spares_fail(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
self.assertEqual(0, len(self.md.spares))
|
||||
self.md.add_spare('device')
|
||||
self.assertRaises(errors.MDDeviceDuplicationError, self.md.add_device,
|
||||
'device')
|
||||
|
||||
def test_add_device_in_devices_fail(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
self.assertEqual(0, len(self.md.spares))
|
||||
self.md.add_device('device')
|
||||
self.assertRaises(errors.MDDeviceDuplicationError, self.md.add_device,
|
||||
'device')
|
||||
|
||||
def test_add_spare_in_spares_fail(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
self.assertEqual(0, len(self.md.spares))
|
||||
self.md.add_spare('device')
|
||||
self.assertRaises(errors.MDDeviceDuplicationError, self.md.add_spare,
|
||||
'device')
|
||||
|
||||
def test_add_spare_in_devices_fail(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
self.assertEqual(0, len(self.md.spares))
|
||||
self.md.add_device('device')
|
||||
self.assertRaises(errors.MDDeviceDuplicationError, self.md.add_spare,
|
||||
'device')
|
||||
|
||||
|
||||
class TestPartition(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestPartition, self).setUp()
|
||||
self.pt = partition.Partition('name', 'count', 'device', 'begin',
|
||||
'end', 'partition_type')
|
||||
|
||||
def test_set_flag(self):
|
||||
self.assertEqual(0, len(self.pt.flags))
|
||||
self.pt.set_flag('fake_flag')
|
||||
self.assertEqual(1, len(self.pt.flags))
|
||||
self.assertIn('fake_flag', self.pt.flags)
|
||||
|
||||
|
||||
class TestPartitionScheme(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestPartitionScheme, self).setUp()
|
||||
self.p_scheme = partition.PartitionScheme()
|
||||
|
||||
def test_root_device_not_found(self):
|
||||
self.assertRaises(errors.WrongPartitionSchemeError,
|
||||
self.p_scheme.root_device)
|
||||
|
||||
def test_fs_by_device(self):
|
||||
expected_fs = partition.Fs('device')
|
||||
self.p_scheme.fss.append(expected_fs)
|
||||
self.p_scheme.fss.append(partition.Fs('wrong_device'))
|
||||
actual_fs = self.p_scheme.fs_by_device('device')
|
||||
self.assertEqual(expected_fs, actual_fs)
|
||||
|
||||
def test_fs_by_mount(self):
|
||||
expected_fs = partition.Fs('d', mount='mount')
|
||||
self.p_scheme.fss.append(expected_fs)
|
||||
self.p_scheme.fss.append(partition.Fs('w_d', mount='wrong_mount'))
|
||||
actual_fs = self.p_scheme.fs_by_mount('mount')
|
||||
self.assertEqual(expected_fs, actual_fs)
|
||||
|
||||
def test_pv_by_name(self):
|
||||
expected_pv = partition.Pv('pv')
|
||||
self.p_scheme.pvs.append(expected_pv)
|
||||
self.p_scheme.pvs.append(partition.Pv('wrong_pv'))
|
||||
actual_pv = self.p_scheme.pv_by_name('pv')
|
||||
self.assertEqual(expected_pv, actual_pv)
|
||||
|
||||
def test_vg_by_name(self):
|
||||
expected_vg = partition.Vg('vg')
|
||||
self.p_scheme.vgs.append(expected_vg)
|
||||
self.p_scheme.vgs.append(partition.Vg('wrong_vg'))
|
||||
actual_vg = self.p_scheme.vg_by_name('vg')
|
||||
self.assertEqual(expected_vg, actual_vg)
|
||||
|
||||
def test_vg_attach_by_name(self):
|
||||
self.p_scheme.vg_attach_by_name('pvname', 'vgname')
|
||||
self.assertEqual(1, len(self.p_scheme.pvs))
|
||||
self.assertEqual(1, len(self.p_scheme.vgs))
|
||||
self.assertIn('pvname', self.p_scheme.vgs[0].pvnames)
|
||||
self.assertIn('vgname', self.p_scheme.vgs[0].name)
|
||||
|
||||
def test_md_next_name_ok(self):
|
||||
expected_name = '/dev/md0'
|
||||
self.assertEqual(expected_name, self.p_scheme.md_next_name())
|
||||
|
||||
def test_md_next_name_fail(self):
|
||||
self.p_scheme.mds = [
|
||||
partition.Md('/dev/md%s' % x, 'level') for x in range(0, 128)]
|
||||
self.assertRaises(errors.MDAlreadyExistsError,
|
||||
self.p_scheme.md_next_name)
|
||||
|
||||
def test_md_by_name(self):
|
||||
self.assertEqual(0, len(self.p_scheme.mds))
|
||||
expected_md = partition.Md('name', 'level')
|
||||
self.p_scheme.mds.append(expected_md)
|
||||
self.p_scheme.mds.append(partition.Md('wrong_name', 'level'))
|
||||
self.assertEqual(expected_md, self.p_scheme.md_by_name('name'))
|
||||
|
||||
def test_md_by_mount(self):
|
||||
self.assertEqual(0, len(self.p_scheme.mds))
|
||||
self.assertEqual(0, len(self.p_scheme.fss))
|
||||
expected_md = partition.Md('name', 'level')
|
||||
expected_fs = partition.Fs('name', mount='mount')
|
||||
self.p_scheme.mds.append(expected_md)
|
||||
self.p_scheme.fss.append(expected_fs)
|
||||
self.p_scheme.fss.append(partition.Fs('wrong_name',
|
||||
mount='wrong_mount'))
|
||||
self.assertEqual(expected_md, self.p_scheme.md_by_mount('mount'))
|
||||
|
||||
def test_md_attach_by_mount_md_exists(self):
|
||||
self.assertEqual(0, len(self.p_scheme.mds))
|
||||
self.assertEqual(0, len(self.p_scheme.fss))
|
||||
expected_md = partition.Md('name', 'level')
|
||||
expected_fs = partition.Fs('name', mount='mount')
|
||||
self.p_scheme.mds.append(expected_md)
|
||||
self.p_scheme.fss.append(expected_fs)
|
||||
actual_md = self.p_scheme.md_attach_by_mount('device', 'mount')
|
||||
self.assertIn('device', actual_md.devices)
|
||||
self.assertEqual(expected_md, actual_md)
|
||||
|
||||
def test_md_attach_by_mount_no_md(self):
|
||||
self.assertEqual(0, len(self.p_scheme.mds))
|
||||
self.assertEqual(0, len(self.p_scheme.fss))
|
||||
actual_md = self.p_scheme.md_attach_by_mount(
|
||||
'device', 'mount', fs_type='fs_type', fs_options='-F',
|
||||
fs_label='fs_label', name='name', level='level')
|
||||
self.assertIn('device', actual_md.devices)
|
||||
self.assertEqual(1, len(self.p_scheme.fss))
|
||||
self.assertEqual('name', self.p_scheme.fss[0].device)
|
||||
self.assertEqual('mount', self.p_scheme.fss[0].mount)
|
||||
self.assertEqual('fs_type', self.p_scheme.fss[0].type)
|
||||
self.assertEqual('fs_label', self.p_scheme.fss[0].label)
|
||||
self.assertEqual('-F', self.p_scheme.fss[0].options)
|
||||
|
||||
|
||||
class TestParted(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestParted, self).setUp()
|
||||
self.prtd = partition.Parted('name', 'label')
|
||||
|
||||
@mock.patch.object(partition.Parted, 'next_count')
|
||||
@mock.patch.object(partition.Parted, 'next_type')
|
||||
def test_next_name_none(self, nt_mock, nc_mock):
|
||||
nc_mock.return_value = 1
|
||||
nt_mock.return_value = 'extended'
|
||||
self.assertEqual(None, self.prtd.next_name())
|
||||
|
||||
@mock.patch.object(partition.Parted, 'next_count')
|
||||
@mock.patch.object(partition.Parted, 'next_type')
|
||||
def test_next_name_no_separator(self, nt_mock, nc_mock):
|
||||
nc_mock.return_value = 1
|
||||
nt_mock.return_value = 'not_extended'
|
||||
expected_name = '%s%s' % (self.prtd.name, 1)
|
||||
self.assertEqual(expected_name, self.prtd.next_name())
|
||||
|
||||
@mock.patch.object(partition.Parted, 'next_count')
|
||||
@mock.patch.object(partition.Parted, 'next_type')
|
||||
def test_next_name_with_separator(self, nt_mock, nc_mock):
|
||||
nc_mock.return_value = 1
|
||||
nt_mock.return_value = 'not_extended'
|
||||
self.prtd.name = 'cciss or loop'
|
||||
expected_name = '%sp%s' % (self.prtd.name, 1)
|
||||
self.assertEqual(expected_name, self.prtd.next_name())
|
||||
|
||||
def test_next_begin_empty_partitions(self):
|
||||
self.assertEqual(0, self.prtd.next_begin())
|
||||
|
||||
def test_next_begin_last_extended_partition(self):
|
||||
self.prtd.partitions.append(
|
||||
partition.Partition('name', 'count', 'device', 'begin', 'end',
|
||||
'extended'))
|
||||
self.assertEqual('begin', self.prtd.next_begin())
|
||||
|
||||
def test_next_begin_no_last_extended_partition(self):
|
||||
self.prtd.partitions.append(
|
||||
partition.Partition('name', 'count', 'device', 'begin', 'end',
|
||||
'primary'))
|
||||
self.assertEqual('end', self.prtd.next_begin())
|
||||
|
||||
def test_next_count_no_logical(self):
|
||||
self.assertEqual(1, self.prtd.next_count('primary'))
|
||||
|
||||
def test_next_count_has_logical(self):
|
||||
self.prtd.partitions.append(
|
||||
partition.Partition('name', 'count', 'device', 'begin', 'end',
|
||||
'logical'))
|
||||
self.assertEqual(6, self.prtd.next_count('logical'))
|
||||
|
||||
def test_next_type_gpt(self):
|
||||
self.prtd.label = 'gpt'
|
||||
self.assertEqual('primary', self.prtd.next_type())
|
||||
|
||||
def test_next_type_no_extended(self):
|
||||
self.prtd.label = 'msdos'
|
||||
self.assertEqual('primary', self.prtd.next_type())
|
||||
self.prtd.partitions.extend(
|
||||
3 * [partition.Partition('name', 'count', 'device', 'begin',
|
||||
'end', 'primary')])
|
||||
self.assertEqual('extended', self.prtd.next_type())
|
||||
|
||||
def test_next_type_has_extended(self):
|
||||
self.prtd.label = 'msdos'
|
||||
self.prtd.partitions.append(
|
||||
partition.Partition('name', 'count', 'device', 'begin', 'end',
|
||||
'extended'))
|
||||
self.assertEqual('logical', self.prtd.next_type())
|
||||
|
||||
def test_primary(self):
|
||||
expected_partitions = [partition.Partition('name', 'count', 'device',
|
||||
'begin', 'end', 'primary')]
|
||||
self.prtd.partitions.extend(expected_partitions)
|
||||
self.assertEqual(expected_partitions, self.prtd.primary)
|
@ -193,3 +193,41 @@ class TestPartitionUtils(test_base.BaseTestCase):
|
||||
}
|
||||
self.assertRaises(errors.PartitionNotFoundError, pu.remove_partition,
|
||||
'/dev/fake', 3)
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_set_gpt_type(self, mock_exec):
|
||||
pu.set_gpt_type('dev', 'num', 'type')
|
||||
mock_exec.assert_called_once_with('sgdisk',
|
||||
'--typecode=%s:%s' % ('num', 'type'),
|
||||
'dev', check_exit_code=[0])
|
||||
|
||||
@mock.patch.object(utils, 'execute')
|
||||
def test_info(self, mock_exec):
|
||||
mock_exec.return_value = [
|
||||
'BYT;\n'
|
||||
'/dev/fake:476940MiB:scsi:512:4096:msdos:ATA 1BD14;\n'
|
||||
'1:0.03MiB:1.00MiB:0.97MiB:free;\n'
|
||||
'1:1.00MiB:191MiB:190MiB:ext3::boot;\n'
|
||||
'2:191MiB:476939MiB:476748MiB:::lvm;\n'
|
||||
'1:476939MiB:476940MiB:1.02MiB:free;\n'
|
||||
]
|
||||
expected = {'generic': {'dev': '/dev/fake',
|
||||
'logical_block': 512,
|
||||
'model': 'ATA 1BD14',
|
||||
'physical_block': 4096,
|
||||
'size': 476940,
|
||||
'table': 'msdos'},
|
||||
|
||||
'parts': [{'begin': 1, 'end': 1, 'fstype': 'free',
|
||||
'num': 1, 'size': 1},
|
||||
{'begin': 1, 'end': 191, 'fstype': 'ext3',
|
||||
'num': 1, 'size': 190},
|
||||
{'begin': 191, 'end': 476939, 'fstype': None,
|
||||
'num': 2, 'size': 476748},
|
||||
{'begin': 476939, 'end': 476940,
|
||||
'fstype': 'free', 'num': 1, 'size': 2}]}
|
||||
actual = pu.info('/dev/fake')
|
||||
self.assertEqual(expected, actual)
|
||||
mock_exec.assert_called_once_with('parted', '-s', '/dev/fake', '-m',
|
||||
'unit', 'MiB', 'print', 'free',
|
||||
check_exit_code=[0, 1])
|
||||
|
@ -17,6 +17,10 @@ import os
|
||||
import tempfile
|
||||
import testtools
|
||||
|
||||
import mock
|
||||
import stevedore
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.openstack.common import processutils
|
||||
from fuel_agent.utils import utils
|
||||
|
||||
@ -24,6 +28,13 @@ from fuel_agent.utils import utils
|
||||
class ExecuteTestCase(testtools.TestCase):
|
||||
"""This class is partly based on the same class in openstack/ironic."""
|
||||
|
||||
def setUp(self):
|
||||
super(ExecuteTestCase, self).setUp()
|
||||
fake_driver = stevedore.extension.Extension('fake_driver', None, None,
|
||||
'fake_obj')
|
||||
self.drv_manager = stevedore.driver.DriverManager.make_test_instance(
|
||||
fake_driver)
|
||||
|
||||
def test_parse_unit(self):
|
||||
self.assertEqual(utils.parse_unit('1.00m', 'm', ceil=True), 1)
|
||||
self.assertEqual(utils.parse_unit('1.00m', 'm', ceil=False), 1)
|
||||
@ -120,3 +131,28 @@ grep foo
|
||||
finally:
|
||||
os.unlink(tmpfilename)
|
||||
os.unlink(tmpfilename2)
|
||||
|
||||
@mock.patch('stevedore.driver.DriverManager')
|
||||
def test_get_driver(self, mock_drv_manager):
|
||||
mock_drv_manager.return_value = self.drv_manager
|
||||
self.assertEqual('fake_obj', utils.get_driver('fake_driver'))
|
||||
|
||||
@mock.patch('jinja2.Environment')
|
||||
@mock.patch('jinja2.FileSystemLoader')
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_render_and_save_fail(self, mock_open, mock_j_lo, mock_j_env):
|
||||
mock_open.side_effect = Exception('foo')
|
||||
self.assertRaises(errors.TemplateWriteError, utils.render_and_save,
|
||||
'fake_dir', 'fake_tmpl_name', 'fake_data',
|
||||
'fake_file_name')
|
||||
|
||||
@mock.patch('jinja2.Environment')
|
||||
@mock.patch('jinja2.FileSystemLoader')
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_render_and_save_ok(self, mock_open, mock_j_lo, mock_j_env):
|
||||
mock_render = mock.Mock()
|
||||
mock_render.render.return_value = 'fake_data'
|
||||
mock_j_env.get_template.return_value = mock_render
|
||||
utils.render_and_save('fake_dir', 'fake_tmpl_name', 'fake_data',
|
||||
'fake_file_name')
|
||||
mock_open.assert_called_once_with('fake_file_name', 'w')
|
||||
|
@ -136,7 +136,7 @@ def vgreduce(vgname, pvname, *args):
|
||||
# check if vg exists
|
||||
if not filter(lambda x: x['name'] == vgname, vgdisplay()):
|
||||
raise errors.VGNotFoundError(
|
||||
'Error while extending vg: vg %s not found' % vgname)
|
||||
'Error while reducing vg: vg %s not found' % vgname)
|
||||
pvnames = [pvname] + list(args)
|
||||
# check if all necessary pv are attached to vg
|
||||
if not set(pvnames).issubset(
|
||||
@ -151,7 +151,7 @@ def vgremove(vgname):
|
||||
# check if vg exists
|
||||
if not filter(lambda x: x['name'] == vgname, vgdisplay()):
|
||||
raise errors.VGNotFoundError(
|
||||
'Error while extending vg: vg %s not found' % vgname)
|
||||
'Error while removing vg: vg %s not found' % vgname)
|
||||
utils.execute('vgremove', '-f', vgname, check_exit_code=[0])
|
||||
|
||||
|
||||
@ -161,7 +161,9 @@ def lvdisplay():
|
||||
'-C',
|
||||
'--noheading',
|
||||
'--units', 'm',
|
||||
'--options', 'lv_name,lv_size,vg_name,lv_uuid,lv_path',
|
||||
#NOTE(agordeev): lv_path had been removed from options
|
||||
# since versions of lvdisplay prior 2.02.68 don't have it.
|
||||
'--options', 'lv_name,lv_size,vg_name,lv_uuid',
|
||||
'--separator', ';',
|
||||
check_exit_code=[0])
|
||||
|
||||
@ -176,7 +178,8 @@ def lvdisplay():
|
||||
'size': utils.parse_unit(lv_params[1], 'm'),
|
||||
'vg': lv_params[2],
|
||||
'uuid': lv_params[3],
|
||||
'path': lv_params[4]
|
||||
#NOTE(agordeev): simulate lv_path with '/dev/$vg_name/$lv_name'
|
||||
'path': '/dev/%s/%s' % (lv_params[2], lv_params[0])
|
||||
})
|
||||
LOG.debug('Found logical volumes: {0}'.format(lvs))
|
||||
return lvs
|
||||
@ -188,7 +191,7 @@ def lvcreate(vgname, lvname, size):
|
||||
# check if vg exists
|
||||
if not vg:
|
||||
raise errors.VGNotFoundError(
|
||||
'Error while extending vg: vg %s not found' % vgname)
|
||||
'Error while creating vg: vg %s not found' % vgname)
|
||||
# check if enough space is available
|
||||
if vg[0]['free'] < size:
|
||||
raise errors.NotEnoughSpaceError(
|
||||
|
@ -18,6 +18,7 @@ import math
|
||||
import jinja2
|
||||
import stevedore.driver
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.openstack.common import gettextutils as gtu
|
||||
from fuel_agent.openstack.common import log as logging
|
||||
from fuel_agent.openstack.common import processutils
|
||||
@ -67,5 +68,6 @@ def render_and_save(tmpl_dir, tmpl_name, tmpl_data, file_name):
|
||||
with open(file_name, 'w') as f:
|
||||
f.write(output)
|
||||
except Exception:
|
||||
raise Exception('Something goes wrong while trying to save'
|
||||
raise errors.TemplateWriteError(
|
||||
'Something goes wrong while trying to save'
|
||||
'templated data to {0}'.format(file_name))
|
||||
|
Loading…
x
Reference in New Issue
Block a user