Merge "Add simple data driver for partitioning info"
This commit is contained in:
commit
180dda07a2
|
@ -28,3 +28,23 @@ class BaseDataDriver(object):
|
|||
|
||||
def __init__(self, data):
|
||||
self.data = copy.deepcopy(data)
|
||||
|
||||
@abc.abstractproperty
|
||||
def partition_scheme(self):
|
||||
"""Retruns instance of PartionScheme object"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def image_scheme(self):
|
||||
"""Returns instance of ImageScheme object"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def grub(self):
|
||||
"""Returns instance of Grub object"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def operating_system(self):
|
||||
"""Returns instance of OperatingSystem object"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def configdrive_scheme(self):
|
||||
"""Returns instance of ConfigDriveScheme object"""
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
import itertools
|
||||
import math
|
||||
import os
|
||||
import six
|
||||
import yaml
|
||||
|
||||
import six
|
||||
from six.moves.urllib.parse import urljoin
|
||||
from six.moves.urllib.parse import urlparse
|
||||
from six.moves.urllib.parse import urlsplit
|
||||
import yaml
|
||||
|
||||
from fuel_agent.drivers.base import BaseDataDriver
|
||||
from fuel_agent.drivers import ks_spaces_validator
|
||||
|
@ -67,6 +67,8 @@ def match_device(hu_disk, ks_disk):
|
|||
|
||||
|
||||
class Nailgun(BaseDataDriver):
|
||||
"""Driver for parsing regular volumes metadata from Nailgun."""
|
||||
|
||||
def __init__(self, data):
|
||||
super(Nailgun, self).__init__(data)
|
||||
|
||||
|
@ -79,11 +81,31 @@ class Nailgun(BaseDataDriver):
|
|||
# get rid of md over all disks for /boot partition.
|
||||
self._boot_done = False
|
||||
|
||||
self.partition_scheme = self.parse_partition_scheme()
|
||||
self.grub = self.parse_grub()
|
||||
self.configdrive_scheme = self.parse_configdrive_scheme()
|
||||
self._partition_scheme = self.parse_partition_scheme()
|
||||
self._grub = self.parse_grub()
|
||||
self._configdrive_scheme = self.parse_configdrive_scheme()
|
||||
# parsing image scheme needs partition scheme has been parsed
|
||||
self.image_scheme = self.parse_image_scheme()
|
||||
self._image_scheme = self.parse_image_scheme()
|
||||
|
||||
@property
|
||||
def partition_scheme(self):
|
||||
return self._partition_scheme
|
||||
|
||||
@property
|
||||
def image_scheme(self):
|
||||
return self._image_scheme
|
||||
|
||||
@property
|
||||
def grub(self):
|
||||
return self._grub
|
||||
|
||||
@property
|
||||
def operating_system(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def configdrive_scheme(self):
|
||||
return self._configdrive_scheme
|
||||
|
||||
def partition_data(self):
|
||||
return self.data['ks_meta']['pm_data']['ks_spaces']
|
||||
|
@ -346,7 +368,7 @@ class Nailgun(BaseDataDriver):
|
|||
for volume in vg['volumes']:
|
||||
LOG.debug('Processing lv %s' % volume['name'])
|
||||
if volume['size'] <= 0:
|
||||
LOG.debug('Lv size is zero. Skipping.')
|
||||
LOG.debug('LogicalVolume size is zero. Skipping.')
|
||||
continue
|
||||
|
||||
if volume['type'] == 'lv':
|
||||
|
@ -543,8 +565,31 @@ class NailgunBuildImage(BaseDataDriver):
|
|||
|
||||
def __init__(self, data):
|
||||
super(NailgunBuildImage, self).__init__(data)
|
||||
self._image_scheme = objects.ImageScheme()
|
||||
self._partition_scheme = objects.PartitionScheme()
|
||||
|
||||
self.parse_schemes()
|
||||
self.parse_operating_system()
|
||||
self._operating_system = self.parse_operating_system()
|
||||
|
||||
@property
|
||||
def partition_scheme(self):
|
||||
return self._partition_scheme
|
||||
|
||||
@property
|
||||
def image_scheme(self):
|
||||
return self._image_scheme
|
||||
|
||||
@property
|
||||
def grub(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def operating_system(self):
|
||||
return self._operating_system
|
||||
|
||||
@property
|
||||
def configdrive_scheme(self):
|
||||
return None
|
||||
|
||||
def parse_operating_system(self):
|
||||
if self.data.get('codename').lower() != 'trusty':
|
||||
|
@ -563,11 +608,9 @@ class NailgunBuildImage(BaseDataDriver):
|
|||
section=repo['section'],
|
||||
priority=repo['priority']))
|
||||
|
||||
self.operating_system = objects.Ubuntu(repos=repos, packages=packages)
|
||||
return objects.Ubuntu(repos=repos, packages=packages)
|
||||
|
||||
def parse_schemes(self):
|
||||
self.image_scheme = objects.ImageScheme()
|
||||
self.partition_scheme = objects.PartitionScheme()
|
||||
|
||||
for mount, image in six.iteritems(self.data['image_data']):
|
||||
filename = os.path.basename(urlsplit(image['uri']).path)
|
||||
|
@ -575,13 +618,13 @@ class NailgunBuildImage(BaseDataDriver):
|
|||
# during initialization.
|
||||
device = objects.Loop()
|
||||
|
||||
self.image_scheme.add_image(
|
||||
self._image_scheme.add_image(
|
||||
uri='file://' + os.path.join(self.data['output'], filename),
|
||||
format=image['format'],
|
||||
container=image['container'],
|
||||
target_device=device)
|
||||
|
||||
self.partition_scheme.add_fs(
|
||||
self._partition_scheme.add_fs(
|
||||
device=device,
|
||||
mount=mount,
|
||||
fs_type=image['format'])
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 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 fuel_agent.drivers import nailgun
|
||||
from fuel_agent import objects
|
||||
|
||||
|
||||
class NailgunSimpleDriver(nailgun.Nailgun):
|
||||
"""Simple driver that do not make any computations.
|
||||
|
||||
This driver digest information that already has all required
|
||||
information how to perform partitioning.
|
||||
Service that sends data to fuel_agent is responsible for preparing
|
||||
it in correct format.
|
||||
"""
|
||||
|
||||
@property
|
||||
def partition_data(self):
|
||||
return self.data.get('partitioning', {})
|
||||
|
||||
@classmethod
|
||||
def parse_lv_data(cls, raw_lvs):
|
||||
return [objects.LV.from_dict(lv) for lv in raw_lvs]
|
||||
|
||||
@classmethod
|
||||
def parse_pv_data(cls, raw_pvs):
|
||||
return [objects.PV.from_dict(pv) for pv in raw_pvs]
|
||||
|
||||
@classmethod
|
||||
def parse_fs_data(cls, raw_fss):
|
||||
return [objects.FS.from_dict(fs) for fs in raw_fss]
|
||||
|
||||
@classmethod
|
||||
def parse_vg_data(cls, raw_vgs):
|
||||
return [objects.VG.from_dict(vg) for vg in raw_vgs]
|
||||
|
||||
@classmethod
|
||||
def parse_md_data(cls, raw_mds):
|
||||
return [objects.MD.from_dict(md) for md in raw_mds]
|
||||
|
||||
@classmethod
|
||||
def parse_parted_data(cls, raw_parteds):
|
||||
return [objects.Parted.from_dict(parted) for parted in raw_parteds]
|
||||
|
||||
def parse_partition_scheme(self):
|
||||
partition_scheme = objects.PartitionScheme()
|
||||
|
||||
for obj in ('lv', 'pv', 'fs', 'vg', 'md', 'parted'):
|
||||
attr = '{0}s'.format(obj)
|
||||
parse_method = getattr(self, 'parse_{0}_data'.format(obj))
|
||||
raw = self.partition_data.get(attr, {})
|
||||
setattr(partition_scheme, attr, parse_method(raw))
|
||||
|
||||
return partition_scheme
|
|
@ -22,18 +22,19 @@ from fuel_agent.objects.image import Image
|
|||
from fuel_agent.objects.image import ImageScheme
|
||||
from fuel_agent.objects.operating_system import OperatingSystem
|
||||
from fuel_agent.objects.operating_system import Ubuntu
|
||||
from fuel_agent.objects.partition import Fs
|
||||
from fuel_agent.objects.partition import Lv
|
||||
from fuel_agent.objects.partition import Md
|
||||
from fuel_agent.objects.partition import FS
|
||||
from fuel_agent.objects.partition import LV
|
||||
from fuel_agent.objects.partition import MD
|
||||
from fuel_agent.objects.partition import Parted
|
||||
from fuel_agent.objects.partition import Partition
|
||||
from fuel_agent.objects.partition import PartitionScheme
|
||||
from fuel_agent.objects.partition import Pv
|
||||
from fuel_agent.objects.partition import Vg
|
||||
from fuel_agent.objects.partition import PV
|
||||
from fuel_agent.objects.partition import VG
|
||||
from fuel_agent.objects.repo import DEBRepo
|
||||
from fuel_agent.objects.repo import Repo
|
||||
|
||||
__all__ = [
|
||||
'Partition', 'Pv', 'Vg', 'Lv', 'Md', 'Fs', 'PartitionScheme',
|
||||
'Partition', 'Parted', 'PV', 'VG', 'LV', 'MD', 'FS', 'PartitionScheme',
|
||||
'ConfigDriveCommon', 'ConfigDrivePuppet', 'ConfigDriveMcollective',
|
||||
'ConfigDriveScheme', 'Image', 'ImageScheme', 'Grub',
|
||||
'OperatingSystem', 'Ubuntu',
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 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 abc
|
||||
import six
|
||||
|
||||
from fuel_agent.utils.decorators import abstractclassmethod
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Serializable(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def to_dict(self):
|
||||
pass
|
||||
|
||||
@abstractclassmethod
|
||||
def from_dict(cls, data):
|
||||
pass
|
|
@ -12,20 +12,23 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import os
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.objects import base
|
||||
from fuel_agent.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Parted(object):
|
||||
def __init__(self, name, label):
|
||||
class Parted(base.Serializable):
|
||||
|
||||
def __init__(self, name, label, partitions=None, install_bootloader=False):
|
||||
self.name = name
|
||||
self.label = label
|
||||
self.partitions = []
|
||||
self.install_bootloader = False
|
||||
self.partitions = partitions or []
|
||||
self.install_bootloader = install_bootloader
|
||||
|
||||
def add_partition(self, **kwargs):
|
||||
# TODO(kozhukalov): validate before appending
|
||||
|
@ -99,14 +102,31 @@ class Parted(object):
|
|||
separator = 'p'
|
||||
return '%s%s%s' % (self.name, separator, self.next_count())
|
||||
|
||||
def to_dict(self):
|
||||
partitions = [partition.to_dict() for partition in self.partitions]
|
||||
return {
|
||||
'name': self.name,
|
||||
'label': self.label,
|
||||
'partitions': partitions,
|
||||
'install_bootloader': self.install_bootloader,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
data = copy.deepcopy(data)
|
||||
raw_partitions = data.pop('partitions')
|
||||
partitions = [Partition.from_dict(partition)
|
||||
for partition in raw_partitions]
|
||||
return cls(partitions=partitions, **data)
|
||||
|
||||
|
||||
class Partition(base.Serializable):
|
||||
|
||||
class Partition(object):
|
||||
def __init__(self, name, count, device, begin, end, partition_type,
|
||||
flags=None, guid=None, configdrive=False):
|
||||
self.name = name
|
||||
self.count = count
|
||||
self.device = device
|
||||
self.name = name
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
self.type = partition_type
|
||||
|
@ -121,15 +141,48 @@ class Partition(object):
|
|||
def set_guid(self, guid):
|
||||
self.guid = guid
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'name': self.name,
|
||||
'count': self.count,
|
||||
'device': self.device,
|
||||
'begin': self.begin,
|
||||
'end': self.end,
|
||||
'partition_type': self.type,
|
||||
'flags': self.flags,
|
||||
'guid': self.guid,
|
||||
'configdrive': self.configdrive,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
class PhysicalVolume(base.Serializable):
|
||||
|
||||
class Pv(object):
|
||||
def __init__(self, name, metadatasize=16, metadatacopies=2):
|
||||
self.name = name
|
||||
self.metadatasize = metadatasize
|
||||
self.metadatacopies = metadatacopies
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'name': self.name,
|
||||
'metadatasize': self.metadatasize,
|
||||
'metadatacopies': self.metadatacopies,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
PV = PhysicalVolume
|
||||
|
||||
|
||||
class VolumeGroup(base.Serializable):
|
||||
|
||||
class Vg(object):
|
||||
def __init__(self, name, pvnames=None):
|
||||
self.name = name
|
||||
self.pvnames = pvnames or []
|
||||
|
@ -138,8 +191,22 @@ class Vg(object):
|
|||
if pvname not in self.pvnames:
|
||||
self.pvnames.append(pvname)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'name': self.name,
|
||||
'pvnames': self.pvnames
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
VG = VolumeGroup
|
||||
|
||||
|
||||
class LogicalVolume(base.Serializable):
|
||||
|
||||
class Lv(object):
|
||||
def __init__(self, name, vgname, size):
|
||||
self.name = name
|
||||
self.vgname = vgname
|
||||
|
@ -150,8 +217,23 @@ class Lv(object):
|
|||
return '/dev/mapper/%s-%s' % (self.vgname.replace('-', '--'),
|
||||
self.name.replace('-', '--'))
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'name': self.name,
|
||||
'vgname': self.vgname,
|
||||
'size': self.size,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
LV = LogicalVolume
|
||||
|
||||
|
||||
class MultipleDevice(base.Serializable):
|
||||
|
||||
class Md(object):
|
||||
def __init__(self, name, level,
|
||||
devices=None, spares=None):
|
||||
self.name = name
|
||||
|
@ -173,8 +255,24 @@ class Md(object):
|
|||
'device %s is already attached' % device)
|
||||
self.spares.append(device)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'name': self.name,
|
||||
'level': self.level,
|
||||
'devices': self.devices,
|
||||
'spares': self.spares,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
MD = MultipleDevice
|
||||
|
||||
|
||||
class FileSystem(base.Serializable):
|
||||
|
||||
class Fs(object):
|
||||
def __init__(self, device, mount=None,
|
||||
fs_type=None, fs_options=None, fs_label=None):
|
||||
self.device = device
|
||||
|
@ -183,6 +281,22 @@ class Fs(object):
|
|||
self.options = fs_options or ''
|
||||
self.label = fs_label or ''
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'device': self.device,
|
||||
'mount': self.mount,
|
||||
'fs_type': self.type,
|
||||
'fs_options': self.options,
|
||||
'fs_label': self.label,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
FS = FileSystem
|
||||
|
||||
|
||||
class PartitionScheme(object):
|
||||
def __init__(self):
|
||||
|
@ -199,22 +313,22 @@ class PartitionScheme(object):
|
|||
return parted
|
||||
|
||||
def add_pv(self, **kwargs):
|
||||
pv = Pv(**kwargs)
|
||||
pv = PV(**kwargs)
|
||||
self.pvs.append(pv)
|
||||
return pv
|
||||
|
||||
def add_vg(self, **kwargs):
|
||||
vg = Vg(**kwargs)
|
||||
vg = VG(**kwargs)
|
||||
self.vgs.append(vg)
|
||||
return vg
|
||||
|
||||
def add_lv(self, **kwargs):
|
||||
lv = Lv(**kwargs)
|
||||
lv = LV(**kwargs)
|
||||
self.lvs.append(lv)
|
||||
return lv
|
||||
|
||||
def add_fs(self, **kwargs):
|
||||
fs = Fs(**kwargs)
|
||||
fs = FS(**kwargs)
|
||||
self.fss.append(fs)
|
||||
return fs
|
||||
|
||||
|
@ -222,7 +336,7 @@ class PartitionScheme(object):
|
|||
mdkwargs = {}
|
||||
mdkwargs['name'] = kwargs.get('name') or self.md_next_name()
|
||||
mdkwargs['level'] = kwargs.get('level') or 'mirror'
|
||||
md = Md(**mdkwargs)
|
||||
md = MD(**mdkwargs)
|
||||
self.mds.append(md)
|
||||
return md
|
||||
|
||||
|
@ -357,3 +471,13 @@ class PartitionScheme(object):
|
|||
for prt in parted.partitions:
|
||||
if prt.configdrive:
|
||||
return prt.name
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'parteds': [parted.to_dict() for parted in self.parteds],
|
||||
'mds': [md.to_dict() for md in self.mds],
|
||||
'pvs': [pv.to_dict() for pv in self.pvs],
|
||||
'vgs': [vg.to_dict() for vg in self.vgs],
|
||||
'lvs': [lv.to_dict() for lv in self.lvs],
|
||||
'fss': [fs.to_dict() for fs in self.fss],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 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 json
|
||||
import os
|
||||
|
||||
|
||||
FIXTURE_PATH = os.path.join(os.path.dirname(__file__), 'fixtures')
|
||||
|
||||
|
||||
def load_fixture(filename):
|
||||
path = os.path.join(FIXTURE_PATH, filename)
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
|
@ -0,0 +1,326 @@
|
|||
{
|
||||
"hostname": "node-1.domain.tld",
|
||||
"interfaces": {
|
||||
"eth0": {
|
||||
"dns_name": "node-1.domain.tld",
|
||||
"ip_address": "10.20.0.3",
|
||||
"mac_address": "08:00:27:79:da:80",
|
||||
"netmask": "255.255.255.0",
|
||||
"static": "0"
|
||||
},
|
||||
"eth1": {
|
||||
"mac_address": "08:00:27:46:43:60",
|
||||
"static": "0"
|
||||
},
|
||||
"eth2": {
|
||||
"mac_address": "08:00:27:b1:d7:15",
|
||||
"static": "0"
|
||||
}
|
||||
},
|
||||
"interfaces_extra": {
|
||||
"eth0": {
|
||||
"onboot": "yes",
|
||||
"peerdns": "no"
|
||||
},
|
||||
"eth1": {
|
||||
"onboot": "no",
|
||||
"peerdns": "no"
|
||||
},
|
||||
"eth2": {
|
||||
"onboot": "no",
|
||||
"peerdns": "no"
|
||||
}
|
||||
},
|
||||
"kernel_options": {
|
||||
"netcfg/choose_interface": "08:00:27:79:da:80",
|
||||
"udevrules": "08:00:27:79:da:80_eth0,08:00:27:46:43:60_eth1,08:00:27:b1:d7:15_eth2"
|
||||
},
|
||||
"ks_meta": {
|
||||
"auth_key": "fake_auth_key",
|
||||
"authorized_keys": [
|
||||
"fake_authorized_key1",
|
||||
"fake_authorized_key2"
|
||||
],
|
||||
"fuel_version": "5.0.1",
|
||||
"gw": "10.20.0.1",
|
||||
"image_data": {
|
||||
"/": {
|
||||
"container": "gzip",
|
||||
"format": "ext4",
|
||||
"uri": "http://fake.host.org:123/imgs/fake_image.img.gz"
|
||||
}
|
||||
},
|
||||
"install_log_2_syslog": 1,
|
||||
"master_ip": "10.20.0.2",
|
||||
"mco_auto_setup": 1,
|
||||
"mco_connector": "rabbitmq",
|
||||
"mco_enable": 1,
|
||||
"mco_host": "10.20.0.2",
|
||||
"mco_password": "marionette",
|
||||
"mco_pskey": "unset",
|
||||
"mco_user": "mcollective",
|
||||
"mco_vhost": "mcollective",
|
||||
"pm_data": {
|
||||
"kernel_params": "console=ttyS0,9600 console=tty0 rootdelay=90 nomodeset",
|
||||
"ks_spaces": []
|
||||
},
|
||||
"puppet_auto_setup": 1,
|
||||
"puppet_enable": 0,
|
||||
"puppet_master": "fuel.domain.tld",
|
||||
"repo_setup": {
|
||||
"repos": [
|
||||
{
|
||||
"name": "repo1",
|
||||
"priority": 1001,
|
||||
"section": "section",
|
||||
"suite": "suite",
|
||||
"type": "deb",
|
||||
"uri": "uri1"
|
||||
},
|
||||
{
|
||||
"name": "repo2",
|
||||
"priority": 1001,
|
||||
"section": "section",
|
||||
"suite": "suite",
|
||||
"type": "deb",
|
||||
"uri": "uri2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"timezone": "America/Los_Angeles"
|
||||
},
|
||||
"name": "node-1",
|
||||
"name_servers": "\"10.20.0.2\"",
|
||||
"name_servers_search": "\"domain.tld\"",
|
||||
"netboot_enabled": "1",
|
||||
"power_address": "10.20.0.253",
|
||||
"power_pass": "/root/.ssh/bootstrap.rsa",
|
||||
"power_type": "ssh",
|
||||
"power_user": "root",
|
||||
"profile": "pro_fi-le",
|
||||
"slave_name": "node-1",
|
||||
"uid": "1",
|
||||
"partitioning": {
|
||||
"fss": [
|
||||
{
|
||||
"device": "/dev/sda3",
|
||||
"fs_label": "",
|
||||
"fs_options": "",
|
||||
"fs_type": "ext2",
|
||||
"mount": "/boot"
|
||||
},
|
||||
{
|
||||
"device": "/dev/sda4",
|
||||
"fs_label": "",
|
||||
"fs_options": "",
|
||||
"fs_type": "ext2",
|
||||
"mount": "/tmp"
|
||||
},
|
||||
{
|
||||
"device": "/dev/mapper/os-root",
|
||||
"fs_label": "",
|
||||
"fs_options": "",
|
||||
"fs_type": "ext4",
|
||||
"mount": "/"
|
||||
},
|
||||
{
|
||||
"device": "/dev/mapper/os-swap",
|
||||
"fs_label": "",
|
||||
"fs_options": "",
|
||||
"fs_type": "swap",
|
||||
"mount": "swap"
|
||||
},
|
||||
{
|
||||
"device": "/dev/mapper/image-glance",
|
||||
"fs_label": "",
|
||||
"fs_options": "",
|
||||
"fs_type": "xfs",
|
||||
"mount": "/var/lib/glance"
|
||||
}
|
||||
],
|
||||
"lvs": [
|
||||
{
|
||||
"name": "root",
|
||||
"size": 15360,
|
||||
"vgname": "os"
|
||||
},
|
||||
{
|
||||
"name": "swap",
|
||||
"size": 4014,
|
||||
"vgname": "os"
|
||||
},
|
||||
{
|
||||
"name": "glance",
|
||||
"size": 175347,
|
||||
"vgname": "image"
|
||||
}
|
||||
],
|
||||
"mds": [],
|
||||
"parteds": [
|
||||
{
|
||||
"label": "gpt",
|
||||
"name": "/dev/sdb",
|
||||
"partitions": [
|
||||
{
|
||||
"begin": 1,
|
||||
"configdrive": false,
|
||||
"count": 1,
|
||||
"device": "/dev/sdb",
|
||||
"end": 25,
|
||||
"flags": [
|
||||
"bios_grub"
|
||||
],
|
||||
"guid": null,
|
||||
"name": "/dev/sdb1",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 25,
|
||||
"configdrive": false,
|
||||
"count": 2,
|
||||
"device": "/dev/sdb",
|
||||
"end": 225,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sdb2",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 225,
|
||||
"configdrive": false,
|
||||
"count": 3,
|
||||
"device": "/dev/sdb",
|
||||
"end": 65196,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sdb3",
|
||||
"partition_type": "primary"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "gpt",
|
||||
"name": "/dev/sda",
|
||||
"partitions": [
|
||||
{
|
||||
"begin": 1,
|
||||
"configdrive": false,
|
||||
"count": 1,
|
||||
"device": "/dev/sda",
|
||||
"end": 25,
|
||||
"flags": [
|
||||
"bios_grub"
|
||||
],
|
||||
"guid": null,
|
||||
"name": "/dev/sda1",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 25,
|
||||
"configdrive": false,
|
||||
"count": 2,
|
||||
"device": "/dev/sda",
|
||||
"end": 225,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sda2",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 225,
|
||||
"configdrive": false,
|
||||
"count": 3,
|
||||
"device": "/dev/sda",
|
||||
"end": 425,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sda3",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 425,
|
||||
"configdrive": false,
|
||||
"count": 4,
|
||||
"device": "/dev/sda",
|
||||
"end": 625,
|
||||
"flags": [],
|
||||
"guid": "fake_guid",
|
||||
"name": "/dev/sda4",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 625,
|
||||
"configdrive": false,
|
||||
"count": 5,
|
||||
"device": "/dev/sda",
|
||||
"end": 20063,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sda5",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 20063,
|
||||
"configdrive": false,
|
||||
"count": 6,
|
||||
"device": "/dev/sda",
|
||||
"end": 65660,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sda6",
|
||||
"partition_type": "primary"
|
||||
},
|
||||
{
|
||||
"begin": 65660,
|
||||
"configdrive": true,
|
||||
"count": 7,
|
||||
"device": "/dev/sda",
|
||||
"end": 65680,
|
||||
"flags": [],
|
||||
"guid": null,
|
||||
"name": "/dev/sda7",
|
||||
"partition_type": "primary"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"pvs": [
|
||||
{
|
||||
"metadatacopies": 2,
|
||||
"metadatasize": 28,
|
||||
"name": "/dev/sda5"
|
||||
},
|
||||
{
|
||||
"metadatacopies": 2,
|
||||
"metadatasize": 28,
|
||||
"name": "/dev/sda6"
|
||||
},
|
||||
{
|
||||
"metadatacopies": 2,
|
||||
"metadatasize": 28,
|
||||
"name": "/dev/sdb3"
|
||||
},
|
||||
{
|
||||
"metadatacopies": 2,
|
||||
"metadatasize": 28,
|
||||
"name": "/dev/sdc3"
|
||||
}
|
||||
],
|
||||
"vgs": [
|
||||
{
|
||||
"name": "image",
|
||||
"pvnames": [
|
||||
"/dev/sda6",
|
||||
"/dev/sdb3",
|
||||
"/dev/sdc3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "os",
|
||||
"pvnames": [
|
||||
"/dev/sda5"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import signal
|
|||
from oslo.config import cfg
|
||||
from oslotest import base as test_base
|
||||
|
||||
from fuel_agent.drivers import nailgun
|
||||
from fuel_agent import errors
|
||||
from fuel_agent import manager
|
||||
from fuel_agent import objects
|
||||
|
@ -438,7 +439,7 @@ class TestManager(test_base.BaseTestCase):
|
|||
mock_fu):
|
||||
mock_os.path.islink.return_value = True
|
||||
mock_utils.execute.return_value = (None, None)
|
||||
self.mgr.driver.partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver._partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.mount_target('fake_chroot')
|
||||
mock_open.assert_called_once_with('fake_chroot/etc/mtab', 'wb')
|
||||
mock_os.path.islink.assert_called_once_with('fake_chroot/etc/mtab')
|
||||
|
@ -451,7 +452,7 @@ class TestManager(test_base.BaseTestCase):
|
|||
@mock.patch('fuel_agent.manager.os', create=True)
|
||||
def test_mount_target(self, mock_os, mock_open, mock_utils, mock_fu):
|
||||
mock_os.path.islink.return_value = False
|
||||
self.mgr.driver.partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver._partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
device='fake', mount='/var/lib', fs_type='xfs')
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
|
@ -500,7 +501,7 @@ none /run/shm tmpfs rw,nosuid,nodev 0 0"""
|
|||
|
||||
@mock.patch('fuel_agent.manager.fu', create=True)
|
||||
def test_umount_target(self, mock_fu):
|
||||
self.mgr.driver.partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver._partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
device='fake', mount='/var/lib', fs_type='xfs')
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
|
@ -521,6 +522,38 @@ none /run/shm tmpfs rw,nosuid,nodev 0 0"""
|
|||
mock.call('fake_chroot/')],
|
||||
mock_fu.umount_fs.call_args_list)
|
||||
|
||||
|
||||
class TestImageBuild(test_base.BaseTestCase):
|
||||
|
||||
@mock.patch('yaml.load')
|
||||
@mock.patch.object(utils, 'init_http_request')
|
||||
@mock.patch.object(utils, 'get_driver')
|
||||
def setUp(self, mock_driver, mock_http, mock_yaml):
|
||||
super(self.__class__, self).setUp()
|
||||
mock_driver.return_value = nailgun.NailgunBuildImage
|
||||
image_conf = {
|
||||
"image_data": {
|
||||
"/": {
|
||||
"container": "gzip",
|
||||
"format": "ext4",
|
||||
"uri": "http:///centos_65_x86_64.img.gz",
|
||||
},
|
||||
},
|
||||
"output": "/var/www/nailgun/targetimages",
|
||||
"repos": [
|
||||
{
|
||||
"name": "repo",
|
||||
"uri": "http://some",
|
||||
'type': 'deb',
|
||||
'suite': '/',
|
||||
'section': '',
|
||||
'priority': 1001
|
||||
}
|
||||
],
|
||||
"codename": "trusty"
|
||||
}
|
||||
self.mgr = manager.Manager(image_conf)
|
||||
|
||||
@mock.patch('fuel_agent.manager.bu', create=True)
|
||||
@mock.patch('fuel_agent.manager.fu', create=True)
|
||||
@mock.patch('fuel_agent.manager.utils', create=True)
|
||||
|
@ -539,17 +572,17 @@ none /run/shm tmpfs rw,nosuid,nodev 0 0"""
|
|||
|
||||
loops = [objects.Loop(), objects.Loop()]
|
||||
|
||||
self.mgr.driver.image_scheme = objects.ImageScheme([
|
||||
self.mgr.driver._image_scheme = objects.ImageScheme([
|
||||
objects.Image('file:///fake/img.img.gz', loops[0], 'ext4', 'gzip'),
|
||||
objects.Image('file:///fake/img-boot.img.gz',
|
||||
loops[1], 'ext2', 'gzip')])
|
||||
self.mgr.driver.partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver._partition_scheme = objects.PartitionScheme()
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
device=loops[0], mount='/', fs_type='ext4')
|
||||
self.mgr.driver.partition_scheme.add_fs(
|
||||
device=loops[1], mount='/boot', fs_type='ext2')
|
||||
self.mgr.driver.metadata_uri = 'file:///fake/img.yaml'
|
||||
self.mgr.driver.operating_system = objects.Ubuntu(
|
||||
self.mgr.driver._operating_system = objects.Ubuntu(
|
||||
repos=[
|
||||
objects.DEBRepo('ubuntu', 'http://fakeubuntu',
|
||||
'trusty', 'fakesection', priority=900),
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
import os
|
||||
|
||||
import mock
|
||||
import six
|
||||
from six.moves.urllib.parse import urlsplit
|
||||
|
||||
from oslotest import base as test_base
|
||||
import unittest2
|
||||
|
||||
from fuel_agent.drivers.nailgun import NailgunBuildImage
|
||||
from fuel_agent import errors
|
||||
|
@ -100,51 +100,45 @@ IMAGE_DATA_SAMPLE = {
|
|||
}
|
||||
|
||||
|
||||
class TestNailgunBuildImage(test_base.BaseTestCase):
|
||||
class TestNailgunBuildImage(unittest2.TestCase):
|
||||
|
||||
def test_default_trusty_packages(self):
|
||||
self.assertEqual(NailgunBuildImage.DEFAULT_TRUSTY_PACKAGES,
|
||||
DEFAULT_TRUSTY_PACKAGES)
|
||||
|
||||
@mock.patch.object(NailgunBuildImage, '__init__')
|
||||
def test_parse_operating_system_error_bad_codename(self, mock_init):
|
||||
mock_init.return_value = None
|
||||
driver = NailgunBuildImage()
|
||||
driver.data = {'codename': 'not-trusty'}
|
||||
self.assertRaises(errors.WrongInputDataError,
|
||||
driver.parse_operating_system)
|
||||
@mock.patch.object(NailgunBuildImage, 'parse_schemes')
|
||||
def test_parse_operating_system_error_bad_codename(self,
|
||||
mock_parse_schemes):
|
||||
with self.assertRaises(errors.WrongInputDataError):
|
||||
data = {'codename': 'not-trusty'}
|
||||
NailgunBuildImage(data)
|
||||
|
||||
@mock.patch('fuel_agent.objects.Ubuntu')
|
||||
@mock.patch.object(NailgunBuildImage, '__init__')
|
||||
def test_parse_operating_system_packages_given(self, mock_init, mock_ub):
|
||||
mock_init.return_value = None
|
||||
@mock.patch.object(NailgunBuildImage, 'parse_schemes')
|
||||
def test_parse_operating_system_packages_given(self, mock_parse_schemes,
|
||||
mock_ub):
|
||||
data = {
|
||||
'repos': [],
|
||||
'codename': 'trusty',
|
||||
'packages': ['pack']
|
||||
}
|
||||
driver = NailgunBuildImage()
|
||||
driver.data = data
|
||||
mock_ub_instance = mock_ub.return_value
|
||||
mock_ub_instance.packages = data['packages']
|
||||
driver.parse_operating_system()
|
||||
driver = NailgunBuildImage(data)
|
||||
mock_ub.assert_called_once_with(repos=[], packages=data['packages'])
|
||||
self.assertEqual(driver.operating_system.packages, data['packages'])
|
||||
|
||||
@mock.patch('fuel_agent.objects.Ubuntu')
|
||||
@mock.patch.object(NailgunBuildImage, '__init__')
|
||||
@mock.patch.object(NailgunBuildImage, 'parse_schemes')
|
||||
def test_parse_operating_system_packages_not_given(
|
||||
self, mock_init, mock_ub):
|
||||
mock_init.return_value = None
|
||||
self, mock_parse_schemes, mock_ub):
|
||||
data = {
|
||||
'repos': [],
|
||||
'codename': 'trusty'
|
||||
}
|
||||
driver = NailgunBuildImage()
|
||||
driver.data = data
|
||||
mock_ub_instance = mock_ub.return_value
|
||||
mock_ub_instance.packages = NailgunBuildImage.DEFAULT_TRUSTY_PACKAGES
|
||||
driver.parse_operating_system()
|
||||
driver = NailgunBuildImage(data)
|
||||
mock_ub.assert_called_once_with(
|
||||
repos=[], packages=NailgunBuildImage.DEFAULT_TRUSTY_PACKAGES)
|
||||
self.assertEqual(driver.operating_system.packages,
|
||||
|
@ -152,15 +146,13 @@ class TestNailgunBuildImage(test_base.BaseTestCase):
|
|||
|
||||
@mock.patch('fuel_agent.objects.DEBRepo')
|
||||
@mock.patch('fuel_agent.objects.Ubuntu')
|
||||
@mock.patch.object(NailgunBuildImage, '__init__')
|
||||
def test_parse_operating_system_repos(self, mock_init, mock_ub, mock_deb):
|
||||
mock_init.return_value = None
|
||||
@mock.patch.object(NailgunBuildImage, 'parse_schemes')
|
||||
def test_parse_operating_system_repos(self, mock_parse_schemes, mock_ub,
|
||||
mock_deb):
|
||||
data = {
|
||||
'repos': REPOS_SAMPLE,
|
||||
'codename': 'trusty'
|
||||
}
|
||||
driver = NailgunBuildImage()
|
||||
driver.data = data
|
||||
|
||||
mock_deb_expected_calls = []
|
||||
repos = []
|
||||
|
@ -174,7 +166,7 @@ class TestNailgunBuildImage(test_base.BaseTestCase):
|
|||
}
|
||||
mock_deb_expected_calls.append(mock.call(**kwargs))
|
||||
repos.append(objects.DEBRepo(**kwargs))
|
||||
driver.parse_operating_system()
|
||||
driver = NailgunBuildImage(data)
|
||||
mock_ub_instance = mock_ub.return_value
|
||||
mock_ub_instance.repos = repos
|
||||
mock_ub.assert_called_once_with(
|
||||
|
@ -185,21 +177,18 @@ class TestNailgunBuildImage(test_base.BaseTestCase):
|
|||
|
||||
@mock.patch('fuel_agent.drivers.nailgun.objects.Loop')
|
||||
@mock.patch('fuel_agent.objects.Image')
|
||||
@mock.patch('fuel_agent.objects.Fs')
|
||||
@mock.patch('fuel_agent.objects.FS')
|
||||
@mock.patch('fuel_agent.objects.PartitionScheme')
|
||||
@mock.patch('fuel_agent.objects.ImageScheme')
|
||||
@mock.patch.object(NailgunBuildImage, '__init__')
|
||||
@mock.patch.object(NailgunBuildImage, 'parse_operating_system')
|
||||
def test_parse_schemes(
|
||||
self, mock_init, mock_imgsch, mock_partsch,
|
||||
self, mock_parse_os, mock_imgsch, mock_partsch,
|
||||
mock_fs, mock_img, mock_loop):
|
||||
mock_init.return_value = None
|
||||
data = {
|
||||
'image_data': IMAGE_DATA_SAMPLE,
|
||||
'output': '/some/local/path',
|
||||
}
|
||||
driver = NailgunBuildImage()
|
||||
driver.data = data
|
||||
driver.parse_schemes()
|
||||
driver = NailgunBuildImage(data)
|
||||
|
||||
mock_fs_expected_calls = []
|
||||
mock_img_expected_calls = []
|
||||
|
@ -223,7 +212,7 @@ class TestNailgunBuildImage(test_base.BaseTestCase):
|
|||
'fs_type': image['format']
|
||||
}
|
||||
mock_fs_expected_calls.append(mock.call(**fs_kwargs))
|
||||
fss.append(objects.Fs(**fs_kwargs))
|
||||
fss.append(objects.FS(**fs_kwargs))
|
||||
|
||||
if mount == '/':
|
||||
metadata_filename = filename.split('.', 1)[0] + '.yaml'
|
||||
|
|
|
@ -14,16 +14,17 @@
|
|||
|
||||
import mock
|
||||
|
||||
from oslotest import base as test_base
|
||||
import unittest2
|
||||
|
||||
from fuel_agent import errors
|
||||
from fuel_agent.objects import partition
|
||||
|
||||
|
||||
class TestMD(test_base.BaseTestCase):
|
||||
class TestMultipleDevice(unittest2.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestMD, self).setUp()
|
||||
self.md = partition.Md('name', 'level')
|
||||
super(self.__class__, self).setUp()
|
||||
self.md = partition.MD(name='name', level='level')
|
||||
|
||||
def test_add_device_ok(self):
|
||||
self.assertEqual(0, len(self.md.devices))
|
||||
|
@ -59,8 +60,22 @@ class TestMD(test_base.BaseTestCase):
|
|||
self.assertRaises(errors.MDDeviceDuplicationError, self.md.add_spare,
|
||||
'device')
|
||||
|
||||
def test_conversion(self):
|
||||
self.md.add_device('device_a')
|
||||
self.md.add_spare('device_b')
|
||||
serialized = self.md.to_dict()
|
||||
assert serialized == {
|
||||
'name': 'name',
|
||||
'level': 'level',
|
||||
'devices': ['device_a', ],
|
||||
'spares': ['device_b', ],
|
||||
}
|
||||
new_md = partition.MD.from_dict(serialized)
|
||||
assert serialized == new_md.to_dict()
|
||||
|
||||
|
||||
class TestPartition(unittest2.TestCase):
|
||||
|
||||
class TestPartition(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestPartition, self).setUp()
|
||||
self.pt = partition.Partition('name', 'count', 'device', 'begin',
|
||||
|
@ -72,8 +87,27 @@ class TestPartition(test_base.BaseTestCase):
|
|||
self.assertEqual(1, len(self.pt.flags))
|
||||
self.assertIn('fake_flag', self.pt.flags)
|
||||
|
||||
def test_conversion(self):
|
||||
self.pt.flags.append('some_flag')
|
||||
self.pt.guid = 'some_guid'
|
||||
serialized = self.pt.to_dict()
|
||||
assert serialized == {
|
||||
'begin': 'begin',
|
||||
'configdrive': False,
|
||||
'count': 'count',
|
||||
'device': 'device',
|
||||
'end': 'end',
|
||||
'flags': ['some_flag', ],
|
||||
'guid': 'some_guid',
|
||||
'name': 'name',
|
||||
'partition_type': 'partition_type',
|
||||
}
|
||||
new_pt = partition.Partition.from_dict(serialized)
|
||||
assert serialized == new_pt.to_dict()
|
||||
|
||||
|
||||
class TestPartitionScheme(unittest2.TestCase):
|
||||
|
||||
class TestPartitionScheme(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestPartitionScheme, self).setUp()
|
||||
self.p_scheme = partition.PartitionScheme()
|
||||
|
@ -83,30 +117,30 @@ class TestPartitionScheme(test_base.BaseTestCase):
|
|||
self.p_scheme.root_device)
|
||||
|
||||
def test_fs_by_device(self):
|
||||
expected_fs = partition.Fs('device')
|
||||
expected_fs = partition.FS('device')
|
||||
self.p_scheme.fss.append(expected_fs)
|
||||
self.p_scheme.fss.append(partition.Fs('wrong_device'))
|
||||
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')
|
||||
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'))
|
||||
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')
|
||||
expected_pv = partition.PV('pv')
|
||||
self.p_scheme.pvs.append(expected_pv)
|
||||
self.p_scheme.pvs.append(partition.Pv('wrong_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')
|
||||
expected_vg = partition.VG('vg')
|
||||
self.p_scheme.vgs.append(expected_vg)
|
||||
self.p_scheme.vgs.append(partition.Vg('wrong_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)
|
||||
|
||||
|
@ -123,33 +157,33 @@ class TestPartitionScheme(test_base.BaseTestCase):
|
|||
|
||||
def test_md_next_name_fail(self):
|
||||
self.p_scheme.mds = [
|
||||
partition.Md('/dev/md%s' % x, 'level') for x in range(0, 128)]
|
||||
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')
|
||||
expected_md = partition.MD('name', 'level')
|
||||
self.p_scheme.mds.append(expected_md)
|
||||
self.p_scheme.mds.append(partition.Md('wrong_name', 'level'))
|
||||
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')
|
||||
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',
|
||||
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')
|
||||
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')
|
||||
|
@ -171,7 +205,7 @@ class TestPartitionScheme(test_base.BaseTestCase):
|
|||
self.assertEqual('-F', self.p_scheme.fss[0].options)
|
||||
|
||||
|
||||
class TestParted(test_base.BaseTestCase):
|
||||
class TestParted(unittest2.TestCase):
|
||||
def setUp(self):
|
||||
super(TestParted, self).setUp()
|
||||
self.prtd = partition.Parted('name', 'label')
|
||||
|
@ -254,3 +288,99 @@ class TestParted(test_base.BaseTestCase):
|
|||
'begin', 'end', 'primary')]
|
||||
self.prtd.partitions.extend(expected_partitions)
|
||||
self.assertEqual(expected_partitions, self.prtd.primary)
|
||||
|
||||
def test_conversion(self):
|
||||
prt = partition.Partition(
|
||||
name='name',
|
||||
count='count',
|
||||
device='device',
|
||||
begin='begin',
|
||||
end='end',
|
||||
partition_type='primary'
|
||||
)
|
||||
self.prtd.partitions.append(prt)
|
||||
serialized = self.prtd.to_dict()
|
||||
assert serialized == {
|
||||
'label': 'label',
|
||||
'name': 'name',
|
||||
'partitions': [
|
||||
prt.to_dict(),
|
||||
],
|
||||
'install_bootloader': False,
|
||||
}
|
||||
new_prtd = partition.Parted.from_dict(serialized)
|
||||
assert serialized == new_prtd.to_dict()
|
||||
|
||||
|
||||
class TestLogicalVolume(unittest2.TestCase):
|
||||
|
||||
def test_conversion(self):
|
||||
lv = partition.LV(
|
||||
name='lv-name',
|
||||
vgname='vg-name',
|
||||
size=1234
|
||||
)
|
||||
serialized = lv.to_dict()
|
||||
assert serialized == {
|
||||
'name': 'lv-name',
|
||||
'vgname': 'vg-name',
|
||||
'size': 1234,
|
||||
}
|
||||
new_lv = partition.LV.from_dict(serialized)
|
||||
assert serialized == new_lv.to_dict()
|
||||
|
||||
|
||||
class TestPhisicalVolume(unittest2.TestCase):
|
||||
|
||||
def test_conversion(self):
|
||||
pv = partition.PV(
|
||||
name='pv-name',
|
||||
metadatasize=987,
|
||||
metadatacopies=112,
|
||||
)
|
||||
serialized = pv.to_dict()
|
||||
assert serialized == {
|
||||
'name': 'pv-name',
|
||||
'metadatasize': 987,
|
||||
'metadatacopies': 112,
|
||||
}
|
||||
new_pv = partition.PV.from_dict(serialized)
|
||||
assert serialized == new_pv.to_dict()
|
||||
|
||||
|
||||
class TestVolumesGroup(unittest2.TestCase):
|
||||
|
||||
def test_conversion(self):
|
||||
vg = partition.VG(
|
||||
name='vg-name',
|
||||
pvnames=['pv-name-a', ]
|
||||
)
|
||||
serialized = vg.to_dict()
|
||||
assert serialized == {
|
||||
'name': 'vg-name',
|
||||
'pvnames': ['pv-name-a', ]
|
||||
}
|
||||
new_vg = partition.VG.from_dict(serialized)
|
||||
assert serialized == new_vg.to_dict()
|
||||
|
||||
|
||||
class TestFileSystem(unittest2.TestCase):
|
||||
|
||||
def test_conversion(self):
|
||||
fs = partition.FS(
|
||||
device='some-device',
|
||||
mount='/mount',
|
||||
fs_type='type',
|
||||
fs_options='some-option',
|
||||
fs_label='some-label',
|
||||
)
|
||||
serialized = fs.to_dict()
|
||||
assert serialized == {
|
||||
'device': 'some-device',
|
||||
'mount': '/mount',
|
||||
'fs_type': 'type',
|
||||
'fs_options': 'some-option',
|
||||
'fs_label': 'some-label',
|
||||
}
|
||||
new_fs = partition.FS.from_dict(serialized)
|
||||
assert serialized == new_fs.to_dict()
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 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
|
||||
import requests_mock
|
||||
import unittest2
|
||||
|
||||
from fuel_agent.drivers import simple
|
||||
from fuel_agent import objects
|
||||
from fuel_agent.tests import base
|
||||
|
||||
|
||||
@mock.patch.multiple(
|
||||
simple.NailgunSimpleDriver,
|
||||
parse_grub=lambda x: objects.Grub(),
|
||||
parse_configdrive_scheme=lambda x: objects.ConfigDriveScheme(),
|
||||
parse_image_scheme=lambda x: objects.ImageScheme())
|
||||
class TestObjectDeserialization(unittest2.TestCase):
|
||||
|
||||
def test_driver_always_has_correct_objects(self):
|
||||
driver = simple.NailgunSimpleDriver({})
|
||||
assert isinstance(driver.partition_scheme, objects.PartitionScheme)
|
||||
|
||||
def test_lv_data_is_loaded(self):
|
||||
lv_data = {
|
||||
'partitioning': {
|
||||
'lvs': [
|
||||
{
|
||||
'name': 'lv-name',
|
||||
'size': 12345,
|
||||
'vgname': 'vg-name',
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(lv_data)
|
||||
lv = driver.partition_scheme.lvs[0]
|
||||
assert len(driver.partition_scheme.lvs) == 1
|
||||
assert isinstance(lv, objects.LV)
|
||||
assert lv.name == 'lv-name'
|
||||
assert lv.size == 12345
|
||||
assert lv.vgname == 'vg-name'
|
||||
|
||||
def test_pv_data_is_loaded(self):
|
||||
pv_data = {
|
||||
'partitioning': {
|
||||
'pvs': [
|
||||
{
|
||||
'metadatacopies': 2,
|
||||
'metadatasize': 28,
|
||||
'name': '/dev/sda5'
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(pv_data)
|
||||
pv = driver.partition_scheme.pvs[0]
|
||||
assert len(driver.partition_scheme.pvs) == 1
|
||||
assert isinstance(pv, objects.PV)
|
||||
assert pv.name == '/dev/sda5'
|
||||
assert pv.metadatacopies == 2
|
||||
assert pv.metadatasize == 28
|
||||
|
||||
def test_vg_data_is_loaded(self):
|
||||
vg_data = {
|
||||
'partitioning': {
|
||||
'vgs': [
|
||||
{
|
||||
'name': 'image',
|
||||
'pvnames': [
|
||||
'/dev/sda6',
|
||||
'/dev/sdb3',
|
||||
'/dev/sdc3',
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(vg_data)
|
||||
vg = driver.partition_scheme.vgs[0]
|
||||
assert len(driver.partition_scheme.vgs) == 1
|
||||
assert isinstance(vg, objects.VG)
|
||||
assert vg.name == 'image'
|
||||
self.assertItemsEqual(
|
||||
vg.pvnames,
|
||||
(
|
||||
'/dev/sda6',
|
||||
'/dev/sdb3',
|
||||
'/dev/sdc3',
|
||||
)
|
||||
)
|
||||
|
||||
def test_fs_data_is_loaded(self):
|
||||
fs_data = {
|
||||
'partitioning': {
|
||||
'fss': [
|
||||
{
|
||||
'device': '/dev/sda3',
|
||||
'fs_label': 'some-label',
|
||||
'fs_options': 'some-options',
|
||||
'fs_type': 'ext2',
|
||||
'mount': '/boot'
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(fs_data)
|
||||
fs = driver.partition_scheme.fss[0]
|
||||
assert len(driver.partition_scheme.fss) == 1
|
||||
assert isinstance(fs, objects.FS)
|
||||
assert fs.device == '/dev/sda3'
|
||||
assert fs.label == 'some-label'
|
||||
assert fs.options == 'some-options'
|
||||
assert fs.type == 'ext2'
|
||||
assert fs.mount == '/boot'
|
||||
|
||||
def test_parted_data_is_loaded(self):
|
||||
parted_data = {
|
||||
'partitioning': {
|
||||
'parteds': [
|
||||
{
|
||||
'label': 'gpt',
|
||||
'name': '/dev/sdb',
|
||||
'partitions': [
|
||||
{
|
||||
'begin': 1,
|
||||
'configdrive': False,
|
||||
'count': 1,
|
||||
'device': '/dev/sdb',
|
||||
'end': 25,
|
||||
'flags': [
|
||||
'bios_grub',
|
||||
'xyz',
|
||||
],
|
||||
'guid': None,
|
||||
'name': '/dev/sdb1',
|
||||
'partition_type': 'primary'
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(parted_data)
|
||||
parted = driver.partition_scheme.parteds[0]
|
||||
partition = parted.partitions[0]
|
||||
assert len(driver.partition_scheme.parteds) == 1
|
||||
assert isinstance(parted, objects.Parted)
|
||||
assert parted.label == 'gpt'
|
||||
assert parted.name == '/dev/sdb'
|
||||
assert len(parted.partitions) == 1
|
||||
assert partition.begin == 1
|
||||
assert partition.configdrive is False
|
||||
assert partition.count == 1
|
||||
assert partition.device == '/dev/sdb'
|
||||
assert partition.end == 25
|
||||
self.assertItemsEqual(partition.flags, ['bios_grub', 'xyz'])
|
||||
assert partition.guid is None
|
||||
assert partition.name == '/dev/sdb1'
|
||||
assert partition.type == 'primary'
|
||||
|
||||
def test_md_data_is_loaded(self):
|
||||
md_data = {
|
||||
'partitioning': {
|
||||
'mds': [
|
||||
{
|
||||
'name': 'some-raid',
|
||||
'level': 1,
|
||||
'devices': [
|
||||
'/dev/sda',
|
||||
'/dev/sdc',
|
||||
],
|
||||
'spares': [
|
||||
'/dev/sdb',
|
||||
'/dev/sdd',
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
driver = simple.NailgunSimpleDriver(md_data)
|
||||
md = driver.partition_scheme.mds[0]
|
||||
assert len(driver.partition_scheme.mds) == 1
|
||||
assert isinstance(md, objects.MD)
|
||||
assert md.name == 'some-raid'
|
||||
assert md.level == 1
|
||||
self.assertItemsEqual(md.devices, ['/dev/sda', '/dev/sdc'])
|
||||
self.assertItemsEqual(md.spares, ['/dev/sdb', '/dev/sdd'])
|
||||
|
||||
|
||||
@requests_mock.mock()
|
||||
class TestFullDataRead(unittest2.TestCase):
|
||||
|
||||
PROVISION_DATA = base.load_fixture('simple_nailgun_driver.json')
|
||||
|
||||
def test_read_with_no_error(self, mock_requests):
|
||||
mock_requests.get('http://fake.host.org:123/imgs/fake_image.img.gz',
|
||||
text='{}')
|
||||
driver = simple.NailgunSimpleDriver(self.PROVISION_DATA)
|
||||
scheme = driver.partition_scheme
|
||||
assert len(scheme.fss) == 5
|
||||
assert len(scheme.lvs) == 3
|
||||
assert len(scheme.mds) == 0
|
||||
assert len(scheme.parteds) == 2
|
||||
assert len(scheme.pvs) == 4
|
||||
assert len(scheme.vgs) == 2
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 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.
|
||||
|
||||
|
||||
class abstractclassmethod(classmethod):
|
||||
"""A decorator indicating abstract classmethods.
|
||||
|
||||
Similar to abstractmethod.
|
||||
|
||||
Usage:
|
||||
|
||||
class C(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abstractclassmethod
|
||||
def my_abstract_classmethod(cls, ...):
|
||||
...
|
||||
|
||||
Copied from Python 3.2
|
||||
"""
|
||||
|
||||
__isabstractmethod__ = True
|
||||
|
||||
def __init__(self, callable):
|
||||
callable.__isabstractmethod__ = True
|
||||
super(abstractclassmethod, self).__init__(callable)
|
|
@ -24,6 +24,7 @@ console_scripts =
|
|||
|
||||
fuel_agent.drivers =
|
||||
nailgun = fuel_agent.drivers.nailgun:Nailgun
|
||||
nailgun_simple = fuel_agent.drivers.simple:NailgunSimpleDriver
|
||||
nailgun_build_image = fuel_agent.drivers.nailgun:NailgunBuildImage
|
||||
|
||||
[pbr]
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
hacking>=0.8.0,<0.9
|
||||
mock==1.0.1
|
||||
# TODO(prmtl): remove oslotest and (probably) testools in favor of unittest2
|
||||
oslotest==1.0
|
||||
testtools>=0.9.34
|
||||
unittest2==1.0.1
|
||||
pytest>=2.7.2
|
||||
pytest-cov>=1.8.1
|
||||
requests-mock>=0.6
|
||||
|
|
Loading…
Reference in New Issue