Allow instance_info to override node interface
This change allows instance_info values to override node interface definitions, so non-admins can make temporary changes to various interfaces. Story: #2008652 Task: #41918 Change-Id: I6c3dc74705bde02bd02882d14838f184f8d4a5e3
This commit is contained in:
parent
227966b586
commit
a165fe3264
|
@ -30,6 +30,7 @@ the services.
|
||||||
Node Multi-Tenancy <node-multitenancy>
|
Node Multi-Tenancy <node-multitenancy>
|
||||||
Fast-Track Deployment <fast-track>
|
Fast-Track Deployment <fast-track>
|
||||||
Booting a Ramdisk or an ISO <ramdisk-boot>
|
Booting a Ramdisk or an ISO <ramdisk-boot>
|
||||||
|
Node Interface Override <node-interface-override>
|
||||||
|
|
||||||
Drivers, Hardware Types and Hardware Interfaces
|
Drivers, Hardware Types and Hardware Interfaces
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
|
@ -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.
|
|
@ -69,7 +69,9 @@ def _attach_interfaces_to_driver(bare_driver, node, hw_type):
|
||||||
the requested implementation is not compatible with it.
|
the requested implementation is not compatible with it.
|
||||||
"""
|
"""
|
||||||
for iface in _INTERFACE_LOADERS:
|
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)
|
impl = get_interface(hw_type, iface, impl_name)
|
||||||
setattr(bare_driver, iface, impl)
|
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
|
# NOTE(dtantsur): objects raise NotImplementedError on accessing fields
|
||||||
# that are known, but missing from an object. Thus, we cannot just use
|
# that are known, but missing from an object. Thus, we cannot just use
|
||||||
# getattr(node, field_name, None) here.
|
# 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:
|
if field_name in node:
|
||||||
impl_name = getattr(node, field_name)
|
impl_name = getattr(node, field_name)
|
||||||
if impl_name is not None:
|
if impl_name is not None:
|
||||||
# Check that the provided value is correct for this type
|
# Check that the provided value is correct for this type
|
||||||
get_interface(hw_type, iface, impl_name)
|
get_interface(hw_type, iface, impl_name)
|
||||||
# Not changing the result, proceeding with the next interface
|
set_default = False
|
||||||
continue
|
|
||||||
|
|
||||||
impl_name = default_interface(hw_type, iface,
|
if set_default:
|
||||||
driver_name=node.driver, node=node.uuid)
|
impl_name = default_interface(hw_type, iface,
|
||||||
|
driver_name=node.driver,
|
||||||
|
node=node.uuid)
|
||||||
|
|
||||||
# Set the calculated default and set result to True
|
# Set the calculated default and set result to True
|
||||||
setattr(node, field_name, impl_name)
|
setattr(node, field_name, impl_name)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,26 @@ class CheckAndUpdateNodeInterfacesTestCase(db_base.DbTestCase):
|
||||||
driver_factory.check_and_update_node_interfaces,
|
driver_factory.check_and_update_node_interfaces,
|
||||||
node)
|
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):
|
def _get_valid_default_interface_name(self, iface):
|
||||||
i_name = 'fake'
|
i_name = 'fake'
|
||||||
# there is no 'fake' network interface
|
# there is no 'fake' network interface
|
||||||
|
@ -506,6 +526,17 @@ class HardwareTypeLoadTestCase(db_base.DbTestCase):
|
||||||
self.assertRaises(exception.InterfaceNotFoundInEntrypoint,
|
self.assertRaises(exception.InterfaceNotFoundInEntrypoint,
|
||||||
task_manager.acquire, self.context, node.id)
|
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):
|
def test_no_storage_interface(self):
|
||||||
node = obj_utils.get_test_node(self.context)
|
node = obj_utils.get_test_node(self.context)
|
||||||
self.assertTrue(driver_factory.check_and_update_node_interfaces(node))
|
self.assertTrue(driver_factory.check_and_update_node_interfaces(node))
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue