Merge "Allow updating interfaces on a node in available state"

This commit is contained in:
Jenkins 2017-07-24 05:49:09 +00:00 committed by Gerrit Code Review
commit 15db6df2a5
4 changed files with 76 additions and 34 deletions

View File

@ -1768,10 +1768,8 @@ function enroll_nodes {
# will NOT go to available state automatically. # will NOT go to available state automatically.
if [[ -n "${IRONIC_NETWORK_INTERFACE}" ]]; then if [[ -n "${IRONIC_NETWORK_INTERFACE}" ]]; then
local n_id local n_id
ironic node-set-maintenance $node_id true
n_id=$(ironic $ironic_api_version node-update $node_id add network_interface=$IRONIC_NETWORK_INTERFACE | grep " uuid " | awk '{ print $4; }') n_id=$(ironic $ironic_api_version node-update $node_id add network_interface=$IRONIC_NETWORK_INTERFACE | grep " uuid " | awk '{ print $4; }')
die_if_not_set $LINENO n_id "Failed to update network interface for node" die_if_not_set $LINENO n_id "Failed to update network interface for node"
ironic node-set-maintenance $node_id false
fi fi
local resource_class local resource_class

View File

@ -164,7 +164,7 @@ class ConductorManager(base_manager.BaseConductorManager):
# TODO(dtantsur): reconsider allowing changing some (but not all) # TODO(dtantsur): reconsider allowing changing some (but not all)
# interfaces for active nodes in the future. # interfaces for active nodes in the future.
allowed_update_states = [states.ENROLL, states.INSPECTING, allowed_update_states = [states.ENROLL, states.INSPECTING,
states.MANAGEABLE] states.MANAGEABLE, states.AVAILABLE]
for iface in drivers_base.ALL_INTERFACES: for iface in drivers_base.ALL_INTERFACES:
interface_field = '%s_interface' % iface interface_field = '%s_interface' % iface
if interface_field not in delta: if interface_field not in delta:

View File

@ -18,6 +18,7 @@
"""Test class for Ironic ManagerService.""" """Test class for Ironic ManagerService."""
from collections import namedtuple
import datetime import datetime
import eventlet import eventlet
@ -569,51 +570,90 @@ class UpdateNodeTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
node.refresh() node.refresh()
self.assertEqual(existing_driver, node.driver) self.assertEqual(existing_driver, node.driver)
def test_update_network_node_deleting_state(self): UpdateInterfaces = namedtuple('UpdateInterfaces', ('old', 'new'))
node = obj_utils.create_test_node(self.context, driver='fake', IFACE_UPDATE_DICT = {
provision_state=states.DELETING, 'boot_interface': UpdateInterfaces(None, 'fake'),
network_interface='flat') 'console_interface': UpdateInterfaces(None, 'fake'),
old_iface = node.network_interface 'deploy_interface': UpdateInterfaces(None, 'fake'),
node.network_interface = 'noop' 'inspect_interface': UpdateInterfaces(None, 'fake'),
'management_interface': UpdateInterfaces(None, 'fake'),
'network_interface': UpdateInterfaces('flat', 'noop'),
'power_interface': UpdateInterfaces(None, 'fake'),
'raid_interface': UpdateInterfaces(None, 'fake'),
'storage_interface': UpdateInterfaces('noop', 'cinder'),
}
def _create_node_with_interfaces(self, prov_state, maintenance=False):
old_ifaces = {}
for iface_name, ifaces in self.IFACE_UPDATE_DICT.items():
old_ifaces[iface_name] = ifaces.old
node = obj_utils.create_test_node(self.context, driver='fake-hardware',
provision_state=prov_state,
maintenance=maintenance,
**old_ifaces)
return node
def _test_update_node_interface_allowed(self, node, iface_name, new_iface):
setattr(node, iface_name, new_iface)
self.service.update_node(self.context, node)
node.refresh()
self.assertEqual(new_iface, getattr(node, iface_name))
def _test_update_node_interface_in_allowed_state(self, prov_state,
maintenance=False):
node = self._create_node_with_interfaces(prov_state,
maintenance=maintenance)
for iface_name, ifaces in self.IFACE_UPDATE_DICT.items():
self._test_update_node_interface_allowed(node, iface_name,
ifaces.new)
node.destroy()
def test_update_node_interface_in_allowed_state(self):
for state in [states.ENROLL, states.MANAGEABLE, states.INSPECTING,
states.AVAILABLE]:
self._test_update_node_interface_in_allowed_state(state)
def test_update_node_interface_in_maintenance(self):
self._test_update_node_interface_in_allowed_state(states.ACTIVE,
maintenance=True)
def _test_update_node_interface_not_allowed(self, node, iface_name,
new_iface):
old_iface = getattr(node, iface_name)
setattr(node, iface_name, new_iface)
exc = self.assertRaises(messaging.rpc.ExpectedException, exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_node, self.service.update_node,
self.context, node) self.context, node)
self.assertEqual(exception.InvalidState, exc.exc_info[0]) self.assertEqual(exception.InvalidState, exc.exc_info[0])
node.refresh() node.refresh()
self.assertEqual(old_iface, node.network_interface) self.assertEqual(old_iface, getattr(node, iface_name))
def test_update_network_node_manageable_state(self): def _test_update_node_interface_in_not_allowed_state(self, prov_state):
node = obj_utils.create_test_node(self.context, driver='fake', node = self._create_node_with_interfaces(prov_state)
provision_state=states.MANAGEABLE, for iface_name, ifaces in self.IFACE_UPDATE_DICT.items():
network_interface='flat') self._test_update_node_interface_not_allowed(node, iface_name,
node.network_interface = 'noop' ifaces.new)
self.service.update_node(self.context, node) node.destroy()
node.refresh()
self.assertEqual('noop', node.network_interface)
def test_update_network_node_active_state_and_maintenance(self): def test_update_node_interface_in_not_allowed_state(self):
node = obj_utils.create_test_node(self.context, driver='fake', for state in [states.ACTIVE, states.DELETING]:
provision_state=states.ACTIVE, self._test_update_node_interface_in_not_allowed_state(state)
network_interface='flat',
maintenance=True)
node.network_interface = 'noop'
self.service.update_node(self.context, node)
node.refresh()
self.assertEqual('noop', node.network_interface)
def test_update_node_invalid_network_interface(self): def _test_update_node_interface_invalid(self, node, iface_name):
node = obj_utils.create_test_node(self.context, driver='fake', old_iface = getattr(node, iface_name)
provision_state=states.MANAGEABLE, setattr(node, iface_name, 'invalid')
network_interface='flat')
old_iface = node.network_interface
node.network_interface = 'cosci'
exc = self.assertRaises(messaging.rpc.ExpectedException, exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_node, self.service.update_node,
self.context, node) self.context, node)
self.assertEqual(exception.InterfaceNotFoundInEntrypoint, self.assertEqual(exception.InterfaceNotFoundInEntrypoint,
exc.exc_info[0]) exc.exc_info[0])
node.refresh() node.refresh()
self.assertEqual(old_iface, node.network_interface) self.assertEqual(old_iface, getattr(node, iface_name))
def test_update_node_interface_invalid(self):
node = self._create_node_with_interfaces(states.MANAGEABLE)
for iface_name in self.IFACE_UPDATE_DICT:
self._test_update_node_interface_invalid(node, iface_name)
@mgr_utils.mock_record_keepalive @mgr_utils.mock_record_keepalive

View File

@ -0,0 +1,4 @@
---
features:
- |
Allows updating hardware interfaces on nodes in the ``available`` state.