diff options
author | Zuul <zuul@review.opendev.org> | 2021-03-08 03:19:40 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2021-03-08 03:19:40 +0000 |
commit | 42df92e7dd127e6a7308a4f7a498b055092203b4 (patch) | |
tree | 185a7410b381fd5b6d785d984c506886802168c2 | |
parent | d0ae891d9b9ba61e7721bc4234788e0390c0b492 (diff) | |
parent | a165fe3264fd8f3a4bd7af9d7a958b9b3abf099f (diff) | |
download | ironic-42df92e7dd127e6a7308a4f7a498b055092203b4.tar.gz |
Merge "Allow instance_info to override node interface"
-rw-r--r-- | doc/source/admin/index.rst | 1 | ||||
-rw-r--r-- | doc/source/admin/node-interface-override.rst | 22 | ||||
-rw-r--r-- | ironic/common/driver_factory.py | 27 | ||||
-rw-r--r-- | ironic/tests/unit/common/test_driver_factory.py | 31 | ||||
-rw-r--r-- | releasenotes/notes/instance-info-interface-override-287c7fcff1081469.yaml | 5 |
5 files changed, 78 insertions, 8 deletions
diff --git a/doc/source/admin/index.rst b/doc/source/admin/index.rst index 3ca6ec26e..de260385e 100644 --- a/doc/source/admin/index.rst +++ b/doc/source/admin/index.rst @@ -30,6 +30,7 @@ the services. Node Multi-Tenancy <node-multitenancy> Fast-Track Deployment <fast-track> Booting a Ramdisk or an ISO <ramdisk-boot> + Node Interface Override <node-interface-override> Drivers, Hardware Types and Hardware Interfaces ----------------------------------------------- diff --git a/doc/source/admin/node-interface-override.rst b/doc/source/admin/node-interface-override.rst new file mode 100644 index 000000000..907c8a00c --- /dev/null +++ b/doc/source/admin/node-interface-override.rst @@ -0,0 +1,22 @@ +======================= +Node Interface Override +======================= + +Non-admins with temporary access to a node, may wish to specify different +node interfaces. However, allowing them to set these interface values is +problematic, as there is no automated way to ensure that the original +interface values are restored. + +This guide details a method for temporarily overriding a node interface +value. + +Overriding a Node Interface +=========================== + +In order to temporarily override a node interface, simply set the +appropriate value in `instance_info`. For example, if you'd like to +override a node's storage interface, run the following:: + + baremetal node set --instance-info storage_interface=cinder node-1 + +`instance_info` values persist until after a node is cleaned. diff --git a/ironic/common/driver_factory.py b/ironic/common/driver_factory.py index 077598019..37ce123fe 100644 --- a/ironic/common/driver_factory.py +++ b/ironic/common/driver_factory.py @@ -69,7 +69,9 @@ def _attach_interfaces_to_driver(bare_driver, node, hw_type): the requested implementation is not compatible with it. """ for iface in _INTERFACE_LOADERS: - impl_name = getattr(node, '%s_interface' % iface) + iface_name = '%s_interface' % iface + impl_name = node.instance_info.get(iface_name, + getattr(node, iface_name)) impl = get_interface(hw_type, iface, impl_name) setattr(bare_driver, iface, impl) @@ -204,20 +206,29 @@ def check_and_update_node_interfaces(node, hw_type=None): # 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. + set_default = True + if 'instance_info' in node and field_name in node.instance_info: + impl_name = node.instance_info.get(field_name) + if impl_name is not None: + # Check that the provided value is correct for this type + get_interface(hw_type, iface, impl_name) + set_default = False + if field_name in node: impl_name = getattr(node, field_name) if impl_name is not None: # Check that the provided value is correct for this type get_interface(hw_type, iface, impl_name) - # Not changing the result, proceeding with the next interface - continue + set_default = False - impl_name = default_interface(hw_type, iface, - driver_name=node.driver, node=node.uuid) + if set_default: + impl_name = default_interface(hw_type, iface, + driver_name=node.driver, + node=node.uuid) - # Set the calculated default and set result to True - setattr(node, field_name, impl_name) - result = True + # Set the calculated default and set result to True + setattr(node, field_name, impl_name) + result = True return result diff --git a/ironic/tests/unit/common/test_driver_factory.py b/ironic/tests/unit/common/test_driver_factory.py index 3d9fb3e90..77626a084 100644 --- a/ironic/tests/unit/common/test_driver_factory.py +++ b/ironic/tests/unit/common/test_driver_factory.py @@ -214,6 +214,26 @@ class CheckAndUpdateNodeInterfacesTestCase(db_base.DbTestCase): driver_factory.check_and_update_node_interfaces, node) + def test_create_node_valid_network_interface_instance_info_override(self): + instance_info = {'network_interface': 'noop', + 'storage_interface': 'noop'} + node = obj_utils.get_test_node(self.context, + instance_info=instance_info) + self.assertTrue(driver_factory.check_and_update_node_interfaces(node)) + self.assertIsNone(node.network_interface) + self.assertIsNone(node.storage_interface) + self.assertEqual('noop', node.instance_info.get('network_interface')) + self.assertEqual('noop', node.instance_info.get('storage_interface')) + + def test_create_node_invalid_network_interface_instance_info_override( + self): + instance_info = {'network_interface': 'banana'} + node = obj_utils.get_test_node(self.context, + instance_info=instance_info) + self.assertRaises(exception.InterfaceNotFoundInEntrypoint, + driver_factory.check_and_update_node_interfaces, + node) + def _get_valid_default_interface_name(self, iface): i_name = 'fake' # there is no 'fake' network interface @@ -506,6 +526,17 @@ class HardwareTypeLoadTestCase(db_base.DbTestCase): self.assertRaises(exception.InterfaceNotFoundInEntrypoint, task_manager.acquire, self.context, node.id) + def test_build_driver_for_task_instance_info_override(self): + self.config(enabled_network_interfaces=['noop', 'neutron']) + instance_info = {'network_interface': 'neutron'} + node = obj_utils.create_test_node(self.context, driver='fake-hardware', + instance_info=instance_info, + **self.node_kwargs) + with task_manager.acquire(self.context, node.id) as task: + self.assertEqual( + getattr(task.driver, 'network').__class__.__name__, + 'NeutronNetwork') + def test_no_storage_interface(self): node = obj_utils.get_test_node(self.context) self.assertTrue(driver_factory.check_and_update_node_interfaces(node)) diff --git a/releasenotes/notes/instance-info-interface-override-287c7fcff1081469.yaml b/releasenotes/notes/instance-info-interface-override-287c7fcff1081469.yaml new file mode 100644 index 000000000..56af6c8c1 --- /dev/null +++ b/releasenotes/notes/instance-info-interface-override-287c7fcff1081469.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Allows node _interface values to be overridden by values in instance_info. + This gives non-admins a temporary method of setting interface values.
\ No newline at end of file |