summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--devstack/lib/ironic2
-rw-r--r--ironic/common/driver_factory.py15
-rw-r--r--ironic/drivers/modules/deploy_utils.py3
-rw-r--r--ironic/tests/unit/common/test_driver_factory.py166
-rw-r--r--releasenotes/notes/fix-disk-identifier-overwrite-42b33a5a0f7742d8.yaml5
-rw-r--r--releasenotes/notes/fix-updating-node-driver-to-classic-16b0d5ba47e74d10.yaml4
-rw-r--r--requirements.txt2
7 files changed, 188 insertions, 9 deletions
diff --git a/devstack/lib/ironic b/devstack/lib/ironic
index 2292da6e3..4474f6372 100644
--- a/devstack/lib/ironic
+++ b/devstack/lib/ironic
@@ -1612,6 +1612,8 @@ function configure_iptables {
# nodes boot from TFTP and callback to the API server listening on $HOST_IP
sudo iptables -I INPUT -d $IRONIC_TFTPSERVER_IP -p udp --dport 69 -j ACCEPT || true
sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
+ sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
+ sudo iptables -I FORWARD -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true
if is_deployed_by_agent; then
# agent ramdisk gets instance image from swift
sudo iptables -I INPUT -d $HOST_IP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true
diff --git a/ironic/common/driver_factory.py b/ironic/common/driver_factory.py
index a45da9386..c4ba83aef 100644
--- a/ironic/common/driver_factory.py
+++ b/ironic/common/driver_factory.py
@@ -253,13 +253,23 @@ def check_and_update_node_interfaces(node, driver_or_hw_type=None):
# for classic drivers, none are allowed except for network & storage.
not_allowed_ifaces = driver_base.ALL_INTERFACES - set(factories)
+ updates = node.obj_what_changed()
+ # Result - whether the node object was modified
+ result = False
+
bad_interface_fields = []
for iface in not_allowed_ifaces:
field_name = '%s_interface' % iface
+ # NOTE(vsaienko): reset *_interface fields that shouldn't exist for
+ # classic driver, only when driver was changed and field not set
+ # explicitly
+ if 'driver' in updates and field_name not in updates:
+ setattr(node, field_name, None)
+ result = True
# NOTE(dtantsur): objects raise NotImplementedError on accessing fields
# that are known, but missing from an object. Thus, we cannot just use
# getattr(node, field_name, None) here.
- if field_name in node:
+ elif field_name in node:
impl_name = getattr(node, field_name)
if impl_name is not None:
bad_interface_fields.append(field_name)
@@ -268,9 +278,6 @@ def check_and_update_node_interfaces(node, driver_or_hw_type=None):
raise exception.MustBeNone(node=node.uuid, driver=node.driver,
node_fields=','.join(bad_interface_fields))
- # Result - whether the node object was modified
- result = False
-
# Walk through all dynamic interfaces and check/update them
for iface in factories:
field_name = '%s_interface' % iface
diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py
index ce7da1971..4cf11d1a6 100644
--- a/ironic/drivers/modules/deploy_utils.py
+++ b/ironic/drivers/modules/deploy_utils.py
@@ -401,12 +401,13 @@ def deploy_disk_image(address, port, iqn, lun,
with _iscsi_setup_and_handle_errors(address, port, iqn,
lun) as dev:
disk_utils.populate_image(image_path, dev)
- disk_identifier = disk_utils.get_disk_identifier(dev)
if configdrive:
disk_utils.create_config_drive_partition(node_uuid, dev,
configdrive)
+ disk_identifier = disk_utils.get_disk_identifier(dev)
+
return {'disk identifier': disk_identifier}
diff --git a/ironic/tests/unit/common/test_driver_factory.py b/ironic/tests/unit/common/test_driver_factory.py
index b4e370513..53e5ed0ea 100644
--- a/ironic/tests/unit/common/test_driver_factory.py
+++ b/ironic/tests/unit/common/test_driver_factory.py
@@ -273,20 +273,22 @@ class CheckAndUpdateNodeInterfacesTestCase(db_base.DbTestCase):
# "none" dhcp provider corresponds to "noop" network_interface
self.assertEqual('noop', node.network_interface)
- def test_valid_interfaces(self):
+ def test_create_node_classic_driver_valid_interfaces(self):
node = obj_utils.get_test_node(self.context, driver='fake',
network_interface='noop',
storage_interface='noop')
self.assertFalse(driver_factory.check_and_update_node_interfaces(node))
+ self.assertEqual('noop', node.network_interface)
+ self.assertEqual('noop', node.storage_interface)
- def test_invalid_network_interface(self):
+ def test_create_node_classic_driver_invalid_network_interface(self):
node = obj_utils.get_test_node(self.context, driver='fake',
network_interface='banana')
self.assertRaises(exception.InterfaceNotFoundInEntrypoint,
driver_factory.check_and_update_node_interfaces,
node)
- def test_classic_setting_interfaces(self):
+ def test_create_node_classic_driver_not_allowed_interfaces_set(self):
# Cannot set these node interfaces for classic driver
no_set_interfaces = (drivers_base.ALL_INTERFACES -
set(['network', 'storage']))
@@ -294,13 +296,171 @@ class CheckAndUpdateNodeInterfacesTestCase(db_base.DbTestCase):
iface_name = '%s_interface' % iface
node_kwargs = {'uuid': uuidutils.generate_uuid(),
iface_name: 'fake'}
+ node = obj_utils.get_test_node(self.context, driver='fake',
+ **node_kwargs)
+ self.assertRaisesRegex(
+ exception.InvalidParameterValue,
+ 'driver fake.*%s' % iface_name,
+ driver_factory.check_and_update_node_interfaces, node)
+
+ def test_create_node_classic_driver_no_interfaces_set(self):
+ no_set_interfaces = (drivers_base.ALL_INTERFACES -
+ set(['network', 'storage']))
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.get_test_node(self.context, driver='fake',
+ **node_kwargs)
+ driver_factory.check_and_update_node_interfaces(node)
+
+ for iface in no_set_interfaces:
+ iface_name = '%s_interface' % iface
+ self.assertIsNone(getattr(node, iface_name))
+
+ def _get_valid_default_interface_name(self, iface):
+ i_name = 'fake'
+ # there is no 'fake' network interface
+ if iface == 'network':
+ i_name = 'noop'
+ return i_name
+
+ def _set_config_interface_options_hardware_type(self):
+ for iface in drivers_base.ALL_INTERFACES:
+ i_name = self._get_valid_default_interface_name(iface)
+ config_kwarg = {'enabled_%s_interfaces' % iface: [i_name],
+ 'default_%s_interface' % iface: i_name}
+ self.config(**config_kwarg)
+
+ def test_create_node_dynamic_driver_invalid_network_interface(self):
+ self._set_config_interface_options_hardware_type()
+
+ node = obj_utils.get_test_node(self.context, driver='fake-hardware',
+ network_interface='banana')
+ self.assertRaises(exception.InterfaceNotFoundInEntrypoint,
+ driver_factory.check_and_update_node_interfaces,
+ node)
+
+ def test_create_node_dynamic_driver_interfaces_set(self):
+ self._set_config_interface_options_hardware_type()
+
+ for iface in drivers_base.ALL_INTERFACES:
+ iface_name = '%s_interface' % iface
+ i_name = self._get_valid_default_interface_name(iface)
+ node_kwargs = {'uuid': uuidutils.generate_uuid(),
+ iface_name: i_name}
+ node = obj_utils.get_test_node(
+ self.context, driver='fake-hardware', **node_kwargs)
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual(i_name, getattr(node, iface_name))
+
+ def test_update_node_set_classic_driver_and_not_allowed_interfaces(self):
+ """Update driver to classic and interfaces specified"""
+ not_allowed_interfaces = (drivers_base.ALL_INTERFACES -
+ set(['network', 'storage']))
+ self.config(enabled_drivers=['fake', 'fake_agent'])
+ for iface in not_allowed_interfaces:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
node = obj_utils.create_test_node(self.context, driver='fake',
**node_kwargs)
+ setattr(node, iface_name, 'fake')
+ node.driver = 'fake_agent'
self.assertRaisesRegex(
exception.InvalidParameterValue,
'driver fake.*%s' % iface_name,
driver_factory.check_and_update_node_interfaces, node)
+ def test_update_node_set_classic_driver_and_allowed_interfaces(self):
+ """Update driver to classic and interfaces specified"""
+ self._set_config_interface_options_hardware_type()
+ self.config(enabled_drivers=['fake', 'fake_agent'])
+ for iface in ['network', 'storage']:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.create_test_node(self.context, driver='fake',
+ **node_kwargs)
+ i_name = self._get_valid_default_interface_name(iface)
+ setattr(node, iface_name, i_name)
+ node.driver = 'fake_agent'
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual(i_name, getattr(node, iface_name))
+
+ def test_update_node_set_classic_driver_unset_interfaces(self):
+ """Update driver to classic and set interfaces to None"""
+ no_set_interfaces = (drivers_base.ALL_INTERFACES -
+ set(['network', 'storage']))
+ self.config(enabled_drivers=['fake', 'fake_agent'])
+ for iface in no_set_interfaces:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.create_test_node(self.context, driver='fake',
+ **node_kwargs)
+ setattr(node, iface_name, None)
+ node.driver = 'fake_agent'
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual('fake_agent', node.driver)
+ self.assertIsNone(getattr(node, iface_name))
+
+ def test_update_node_classic_driver_unset_interfaces(self):
+ """Update interfaces to None for node with classic driver"""
+ no_set_interfaces = (drivers_base.ALL_INTERFACES -
+ set(['network', 'storage']))
+ self.config(enabled_drivers=['fake', 'fake_agent'])
+ for iface in no_set_interfaces:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.create_test_node(self.context, driver='fake',
+ **node_kwargs)
+ setattr(node, iface_name, None)
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertIsNone(getattr(node, iface_name))
+
+ def test_update_node_set_classic_driver_no_interfaces(self):
+ """Update driver to classic no interfaces specified"""
+ self._set_config_interface_options_hardware_type()
+ no_set_interfaces = (drivers_base.ALL_INTERFACES -
+ set(['network', 'storage']))
+ for iface in no_set_interfaces:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node_kwargs[iface_name] = 'fake'
+ node = obj_utils.create_test_node(self.context,
+ driver='fake-hardware',
+ **node_kwargs)
+ node.driver = 'fake'
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual('fake', node.driver)
+ self.assertIsNone(getattr(node, iface_name))
+ self.assertEqual('noop', node.network_interface)
+
+ def test_update_node_set_dynamic_driver_and_interfaces(self):
+ """Update driver to dynamic and interfaces specified"""
+ self._set_config_interface_options_hardware_type()
+
+ for iface in drivers_base.ALL_INTERFACES:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.create_test_node(self.context, driver='fake',
+ **node_kwargs)
+ i_name = self._get_valid_default_interface_name(iface)
+ setattr(node, iface_name, i_name)
+ node.driver = 'fake-hardware'
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual(i_name, getattr(node, iface_name))
+
+ def test_node_update_dynamic_driver_set_interfaces(self):
+ """Update interfaces for node with dynamic driver"""
+ self._set_config_interface_options_hardware_type()
+ for iface in drivers_base.ALL_INTERFACES:
+ iface_name = '%s_interface' % iface
+ node_kwargs = {'uuid': uuidutils.generate_uuid()}
+ node = obj_utils.create_test_node(self.context,
+ driver='fake-hardware',
+ **node_kwargs)
+
+ i_name = self._get_valid_default_interface_name(iface)
+ setattr(node, iface_name, i_name)
+ driver_factory.check_and_update_node_interfaces(node)
+ self.assertEqual(i_name, getattr(node, iface_name))
+
class DefaultInterfaceTestCase(db_base.DbTestCase):
def setUp(self):
diff --git a/releasenotes/notes/fix-disk-identifier-overwrite-42b33a5a0f7742d8.yaml b/releasenotes/notes/fix-disk-identifier-overwrite-42b33a5a0f7742d8.yaml
new file mode 100644
index 000000000..6404bc15e
--- /dev/null
+++ b/releasenotes/notes/fix-disk-identifier-overwrite-42b33a5a0f7742d8.yaml
@@ -0,0 +1,5 @@
+---
+fixes:
+ - Fix handling of whole disk images with 0x00000000 disk identifier.
+ Instances failed to boot as the identifier in boot config was overwritten
+ during config drive creation. See https://bugs.launchpad.net/ironic/+bug/1685093
diff --git a/releasenotes/notes/fix-updating-node-driver-to-classic-16b0d5ba47e74d10.yaml b/releasenotes/notes/fix-updating-node-driver-to-classic-16b0d5ba47e74d10.yaml
new file mode 100644
index 000000000..f1cf8cd88
--- /dev/null
+++ b/releasenotes/notes/fix-updating-node-driver-to-classic-16b0d5ba47e74d10.yaml
@@ -0,0 +1,4 @@
+---
+fixes:
+ - Fixes failure to update a node's driver from a hardware type to
+ a classic driver.
diff --git a/requirements.txt b/requirements.txt
index 54cb24f1c..849c9e8ec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr<2.0.0,>=1.8 # Apache-2.0
+pbr>=1.8 # Apache-2.0
SQLAlchemy<1.1.0,>=1.0.10 # MIT
alembic>=0.8.10 # MIT
automaton>=0.5.0 # Apache-2.0