Add parse_root_device_hints to utils.py

This patch is adding a function called parse_root_device_hints to the
utils.py module. This function is responsible for parsing the root
device hints dictionary from the node's properties attribute.

Both Ironic and Ironic Python Agent project have similar functions so
adding it to ironic-lib would make it easier to share code between both
projects and fix bugs in only one place.

Change-Id: Ida6d20d1fdb40e50fe33ffec1c953286d4cbc2b7
Partial-Bug: #1605631
This commit is contained in:
Lucas Alvares Gomes 2016-07-22 15:42:16 +01:00
parent 64dc8b64c7
commit 7aac631fbc
2 changed files with 111 additions and 0 deletions

View File

@ -279,3 +279,52 @@ class IsHttpUrlTestCase(test_base.BaseTestCase):
self.assertTrue(utils.is_http_url('HTTPS://127.3.2.1'))
self.assertFalse(utils.is_http_url('Zm9vYmFy'))
self.assertFalse(utils.is_http_url('11111111'))
class ParseRootDeviceTestCase(test_base.BaseTestCase):
def setUp(self):
super(ParseRootDeviceTestCase, self).setUp()
self.root_device = {
'wwn': '123456', 'model': 'foo-model', 'size': 12345,
'serial': 'foo-serial', 'vendor': 'foo-vendor', 'name': '/dev/sda',
'wwn_with_extension': '123456111', 'wwn_vendor_extension': '111',
'rotational': True}
def test_parse_root_device_hints(self):
result = utils.parse_root_device_hints(self.root_device)
self.assertEqual(self.root_device, result)
def test_parse_root_device_hints_no_hints(self):
result = utils.parse_root_device_hints({})
self.assertIsNone(result)
def test_parse_root_device_hints_convert_size(self):
result = utils.parse_root_device_hints({'size': '12345'})
self.assertEqual({'size': 12345}, result)
def test_parse_root_device_hints_invalid_size(self):
for value in ('not-int', -123, 0):
self.assertRaises(ValueError, utils.parse_root_device_hints,
{'size': value})
def _parse_root_device_hints_convert_rotational(self, values,
expected_value):
for value in values:
result = utils.parse_root_device_hints({'rotational': value})
self.assertEqual({'rotational': expected_value}, result)
def test_parse_root_device_hints_convert_rotational(self):
self._parse_root_device_hints_convert_rotational(
(True, 'true', 'on', 'y', 'yes'), True)
self._parse_root_device_hints_convert_rotational(
(False, 'false', 'off', 'n', 'no'), False)
def test_parse_root_device_hints_invalid_rotational(self):
self.assertRaises(ValueError, utils.parse_root_device_hints,
{'rotational': 'not-bool'})
def test_parse_root_device_hints_non_existent_hint(self):
self.assertRaises(ValueError, utils.parse_root_device_hints,
{'non-existent': 'foo'})

View File

@ -18,6 +18,7 @@
"""Utilities and helper functions."""
import copy
import errno
import logging
import os
@ -25,7 +26,9 @@ import os
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_utils import excutils
from oslo_utils import strutils
from ironic_lib.common.i18n import _
from ironic_lib.common.i18n import _LE
from ironic_lib.common.i18n import _LW
from ironic_lib import exception
@ -43,6 +46,11 @@ CONF.register_opts(utils_opts, group='ironic_lib')
LOG = logging.getLogger(__name__)
VALID_ROOT_DEVICE_HINTS = set(('size', 'model', 'wwn', 'serial', 'vendor',
'wwn_with_extension', 'wwn_vendor_extension',
'name', 'rotational'))
def execute(*cmd, **kwargs):
"""Convenience wrapper around oslo's execute() method.
@ -159,3 +167,57 @@ def is_http_url(url):
def list_opts():
"""Entry point for oslo-config-generator."""
return [('ironic_lib', utils_opts)]
def parse_root_device_hints(root_device):
"""Parse the root_device property of a node.
Parses and validates the root_device property of a node. These are
hints for how a node's root device is created. The 'size' hint
should be a positive integer. The 'rotational' hint should be a
Boolean value.
:param root_device: the root_device dictionary from the node's property.
:returns: a dictionary with the root device hints parsed or
None if there are no hints.
:raises: ValueError, if some information is invalid.
"""
if not root_device:
return
root_device = copy.deepcopy(root_device)
invalid_hints = set(root_device) - VALID_ROOT_DEVICE_HINTS
if invalid_hints:
raise ValueError(
_('The hints "%(invalid_hints)s" are invalid. '
'Valid hints are: "%(valid_hints)s"') %
{'invalid_hints': ', '.join(invalid_hints),
'valid_hints': ', '.join(VALID_ROOT_DEVICE_HINTS)})
if 'size' in root_device:
try:
size = int(root_device['size'])
except ValueError:
raise ValueError(
_('Root device hint "size" is not an integer value. '
'Current value: %s') % root_device['size'])
if size <= 0:
raise ValueError(
_('Root device hint "size" should be a positive integer. '
'Current value: %d') % size)
root_device['size'] = size
if 'rotational' in root_device:
try:
root_device['rotational'] = strutils.bool_from_string(
root_device['rotational'], strict=True)
except ValueError:
raise ValueError(
_('Root device hint "rotational" is not a Boolean value. '
'Current value: %s') % root_device['rotational'])
return root_device