Extend usage of jsonschema

Validate all data feeded into bareon by jsonschema, not only data
related to disk partitioning.

It allows ironic-driver to make early data validation
(https://review.openstack.org/410841).

Change-Id: Ic1acf6b162ada83950ad4a890d32ca2a80152302
This commit is contained in:
Dmitry Bogun 2016-12-20 18:22:42 +02:00 committed by Andrii Ostapenko
parent af70312e49
commit c1fb86038f
20 changed files with 1035 additions and 788 deletions

View File

@ -0,0 +1,48 @@
#
# Copyright 2015 Cray Inc. All Rights Reserved.
#
# 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 jsonschema.validators
from bareon import errors
def validate(schema_path, payload):
schema = _load_validator_schema(schema_path)
cls = jsonschema.validators.validator_for(schema)
cls.check_schema(schema)
schema_validator = cls(schema, format_checker=jsonschema.FormatChecker())
defects = schema_validator.iter_errors(payload)
defects = list(defects)
if defects:
raise errors.InputDataSchemaValidationError(defects)
def _load_validator_schema(schema_path):
try:
with open(schema_path, 'rt') as storage:
schema = json.load(storage)
except IOError as e:
raise errors.ApplicationDataCorruptError(
'Can\'t read validation schema "{}": {} {}'.format(
e.filename, e.errno, e.strerror))
except (ValueError, TypeError) as e:
raise errors.ApplicationDataCorruptError(
'Corrupted validation schema "{}": {}'.format(schema_path, e))
return schema

View File

@ -14,9 +14,13 @@
import abc
import copy
import os
import pkg_resources
import six
import bareon.drivers.data
@six.add_metaclass(abc.ABCMeta)
class BaseDataDriver(object):
@ -26,11 +30,21 @@ class BaseDataDriver(object):
methods for getting object schemes, etc.
"""
data_validation_schema = None
def __init__(self, data):
self.validate_data(data)
self.data = copy.deepcopy(data)
if 'flow' in self.data:
self.flow = self.data['flow']
@classmethod
def validate_data(cls, data):
root = pkg_resources.resource_filename(
'bareon.drivers.data', 'json_schemes')
schema_path = os.path.join(root, cls.data_validation_schema)
bareon.drivers.data.validate(schema_path, data)
@six.add_metaclass(abc.ABCMeta)
class PartitioningDataDriverMixin(object):
@ -82,3 +96,7 @@ class MultibootDeploymentMixin(object):
@abc.abstractmethod
def get_os_ids(self):
pass
@abc.abstractmethod
def _partition_data(self):
pass

View File

@ -12,11 +12,14 @@
# 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 os
from oslo_config import cfg
from bareon import errors
from bareon.utils.partition import MiB
from bareon.utils.partition import TiB
from bareon.utils import utils
from bareon.drivers.data.base import BaseDataDriver
@ -167,7 +170,7 @@ class GenericDataDriver(BaseDataDriver,
@property
def _small_ks_disks(self):
"""Get those disks which are smaller than 2T"""
return [d for d in self._ks_disks if d['size'] <= 2 * 1024 * 1024]
return [x for x in self._ks_disks if x['size'] <= 2 * TiB / MiB]
def get_os_ids(self):
raise NotImplementedError

View File

@ -22,7 +22,6 @@ from oslo_config import cfg
from oslo_log import log as logging
from bareon.drivers.data.generic import GenericDataDriver
from bareon.drivers.data import ks_spaces_validator
from bareon import errors
from bareon import objects
from bareon.utils import hardware as hu
@ -39,11 +38,14 @@ DEFAULT_GRUB_SIZE = 24
class Ironic(GenericDataDriver):
data_validation_schema = 'ironic.json'
_root_on_lvm = None
_boot_on_lvm = None
def __init__(self, data):
super(Ironic, self).__init__(data)
self._root_on_lvm = None
self._boot_on_lvm = None
convert_size(self.data['partitions'])
def _get_image_meta(self):
pass
@ -120,15 +122,11 @@ class Ironic(GenericDataDriver):
scanning/comparing the underlying node hardware.
"""
LOG.debug('--- Preparing partition scheme ---')
# TODO(oberezovskyi): make validator work
data = self._partition_data()
ks_spaces_validator.validate(data, 'ironic')
data = convert_size(data)
partition_schema = objects.PartitionScheme()
LOG.debug('Looping over all disks in provision data')
multiboot_installed = False
LOG.debug('Looping over all disks in provision data')
partition_schema = objects.PartitionScheme()
for disk in self._ks_disks:
# # skipping disk if there are no volumes with size >0
# # to be allocated on it which are not boot partitions
@ -602,6 +600,18 @@ class Ironic(GenericDataDriver):
else:
return fnmatch.fnmatch(hu_data.get(id_type, ''), id_value)
@classmethod
def validate_data(cls, data):
super(Ironic, cls).validate_data(data)
disks = data['partitions']
# scheme is not valid if the number of disks is 0
if not [d for d in disks if d['type'] == 'disk']:
raise errors.WrongInputDataError(
'Invalid partition schema: You must specify at least one '
'disk.')
def convert_size(data):
data = convert_string_sizes(data)

View File

@ -1,54 +1,223 @@
{
"uniqueItems": true,
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"title": "Ironic partition schema",
"minItems": 1,
"items": {
"anyOf": [
{
"required": [
"type",
"id",
"volumes",
"size"
],
"title": "Ironic deployment config schema",
"type": "object",
"required": [
"partitions",
"images"
],
"properties": {
"images": {
"type": "array",
"items": {
"type": "object",
"properties": {
"image_name": {
"type": "string"
},
"image_uuid": {
"type": "string"
},
"image_pull_url": {
"type": "string"
},
"target": {
"type": "string"
},
"name": {
"type": "string"
},
"volumes": {
"items": {
"anyOf": [
{
"boot": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "integer"
}
]
}
}
}
},
"image_deploy_flags": {
"type": "object"
},
"partitions_policy": {
"enum": [
"verify",
"clean",
"nailgun_legacy"
]
},
"partitions": {
"type": "array",
"uniqueItems": true,
"minItems": 1,
"items": {
"anyOf": [
{
"type": "object",
"required": [
"type",
"id",
"volumes",
"size"
],
"properties": {
"name": {
"type": "string"
},
"volumes": {
"items": {
"anyOf": [
{
"required": [
"type",
"size",
"vg"
],
"type": "object",
"properties": {
"vg": {
"type": "string"
},
"type": {
"enum": [
"pv"
]
},
"keep_data": {
"type": "boolean"
},
"lvm_meta_size": {
"type": "string"
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"mount": {
"type": "string"
},
"type": {
"enum": [
"raid",
"partition"
]
},
"keep_data": {
"type": "boolean"
},
"file_system": {
"type": "string"
},
"name": {
"type": "string"
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"boot"
]
},
"size": {
"type": "string"
},
"keep_data": {
"type": "boolean"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"lvm_meta_pool"
]
},
"size": {
"type": "string"
}
}
}
]
},
"type": "array"
},
"type": {
"enum": [
"disk"
]
},
"id": {
"required": [
"type",
"value"
],
"type": "object",
"properties": {
"type": {
"enum": [
"scsi",
"path",
"name"
]
}
}
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"id",
"volumes"
],
"type": "object",
"properties": {
"_allocate_size": {
"type": "string"
},
"label": {
"type": "string"
},
"min_size": {
"type": "integer"
},
"volumes": {
"items": {
"required": [
"type",
"size",
"vg"
],
"type": "object",
"properties": {
"vg": {
"type": "string"
},
"type": {
"enum": [
"pv"
]
},
"lvm_meta_size": {
"type": "string"
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"size"
"name"
],
"type": "object",
"properties": {
@ -57,142 +226,48 @@
},
"type": {
"enum": [
"raid",
"partition"
"lv"
]
},
"file_system": {
"type": "string"
"keep_data": {
"type": "boolean"
},
"name": {
"type": "string"
},
"size": {
"file_system": {
"type": "string"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"boot"
]
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"lvm_meta_pool"
]
},
"size": {
"type": "string"
}
}
}
]
},
"type": "array"
},
"type": {
"enum": [
"disk"
]
},
"id": {
"required": [
"type",
"value"
],
"type": "object",
"properties": {
"type": "array"
},
"type": {
"enum": [
"scsi",
"path",
"name"
"vg"
]
},
"keep_data": {
"type": "boolean"
},
"id": {
"type": "string"
}
}
},
"size": {
"type": "string"
}
}
},
{
"required": [
"type",
"id",
"volumes"
],
"type": "object",
"properties": {
"_allocate_size": {
"type": "string"
},
"label": {
"type": "string"
},
"min_size": {
"type": "integer"
},
"volumes": {
"items": {
"required": [
"type",
"size",
"name"
],
"type": "object",
"properties": {
"mount": {
"type": "string"
},
"type": {
"enum": [
"lv"
]
},
"name": {
"type": "string"
},
"file_system": {
"type": "string"
},
"size": {
"type": "string"
}
}
},
"type": "array"
},
"type": {
"enum": [
"vg"
]
},
"id": {
"type": "string"
}
]
}
},
"deploy_data": {
"type": "object",
"properties": {
"kernel_params": {
"type": "string"
}
}
]
}
}
}
}

View File

@ -0,0 +1,3 @@
{
"type": "object"
}

View File

@ -1,99 +1,314 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Partition scheme",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"anyOf": [
{
"type": "object",
"required": ["type", "id", "volumes", "name",
"size", "extra", "free_space"],
"properties": {
"type": {"enum": ["disk"]},
"id": {"type": "string"},
"name": {"type": "string"},
"size": {"type": "integer"},
"free_space": {"type": "integer"},
"extra": {
"type": "array",
"items": {"type": "string"}
},
"volumes": {
"type": "array",
"items": {
"title": "Nailgun partition schema",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"ks_meta"
],
"properties": {
"hostname": {
"type": "string"
},
"name_servers": {
"type": "string"
},
"name_servers_search": {
"type": "string"
},
"profile": {
"type": "string"
},
"ks_meta": {
"type": "object",
"required": [
"pm_data"
],
"properties": {
"timezone": {
"type": "string"
},
"master_ip": {
"type": "string"
},
"gw": {
"type": "string"
},
"auth_key": {
"type": "string"
},
"pm_data": {
"type": "object",
"required": [
"ks_spaces"
],
"properties": {
"kernel_params": {
"type": "string"
},
"ks_spaces": {
"type": "array",
"uniqueItems": true,
"minItems": 1,
"items": {
"anyOf": [
{
"required": [
"type",
"id",
"volumes",
"name",
"size",
"extra",
"free_space"
],
"type": "object",
"properties": {
"name": {
"type": "string"
},
"extra": {
"items": {
"type": "string"
},
"type": "array"
},
"free_space": {
"type": "integer"
},
"volumes": {
"items": {
"anyOf": [
{
"type": "object",
"required": ["type", "size",
"lvm_meta_size", "vg"],
"properties": {
"type": {"enum": ["pv"]},
"size": {"type": "integer"},
"lvm_meta_size": {"type": "integer"},
"vg": {"type": "string"}
}
},
{
"type": "object",
"required": ["type", "size"],
"properties": {
"type": {"enum": ["raid",
"partition"]},
"size": {"type": "integer"},
"mount": {"type": "string"},
"file_system": {"type": "string"},
"name": {"type": "string"}
}
},
{
"type": "object",
"required": ["type", "size"],
"properties": {
"type": {"enum": ["boot"]},
"size": {"type": "integer"}
}
},
{
"type": "object",
"required": ["type", "size"],
"properties": {
"type": {"enum": ["lvm_meta_pool"]},
"size": {"type": "integer"}
}
{
"required": [
"type",
"size",
"vg"
],
"type": "object",
"properties": {
"vg": {
"type": "string"
},
"type": {
"enum": [
"pv"
]
},
"lvm_meta_size": {
"type": "integer"
},
"size": {
"type": "integer"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"mount": {
"type": "string"
},
"type": {
"enum": [
"raid",
"partition"
]
},
"file_system": {
"type": "string"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"boot"
]
},
"size": {
"type": "integer"
}
}
},
{
"required": [
"type",
"size"
],
"type": "object",
"properties": {
"type": {
"enum": [
"lvm_meta_pool"
]
},
"size": {
"type": "integer"
}
}
}
]
},
"type": "array"
},
"type": {
"enum": [
"disk"
]
},
"id": {
"type": "string"
},
"size": {
"type": "integer"
}
}
},
{
"required": [
"type",
"id",
"volumes"
],
"type": "object",
"properties": {
"_allocate_size": {
"type": "string"
},
"label": {
"type": "string"
},
"min_size": {
"type": "integer"
},
"volumes": {
"items": {
"required": [
"type",
"size",
"name"
],
"type": "object",
"properties": {
"mount": {
"type": "string"
},
"type": {
"enum": [
"lv"
]
},
"name": {
"type": "string"
},
"file_system": {
"type": "string"
},
"size": {
"type": "integer"
}
}
},
"type": "array"
},
"type": {
"enum": [
"vg"
]
},
"id": {
"type": "string"
}
}
}
]
}
}
}
},
"image_data": {
"type": "object"
},
"repo_setup": {
"type": "object",
"properties": {
"repos": {
"type": "array"
}
}
},
"puppet_master": {
"type": "string"
},
"puppet_enable": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "object",
"required": ["type", "id", "volumes"],
"properties": {
"type": {"enum": ["vg"]},
"id": {"type": "string"},
"label": {"type": "string"},
"min_size": {"type": "integer"},
"_allocate_size": {"type": "string"},
"volumes": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "size", "name"],
"properties": {
"type": {"enum": ["lv"]},
"size": {"type": "integer"},
"name": {"type": "string"},
"mount": {"type": "string"},
"file_system": {"type": "string"}
}
}
}
}
"type": "integer"
}
]
]
},
"mco_pskey": {
"type": "string"
},
"mco_vhost": {
"type": "string"
},
"mco_host": {
"type": "string"
},
"mco_user": {
"type": "string"
},
"mco_password": {
"type": "string"
},
"mco_connector": {
"type": "string"
},
"mco_enable": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "integer"
}
]
}
}
},
"kernel_options": {
"type": "object",
"properties": {
"netcfg/choose_interface": {
"type": "string"
},
"udevrules": {
"type": "string"
}
}
},
"interfaces": {
"type": "object"
}
}
}

View File

@ -1,57 +0,0 @@
# 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 json
import jsonschema
import os
from oslo_log import log as logging
from bareon import errors
LOG = logging.getLogger(__name__)
def validate(data, schema_file='nailgun'):
"""Validates a given partition scheme using jsonschema.
:param scheme: partition scheme to validate
"""
base_path = os.path.dirname(__file__)
schemas_path = os.path.join(base_path, 'json_schemes')
with open(os.path.join(schemas_path, '%s.json' % schema_file)) as file:
schema = json.load(file)
try:
checker = jsonschema.FormatChecker()
jsonschema.validate(data, schema,
format_checker=checker)
except Exception as exc:
LOG.exception(exc)
raise errors.WrongPartitionSchemeError(str(exc))
# scheme is not valid if the number of disks is 0
if not [d for d in data if d['type'] == 'disk']:
raise errors.WrongPartitionSchemeError(
'Partition scheme seems empty')
# TODO(lobur): Must be done after unit conversion
# for space in data:
# for volume in space.get('volumes', []):
# if volume['size'] > 16777216 and volume.get('mount') == '/':
# raise errors.WrongPartitionSchemeError(
# 'Root file system must be less than 16T')
# TODO(kozhukalov): need to have additional logical verifications
# maybe sizes and format of string values

View File

@ -32,7 +32,6 @@ from bareon.drivers.data.base import ConfigDriveDataDriverMixin
from bareon.drivers.data.base import GrubBootloaderDataDriverMixin
from bareon.drivers.data.base import PartitioningDataDriverMixin
from bareon.drivers.data.base import ProvisioningDataDriverMixin
from bareon.drivers.data import ks_spaces_validator
from bareon import errors
from bareon import objects
@ -84,6 +83,9 @@ class Nailgun(BaseDataDriver,
GrubBootloaderDataDriverMixin):
"""Driver for parsing regular volumes metadata from Nailgun."""
data_validation_schema = 'nailgun.json'
partitions_policy = 'nailgun_legacy'
def __init__(self, data):
super(Nailgun, self).__init__(data)
@ -336,15 +338,13 @@ class Nailgun(BaseDataDriver,
def parse_partition_scheme(self):
LOG.debug('--- Preparing partition scheme ---')
data = self.partition_data()
ks_spaces_validator.validate(data)
partition_scheme = objects.PartitionScheme()
ceph_osds = self._num_ceph_osds()
journals_left = ceph_osds
ceph_journals = self._num_ceph_journals()
LOG.debug('Looping over all disks in provision data')
partition_scheme = objects.PartitionScheme()
for disk in self.ks_disks:
# skipping disk if there are no volumes with size >0
# to be allocated on it which are not boot partitions
@ -710,6 +710,18 @@ class Nailgun(BaseDataDriver,
)
return image_scheme
@classmethod
def validate_data(cls, data):
super(Nailgun, cls).validate_data(data)
disks = data['ks_meta']['pm_data']['ks_spaces']
# scheme is not valid if the number of disks is 0
if not [d for d in disks if d['type'] == 'disk']:
raise errors.WrongInputDataError(
'Invalid partition schema: You must specify at least one '
'disk.')
class Ironic(Nailgun):
def __init__(self, data):
@ -723,6 +735,7 @@ class NailgunBuildImage(BaseDataDriver,
ProvisioningDataDriverMixin,
ConfigDriveDataDriverMixin,
GrubBootloaderDataDriverMixin):
data_validation_schema = 'nailgun-build-image.json'
DEFAULT_TRUSTY_PACKAGES = [
"acl",

View File

@ -19,10 +19,32 @@ class BaseError(Exception):
super(BaseError, self).__init__(message, *args, **kwargs)
class ApplicationDataCorruptError(BaseError):
pass
class WrongInputDataError(BaseError):
pass
class InputDataSchemaValidationError(WrongInputDataError):
def __init__(self, defects):
human_readable_defects = []
for idx, d in enumerate(defects):
path = [''] + list(d.path)
path = '/'.join((str(x) for x in path))
human_readable_defects.append(
'#{} ({}): {}'.format(idx, path, d.message))
indent = ' ' * 4
separator = '\n{}'.format(indent)
message = 'Invalid input data:\n{}{}'.format(
indent, separator.join(human_readable_defects))
super(WrongInputDataError, self).__init__(message, defects)
self.defects = defects
class WrongPartitionSchemeError(BaseError):
pass

View File

@ -63,7 +63,17 @@
"mco_identity": -1,
"pm_data": {
"kernel_params": "console=ttyS0,9600 console=tty0 rootdelay=90 nomodeset",
"ks_spaces": []
"ks_spaces": [
{
"type": "disk",
"id": "dummy-disk-id",
"name": "dummy0",
"free_space": 0,
"size": 128,
"extra": [],
"volumes": []
}
]
},
"puppet_auto_setup": 1,
"puppet_enable": 0,

View File

@ -17,12 +17,14 @@ import mock
import unittest2
from bareon.drivers.data import generic
from bareon.utils.partition import MiB
from bareon.utils.partition import TiB
class TestKsDisks(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestKsDisks, self).__init__(*args, **kwargs)
self.driver = generic.GenericDataDriver({})
def setUp(self):
super(TestKsDisks, self).setUp()
self.driver = _DummyDataDriver({})
self.driver._partition_data = self.mock_part_data = mock.MagicMock()
def test_no_partition_data(self):
@ -72,9 +74,9 @@ class TestKsDisks(unittest2.TestCase):
class TestKsVgs(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestKsVgs, self).__init__(*args, **kwargs)
self.driver = generic.GenericDataDriver({})
def setUp(self):
super(TestKsVgs, self).setUp()
self.driver = _DummyDataDriver({})
self.driver._partition_data = self.mock_part_data = mock.MagicMock()
def test_no_partition_data(self):
@ -112,9 +114,9 @@ class TestKsVgs(unittest2.TestCase):
class TestSmallKsDisks(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestSmallKsDisks, self).__init__(*args, **kwargs)
self.driver = generic.GenericDataDriver({})
def setUp(self):
super(TestSmallKsDisks, self).setUp()
self.driver = _DummyDataDriver({})
self.driver._partition_data = self.mock_part_data = mock.MagicMock()
def test_no_partition_data(self):
@ -128,8 +130,8 @@ class TestSmallKsDisks(unittest2.TestCase):
def test_no_partitions_valid_size(self):
self.mock_part_data.return_value = [
{'size': 3 * 1024 * 1024, 'type': 'disk'},
{'size': 5 * 1024 * 1024, 'type': 'disk'}
{'size': 3 * TiB, 'type': 'disk'},
{'size': 5 * TiB, 'type': 'disk'}
]
desired = []
@ -140,10 +142,10 @@ class TestSmallKsDisks(unittest2.TestCase):
def test_valid_data(self):
self.mock_part_data.return_value = [
{'size': 3 * 1024 * 1024, 'type': 'vg'},
{'size': 1 * 1024 * 1024, 'type': 'disk'}
{'size': 3 * MiB, 'type': 'vg'},
{'size': 1 * MiB, 'type': 'disk'}
]
desired = [{'size': 1 * 1024 * 1024, 'type': 'disk'}]
desired = [{'size': 1 * MiB, 'type': 'disk'}]
result = self.driver._small_ks_disks
@ -152,9 +154,9 @@ class TestSmallKsDisks(unittest2.TestCase):
class TestGetLabel(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestGetLabel, self).__init__(*args, **kwargs)
self.driver = generic.GenericDataDriver({})
def setUp(self):
super(TestGetLabel, self).setUp()
self.driver = _DummyDataDriver({})
def test_no_label(self):
label = None
@ -179,3 +181,12 @@ class TestGetLabel(unittest2.TestCase):
result = self.driver._getlabel(label)
self.assertEqual(result, desired)
class _DummyDataDriver(generic.GenericDataDriver):
def _partition_data(self):
return []
@classmethod
def validate_data(cls, payload):
pass

View File

@ -226,11 +226,14 @@ LIST_BLOCK_DEVICES_SAMPLE = [
]
class TestIronicMatch(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestIronicMatch, self).__init__(*args, **kwargs)
self.data_driver = ironic.Ironic('')
class _IronicTest(unittest2.TestCase):
def setUp(self):
super(_IronicTest, self).setUp()
with mock.patch.object(ironic.Ironic, 'validate_data'):
self.data_driver = ironic.Ironic({'partitions': []})
class TestIronicMatch(_IronicTest):
def test_match_device_by_scsi_matches(self):
# matches by scsi address
fake_ks_disk = {
@ -319,10 +322,11 @@ class TestIronicMatch(unittest2.TestCase):
self.data_driver._match_device(fake_hu_disk, fake_ks_disk))
@mock.patch('bareon.drivers.data.ironic.hu.scsi_address')
class TestNailgunMockedMeta(unittest2.TestCase):
def test_partition_scheme(self, mock_scsi_address):
data_driver = ironic.Ironic(PROVISION_SAMPLE_DATA_SWIFT)
@mock.patch('bareon.utils.hardware.scsi_address', mock.Mock())
class TestNailgunMockedMeta(_IronicTest):
def test_partition_scheme(self):
with mock.patch.object(ironic.Ironic, 'validate_data'):
data_driver = ironic.Ironic(PROVISION_SAMPLE_DATA_SWIFT)
data_driver.get_image_ids = mock.MagicMock
mock_devices = data_driver._get_block_devices = mock.MagicMock()
@ -336,18 +340,17 @@ class TestNailgunMockedMeta(unittest2.TestCase):
self.assertEqual(3, len(p_scheme.parteds))
@mock.patch('bareon.drivers.data.ironic.hu.get_block_devices_from_udev_db')
class TestGetBlockDevices(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestGetBlockDevices, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic('')
self.mock_devices = mock.MagicMock()
self.driver._get_block_device_info = self.mock_devices
@mock.patch('bareon.utils.hardware.get_block_devices_from_udev_db')
class TestGetBlockDevices(_IronicTest):
def setUp(self):
super(TestGetBlockDevices, self).setUp()
self.mock_devices = mock.Mock()
self.data_driver._get_block_device_info = self.mock_devices
def test_no_devices(self, mock_get_block_devices_from_udev_db):
mock_get_block_devices_from_udev_db.return_value = []
result = self.driver._get_block_devices()
result = self.data_driver._get_block_devices()
self.assertEqual(result, [])
mock_get_block_devices_from_udev_db.assert_called_once_with()
self.assertEqual(self.mock_devices.call_count, 0)
@ -357,32 +360,30 @@ class TestGetBlockDevices(unittest2.TestCase):
mock_get_block_devices_from_udev_db.return_value = [data]
self.mock_devices.return_value = block_device = 'test_value'
result = self.driver._get_block_devices()
result = self.data_driver._get_block_devices()
self.assertEqual(result, [block_device])
mock_get_block_devices_from_udev_db.assert_called_once_with()
self.mock_devices.assert_called_once_with(data)
@mock.patch('bareon.drivers.data.ironic.hu.get_device_ids')
@mock.patch('bareon.drivers.data.ironic.hu.get_device_info')
@mock.patch('bareon.drivers.data.ironic.hu.scsi_address')
class TestGetBlockDevice(unittest2.TestCase):
@mock.patch('bareon.utils.hardware.get_device_ids')
@mock.patch('bareon.utils.hardware.get_device_info')
@mock.patch('bareon.utils.hardware.scsi_address')
class TestGetBlockDevice(_IronicTest):
def test_no_device_info(self, mock_scsi_address, mock_get_device_info,
mock_get_device_ids):
data_driver = ironic.Ironic('')
device = 'fake_device'
mock_scsi_address.return_value = None
mock_get_device_info.return_value = {}
mock_get_device_ids.return_value = []
result = data_driver._get_block_device_info(device)
result = self.data_driver._get_block_device_info(device)
self.assertEqual(result, {'name': 'fake_device'})
def test_device_info(self, mock_scsi_address, mock_get_device_info,
mock_get_device_ids):
data_driver = ironic.Ironic('')
device = 'fake_device'
devpath = ['test/devpath']
uspec = {'DEVPATH': devpath}
@ -396,19 +397,19 @@ class TestGetBlockDevice(unittest2.TestCase):
desired = {'path': devpath, 'name': device, 'scsi': scsi_address,
'uspec': uspec}
result = data_driver._get_block_device_info(device)
result = self.data_driver._get_block_device_info(device)
self.assertEqual(result, desired)
mock_get_device_info.assert_called_once_with(device)
mock_scsi_address.assert_called_once_with(device)
@mock.patch('bareon.drivers.data.ironic.Ironic.validate_data', mock.Mock())
class TestGetGrub(unittest2.TestCase):
@mock.patch('bareon.utils.utils.parse_kernel_cmdline')
def test_kernel_params(self, cmdline_mock):
data = {'deploy_data': {'kernel_params': "test_param=test_val",
'other_data': 'test'},
'partitions': 'fake_shema'}
'partitions': {}}
cmdline_mock.return_value = {
"BOOTIF": "01-52-54-00-a5-55-58",
"extrastuff": "test123"
@ -421,24 +422,24 @@ class TestGetGrub(unittest2.TestCase):
def test_no_kernel_params(self):
data = {'deploy_data': {'other_data': "test"},
'partitions': 'fake_shema'}
'partitions': {}}
data_driver = ironic.Ironic(data)
self.assertEqual('', data_driver.grub.kernel_params)
@mock.patch('bareon.drivers.data.ironic.Ironic.validate_data', mock.Mock())
class TestPartitionsPolicy(unittest2.TestCase):
def test_partitions_policy(self):
data = {'partitions_policy': "test_value",
'partitions': 'fake_shema'}
'partitions': {}}
data_driver = ironic.Ironic(data)
self.assertEqual('test_value', data_driver.partitions_policy)
def test_partitions_policy_default(self):
data = {'partitions': 'fake_shema'}
data = {'partitions': {}}
data_driver = ironic.Ironic(data)

View File

@ -23,10 +23,24 @@ from bareon.utils import hardware as hu
from bareon.utils import utils
class TestGetImageSchema(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestGetImageSchema, self).__init__(*args, **kwargs)
class IronicTestAbstract(unittest2.TestCase):
def setUp(self):
super(IronicTestAbstract, self).setUp()
self.driver = self.new_data_driver()
@staticmethod
def new_data_driver(payload=None):
if payload is None:
payload = {}
payload.setdefault('partitions', [])
with mock.patch.object(ironic.Ironic, 'validate_data'):
driver = ironic.Ironic(payload)
return driver
class TestGetImageSchema(IronicTestAbstract):
def test_get_image_schema(self):
image_uri = 'test_uri'
rsync_flags = '-a -X'
@ -38,9 +52,9 @@ class TestGetImageSchema(unittest2.TestCase):
'name': 'test'
}
], 'image_deploy_flags': deploy_flags}
self.driver = ironic.Ironic(data)
driver = self.new_data_driver(data)
result = self.driver._get_image_scheme()
result = driver._get_image_scheme()
self.assertEqual(len(result.images), 1)
@ -49,11 +63,7 @@ class TestGetImageSchema(unittest2.TestCase):
self.assertEqual(result_image.uri, image_uri)
class TestMatchDevice(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestMatchDevice, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestMatchDevice(IronicTestAbstract):
def test_match_list_value(self):
test_type = 'path'
test_value = 'test_path'
@ -95,10 +105,9 @@ class TestMatchDevice(unittest2.TestCase):
self.assertFalse(result)
class TestDiskDev(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestDiskDev, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestDiskDev(IronicTestAbstract):
def setUp(self):
super(TestDiskDev, self).setUp()
self.driver._match_device = self.mock_match_device = mock.MagicMock()
def test_no_valid_disks(self):
@ -133,11 +142,7 @@ class TestDiskDev(unittest2.TestCase):
self.assertEqual(result, 'disk1')
class TestMatchPartition(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestMatchPartition, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestMatchPartition(IronicTestAbstract):
def test_match_list_value(self):
test_type = 'path'
test_value = 'test_path'
@ -221,10 +226,9 @@ class TestMatchPartition(unittest2.TestCase):
self.assertFalse(result)
class TestDiskPartition(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestDiskPartition, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestDiskPartition(IronicTestAbstract):
def setUp(self):
super(TestDiskPartition, self).setUp()
self.driver._match_data_by_pattern = \
self.mock_match_part = mock.MagicMock()
@ -262,11 +266,7 @@ class TestDiskPartition(unittest2.TestCase):
@mock.patch('bareon.utils.hardware.get_partitions_from_udev_db')
@mock.patch('bareon.utils.hardware.get_device_ids')
class TestGetPartitionIds(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestGetPartitionIds, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestGetPartitionIds(IronicTestAbstract):
def test_no_devices(self, mock_ids, mock_partitions):
mock_partitions.return_value = []
desired = []
@ -299,22 +299,21 @@ class TestGetPartitionIds(unittest2.TestCase):
mock_ids.assert_has_calls([mock.call(part) for part in parts])
class TestFindHwFstab(unittest2.TestCase):
class TestFindHwFstab(IronicTestAbstract):
@mock.patch.object(utils, 'execute')
def test__find_hw_fstab_success_single_disk(self, exec_mock):
fs = namedtuple('fs', 'mount type device os_id')
fss = [fs(mount='/', type='ext4', device='/dev/sda', os_id='1'),
fs(mount='/usr', type='ext4', device='/dev/sdb', os_id='1')]
data_driver = ironic.Ironic({})
data_driver._partition_scheme = ironic.objects.PartitionScheme()
data_driver.partition_scheme.fss = fss
self.driver._partition_scheme = ironic.objects.PartitionScheme()
self.driver.partition_scheme.fss = fss
exec_mock.side_effect = [('stdout', 'stderr'),
('fstab_1', 'stderr'),
('stdout', 'stderr')]
res = data_driver._find_hw_fstab()
res = self.driver._find_hw_fstab()
self.assertEqual('\n'.join(('fstab_1',)), res)
@ -325,9 +324,8 @@ class TestFindHwFstab(unittest2.TestCase):
fs(mount='/usr', type='ext4', device='/dev/sdb', os_id='1'),
fs(mount='/', type='ext4', device='/dev/sda', os_id='2')]
data_driver = ironic.Ironic({})
data_driver._partition_scheme = ironic.objects.PartitionScheme()
data_driver.partition_scheme.fss = fss
self.driver._partition_scheme = ironic.objects.PartitionScheme()
self.driver.partition_scheme.fss = fss
exec_mock.side_effect = [('stdout', 'stderr'),
('fstab_1', 'stderr'),
@ -336,7 +334,7 @@ class TestFindHwFstab(unittest2.TestCase):
('fstab_2', 'stderr'),
('stdout', 'stderr')]
res = data_driver._find_hw_fstab()
res = self.driver._find_hw_fstab()
self.assertEqual('\n'.join(('fstab_1', 'fstab_2')), res)
@ -346,15 +344,14 @@ class TestFindHwFstab(unittest2.TestCase):
fss = [fs(mount='/etc', type='ext4', device='/dev/sda', os_id='1'),
fs(mount='/', type='ext4', device='/dev/sda', os_id='1')]
data_driver = ironic.Ironic({})
data_driver._partition_scheme = ironic.objects.PartitionScheme()
data_driver.partition_scheme.fss = fss
self.driver._partition_scheme = ironic.objects.PartitionScheme()
self.driver.partition_scheme.fss = fss
exec_mock.side_effect = [('stdout', 'stderr'),
errors.ProcessExecutionError,
('stdout', 'stderr')]
self.assertRaises(errors.HardwarePartitionSchemeCannotBeReadError,
data_driver._find_hw_fstab)
self.driver._find_hw_fstab)
class TestConvertStringSize(unittest2.TestCase):
@ -847,10 +844,9 @@ class TestConvertPercentSizes(unittest2.TestCase):
map(lambda r, d: self.assertDictEqual(r, d), result, desired)
class TestProcessPartition(unittest2.TestCase):
def __init__(self, *args, **kwargs):
super(TestProcessPartition, self).__init__(*args, **kwargs)
self.driver = ironic.Ironic({})
class TestProcessPartition(IronicTestAbstract):
def setUp(self):
super(TestProcessPartition, self).setUp()
self.driver._partition_data = self.mock_part_data = mock.MagicMock()
self.driver._add_partition = self.mock_add_part = mock.MagicMock()
self.mock_add_part.return_value = self.mock_part = mock.MagicMock()

View File

@ -16,10 +16,10 @@ import copy
import unittest2
from bareon.drivers.data import ks_spaces_validator as kssv
from bareon.drivers.data import ironic
from bareon import errors
SAMPLE_SCHEME = [
SAMPLE_CHUNK_PARTITIONS = [
{
"id": {
"type": "name",
@ -175,67 +175,108 @@ SAMPLE_SCHEME = [
}
]
SAMPLE_PAYLOAD = {
'partitions': SAMPLE_CHUNK_PARTITIONS,
'images': []
}
class TestKSSpacesValidator(unittest2.TestCase):
class TestIronicDataValidator(unittest2.TestCase):
def setUp(self):
super(TestKSSpacesValidator, self).setUp()
self.fake_scheme = copy.deepcopy(SAMPLE_SCHEME)
super(TestIronicDataValidator, self).setUp()
self.payload = copy.deepcopy(SAMPLE_PAYLOAD)
def test_validate_ok(self):
kssv.validate(self.fake_scheme, 'ironic')
def test_no_error(self):
ironic.Ironic.validate_data(self.payload)
def test_validate_jsoschema_fail(self):
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, [{}], 'ironic')
def test_fail(self):
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data, [{}])
def test_validate_no_disks_fail(self):
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme[-2:], 'ironic')
def test_required_fields(self):
for field in ['partitions']:
payload = copy.deepcopy(self.payload)
del payload[field]
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
payload)
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, 'ironic')
def test_disks_no_disks_fail(self):
partitions = self.payload['partitions']
partitions[:-2] = []
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
def test_validate_volume_type_fail(self):
@unittest2.skip(
'FIXME(dbogun): Invalid test - failed because invalid data '
'type(expect sting in size field) but not because illegal partition '
'size')
def test_disks_16T_root_volume_fail(self):
partitions = self.payload['partitions']
partitions[3]['volumes'][0]['size'] = 16777216 + 1
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
def test_disks_volume_type_fail(self):
incorrect_values_for_type = [
False, True, 0, 1, None, object
]
partitions = self.payload['partitions']
for value in incorrect_values_for_type:
self.fake_scheme[0]['volumes'][1]['type'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'ironic')
partitions[0]['volumes'][1]['type'] = value
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
def test_validate_volume_size_fail(self):
def test_disks_volume_size_fail(self):
incorrect_values_for_size = [
False, True, 0, 1, None, object
]
partitions = self.payload['partitions']
for value in incorrect_values_for_size:
self.fake_scheme[0]['volumes'][1]['size'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'ironic')
partitions[0]['volumes'][1]['size'] = value
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
def test_validate_device_id_fail(self):
def test_disks_device_id_fail(self):
incorrect_values_for_id = [
False, True, 0, 1, None, object
]
partitions = self.payload['partitions']
for value in incorrect_values_for_id:
self.fake_scheme[0]['id'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'ironic')
partitions[0]['id'] = value
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
def test_validate_missed_property(self):
def test_disks_missed_property_fail(self):
required = ['id', 'size', 'volumes', 'type']
for prop in required:
fake = copy.deepcopy(self.fake_scheme)
del fake[0][prop]
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, fake, 'ironic')
fake = copy.deepcopy(self.payload)
partitions = fake['partitions']
del partitions[0][prop]
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data, fake)
def test_validate_missed_volume_property(self):
required = ['type', 'size', 'vg']
for prop in required:
fake = copy.deepcopy(self.fake_scheme)
del fake[0]['volumes'][3][prop]
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, fake, 'ironic')
fake = copy.deepcopy(self.payload)
partitions = fake['partitions']
del partitions[0]['volumes'][3][prop]
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data, fake)
def test_disks_keep_data_flag_type(self):
partitions = self.payload['partitions']
partitions[0]['volumes'][1]['keep_data'] = "True"
self.assertRaises(
errors.WrongInputDataError, ironic.Ironic.validate_data,
self.payload)
@staticmethod
def _get_disks(payload):
return payload['partitions']

View File

@ -1,205 +0,0 @@
# 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
import unittest2
from bareon.drivers.data import ks_spaces_validator as kssv
from bareon 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(unittest2.TestCase):
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:])
@unittest2.skip("Fix after cray rebase")
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)

View File

@ -16,10 +16,10 @@ import copy
import unittest2
from bareon.drivers.data import ks_spaces_validator as kssv
from bareon.drivers.data import nailgun
from bareon import errors
SAMPLE_SCHEME = [
SAMPLE_CHUNK_SPACES = [
{
"name": "sda",
"extra": [
@ -181,71 +181,96 @@ SAMPLE_SCHEME = [
}
]
SAMPLE_PAYLOAD = {
'ks_meta': {
'pm_data': {
'ks_spaces': SAMPLE_CHUNK_SPACES
}
}
}
class TestKSSpacesValidator(unittest2.TestCase):
class TestNailgunDataValidator(unittest2.TestCase):
def setUp(self):
super(TestKSSpacesValidator, self).setUp()
self.fake_scheme = copy.deepcopy(SAMPLE_SCHEME)
super(TestNailgunDataValidator, self).setUp()
self.payload = copy.deepcopy(SAMPLE_PAYLOAD)
self.payload_spaces = self._get_spaces(self.payload)
def test_validate_ok(self):
kssv.validate(self.fake_scheme, 'nailgun')
def test_no_error(self):
nailgun.Nailgun.validate_data(self.payload)
def test_validate_jsoschema_fail(self):
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, [{}], 'nailgun')
def test_fail(self):
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data, {})
def test_validate_no_disks_fail(self):
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme[-2:], 'nailgun')
def test_disks_no_disks_fail(self):
self.payload_spaces[:-2] = []
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
self.payload)
def test_validate_free_space_type_fail(self):
def test_disks_free_space_type_fail(self):
incorrect_values_for_free_space = [
False, True, '0', '1', None, object
]
for value in incorrect_values_for_free_space:
self.fake_scheme[0]['free_space'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'nailgun')
self.payload_spaces[0]['free_space'] = value
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
self.payload)
def test_validate_volume_type_fail(self):
def test_disks_volume_type_fail(self):
incorrect_values_for_type = [
False, True, 0, 1, None, object
]
for value in incorrect_values_for_type:
self.fake_scheme[0]['volumes'][1]['type'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'nailgun')
self.payload_spaces[0]['volumes'][1]['type'] = value
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
self.payload)
def test_validate_volume_size_fail(self):
def test_disks_volume_size_fail(self):
incorrect_values_for_size = [
False, True, '0', '1', None, object
]
for value in incorrect_values_for_size:
self.fake_scheme[0]['volumes'][1]['size'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'nailgun')
self.payload_spaces[0]['volumes'][1]['size'] = value
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
self.payload)
def test_validate_device_id_fail(self):
def test_disks_device_id_fail(self):
incorrect_values_for_id = [
False, True, 0, 1, None, object
]
for value in incorrect_values_for_id:
self.fake_scheme[0]['id'] = value
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, self.fake_scheme, 'nailgun')
self.payload_spaces[0]['id'] = value
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
self.payload)
def test_validate_missed_property(self):
def test_disks_missed_property(self):
required = ['id', 'size', 'volumes', 'type', 'free_space', 'volumes']
for prop in required:
fake = copy.deepcopy(self.fake_scheme)
del fake[0][prop]
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, fake, 'nailgun')
payload = copy.deepcopy(self.payload)
spaces = self._get_spaces(payload)
del spaces[0][prop]
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
payload)
def test_validate_missed_volume_property(self):
def test_disks_missed_volume_property(self):
required = ['type', 'size', 'vg']
for prop in required:
fake = copy.deepcopy(self.fake_scheme)
del fake[0]['volumes'][3][prop]
self.assertRaises(errors.WrongPartitionSchemeError,
kssv.validate, fake, 'nailgun')
payload = copy.deepcopy(self.payload)
spaces = self._get_spaces(payload)
del spaces[0]['volumes'][3][prop]
self.assertRaises(
errors.WrongInputDataError, nailgun.Nailgun.validate_data,
payload)
@staticmethod
def _get_spaces(payload):
payload = payload['ks_meta']
payload = payload['pm_data']
return payload['ks_spaces']

View File

@ -30,25 +30,23 @@ from bareon.tests import base
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({})
driver = simple.NailgunSimpleDriver(self._minimal_payload())
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',
},
]
}
payload = self._minimal_payload()
payload['partitioning'] = {
'lvs': [
{
'name': 'lv-name',
'size': 12345,
'vgname': 'vg-name',
},
]
}
driver = simple.NailgunSimpleDriver(lv_data)
driver = simple.NailgunSimpleDriver(payload)
lv = driver.partition_scheme.lvs[0]
assert len(driver.partition_scheme.lvs) == 1
assert isinstance(lv, objects.LV)
@ -57,19 +55,18 @@ class TestObjectDeserialization(unittest2.TestCase):
assert lv.vgname == 'vg-name'
def test_pv_data_is_loaded(self):
pv_data = {
'partitioning': {
'pvs': [
{
'metadatacopies': 2,
'metadatasize': 28,
'name': '/dev/sda5'
},
]
}
payload = self._minimal_payload()
payload['partitioning'] = {
'pvs': [
{
'metadatacopies': 2,
'metadatasize': 28,
'name': '/dev/sda5'
},
]
}
driver = simple.NailgunSimpleDriver(pv_data)
driver = simple.NailgunSimpleDriver(payload)
pv = driver.partition_scheme.pvs[0]
assert len(driver.partition_scheme.pvs) == 1
assert isinstance(pv, objects.PV)
@ -78,22 +75,21 @@ class TestObjectDeserialization(unittest2.TestCase):
assert pv.metadatasize == 28
def test_vg_data_is_loaded(self):
vg_data = {
'partitioning': {
'vgs': [
{
'name': 'image',
'pvnames': [
'/dev/sda6',
'/dev/sdb3',
'/dev/sdc3',
]
},
]
}
payload = self._minimal_payload()
payload['partitioning'] = {
'vgs': [
{
'name': 'image',
'pvnames': [
'/dev/sda6',
'/dev/sdb3',
'/dev/sdc3',
]
},
]
}
driver = simple.NailgunSimpleDriver(vg_data)
driver = simple.NailgunSimpleDriver(payload)
vg = driver.partition_scheme.vgs[0]
assert len(driver.partition_scheme.vgs) == 1
assert isinstance(vg, objects.VG)
@ -108,21 +104,20 @@ class TestObjectDeserialization(unittest2.TestCase):
)
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'
},
]
}
payload = self._minimal_payload()
payload['partitioning'] = {
'fss': [
{
'device': '/dev/sda3',
'fs_label': 'some-label',
'fs_options': 'some-options',
'fs_type': 'ext2',
'mount': '/boot'
},
]
}
driver = simple.NailgunSimpleDriver(fs_data)
driver = simple.NailgunSimpleDriver(payload)
fs = driver.partition_scheme.fss[0]
assert len(driver.partition_scheme.fss) == 1
assert isinstance(fs, objects.FS)
@ -133,34 +128,33 @@ class TestObjectDeserialization(unittest2.TestCase):
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'
},
]
},
]
}
payload = self._minimal_payload()
payload['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)
driver = simple.NailgunSimpleDriver(payload)
parted = driver.partition_scheme.parteds[0]
partition = parted.partitions[0]
assert len(driver.partition_scheme.parteds) == 1
@ -179,26 +173,25 @@ class TestObjectDeserialization(unittest2.TestCase):
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',
]
},
]
}
payload = self._minimal_payload()
payload['partitioning'] = {
'mds': [
{
'name': 'some-raid',
'level': 1,
'devices': [
'/dev/sda',
'/dev/sdc',
],
'spares': [
'/dev/sdb',
'/dev/sdd',
]
},
]
}
driver = simple.NailgunSimpleDriver(md_data)
driver = simple.NailgunSimpleDriver(payload)
md = driver.partition_scheme.mds[0]
assert len(driver.partition_scheme.mds) == 1
assert isinstance(md, objects.MD)
@ -207,6 +200,26 @@ class TestObjectDeserialization(unittest2.TestCase):
self.assertItemsEqual(md.devices, ['/dev/sda', '/dev/sdc'])
self.assertItemsEqual(md.spares, ['/dev/sdb', '/dev/sdd'])
@staticmethod
def _minimal_payload():
return {
'ks_meta': {
'pm_data': {
'ks_spaces': [
{
'type': 'disk',
'id': 'dummy-disk-id',
'name': 'dummy0',
'free_space': 0,
'size': 128,
'extra': [],
'volumes': []
}
]
}
}
}
@requests_mock.mock()
class TestFullDataRead(unittest2.TestCase):

View File

@ -22,6 +22,11 @@ from bareon.utils import utils
LOG = logging.getLogger(__name__)
PARTITION_ALIGMENT = ('none', 'cylinder', 'minimal', 'optimal')
KiB = 1024
MiB = KiB * 1024
GiB = MiB * 1024
TiB = GiB * 1024
def parse_partition_info(parted_output):
lines = parted_output.split('\n')

View File

@ -1,6 +1,6 @@
[metadata]
name = bareon
version = 0.0.1.a3
version = 0.0.2
author = Mirantis
author-email = openstack-dev@lists.openstack.org
summary = Bareon