Allow missing local_gb if root_disk_size is provided

Change-Id: Ieb89044b1f3243cc09b49f3afbca96c7602b0b06
This commit is contained in:
Dmitry Tantsur 2018-05-15 18:29:07 +02:00
parent 8c7870f6ad
commit 23d605c212
5 changed files with 76 additions and 40 deletions

View File

@ -63,3 +63,7 @@ class InvalidImage(Error):
class InvalidNetwork(Error):
"""Requested network is invalid and cannot be used."""
class UnknownRootDiskSize(Error):
"""Cannot determine the root disk size."""

View File

@ -180,22 +180,6 @@ class ValidationFilter(Filter):
self._failed_validation.append(message)
return False
try:
assert int(node.properties['local_gb']) > 0
except KeyError:
message = 'No local_gb for node %s' % _utils.log_node(node)
LOG.warning(message)
self._failed_validation.append(message)
return False
except (TypeError, AssertionError):
message = ('The local_gb for node %(node)s is invalid: '
'expected positive integer, got %(value)s' %
{'node': _utils.log_node(node),
'value': node.properties['local_gb']})
LOG.warning(message)
self._failed_validation.append(message)
return False
return True
def fail(self):

View File

@ -19,6 +19,8 @@ import os
import shutil
import tempfile
from metalsmith import _exceptions
def log_node(node):
if node.name:
@ -69,6 +71,19 @@ def get_root_disk(root_disk_size, node):
raise ValueError("The root_disk_size argument must be "
"a positive integer, got %d" % root_disk_size)
else:
try:
assert int(node.properties['local_gb']) > 0
except KeyError:
raise _exceptions.UnknownRootDiskSize(
'No local_gb for node %s and no root disk size requested' %
log_node(node))
except (TypeError, ValueError, AssertionError):
raise _exceptions.UnknownRootDiskSize(
'The local_gb for node %(node)s is invalid: '
'expected positive integer, got %(value)s' %
{'node': log_node(node),
'value': node.properties['local_gb']})
# allow for partitioning and config drive
root_disk_size = int(node.properties['local_gb']) - 1

View File

@ -102,6 +102,32 @@ class TestProvisionNode(Base):
self.assertFalse(self.api.release_node.called)
self.assertFalse(self.api.delete_port.called)
def test_with_root_disk_size(self):
self.pr.provision_node(self.node, 'image', ['network'],
root_disk_size=50)
self.api.create_port.assert_called_once_with(
network_id=self.api.get_network.return_value.id)
self.api.attach_port_to_node.assert_called_once_with(
self.node.uuid, self.api.create_port.return_value.id)
image = self.api.get_image_info.return_value
updates = {'/instance_info/ramdisk': image.ramdisk_id,
'/instance_info/kernel': image.kernel_id,
'/instance_info/image_source': image.id,
'/instance_info/root_gb': 50,
'/instance_info/capabilities': {'boot_option': 'local'},
'/extra/metalsmith_created_ports': [
self.api.create_port.return_value.id
]}
self.api.update_node.assert_called_once_with(self.node, updates)
self.api.validate_node.assert_called_once_with(self.node,
validate_deploy=True)
self.api.node_action.assert_called_once_with(self.node, 'active',
configdrive=mock.ANY)
self.assertFalse(self.api.wait_for_node_state.called)
self.assertFalse(self.api.release_node.called)
self.assertFalse(self.api.delete_port.called)
def test_with_wait(self):
self.api.get_port.return_value = mock.Mock(
spec=['fixed_ips'],
@ -239,6 +265,35 @@ class TestProvisionNode(Base):
self.assertFalse(self.api.create_port.called)
self.assertFalse(self.api.node_action.called)
def test_no_local_gb(self):
self.node.properties = {}
self.assertRaises(_exceptions.UnknownRootDiskSize,
self.pr.provision_node,
self.node, 'image', ['network'])
self.assertFalse(self.api.create_port.called)
self.assertFalse(self.api.node_action.called)
def test_invalid_local_gb(self):
for value in (None, 'meow', -42, []):
self.node.properties = {'local_gb': value}
self.assertRaises(_exceptions.UnknownRootDiskSize,
self.pr.provision_node,
self.node, 'image', ['network'])
self.assertFalse(self.api.create_port.called)
self.assertFalse(self.api.node_action.called)
def test_invalid_root_disk_size(self):
self.assertRaises(TypeError,
self.pr.provision_node,
self.node, 'image', ['network'],
root_disk_size={})
self.assertRaises(ValueError,
self.pr.provision_node,
self.node, 'image', ['network'],
root_disk_size=0)
self.assertFalse(self.api.create_port.called)
self.assertFalse(self.api.node_action.called)
class TestUnprovisionNode(Base):

View File

@ -173,33 +173,11 @@ class TestValidationFilter(testtools.TestCase):
{'profile': 'compute'})
def test_pass(self):
node = mock.Mock(properties={'local_gb': 100},
spec=['properties', 'uuid', 'name'])
node = mock.Mock(spec=['uuid', 'name'])
self.assertTrue(self.fltr(node))
def test_fail_without_local_gb(self):
node = mock.Mock(properties={},
spec=['properties', 'uuid', 'name'])
self.assertFalse(self.fltr(node))
self.assertRaisesRegex(_exceptions.ValidationFailed,
'All available nodes have failed validation: '
'No local_gb for node',
self.fltr.fail)
def test_fail_malformed_local_gb(self):
node = mock.Mock(properties={'local_gb': []},
spec=['properties', 'uuid', 'name'])
self.assertFalse(self.fltr(node))
self.assertRaisesRegex(_exceptions.ValidationFailed,
'All available nodes have failed validation: '
'The local_gb for node .* is invalid',
self.fltr.fail)
def test_fail_validation(self):
node = mock.Mock(properties={'local_gb': 100},
spec=['properties', 'uuid', 'name'])
node = mock.Mock(spec=['uuid', 'name'])
self.api.validate_node.side_effect = RuntimeError('boom')
self.assertFalse(self.fltr(node))