Initial support for ironic enroll state

Addition of logic for the ironic enroll state which will
ultimately permit a newer client library version.

Change-Id: I85fe0f2b2f0e6766928f9fb23cb1a8177779008c
This commit is contained in:
Julia Kreger 2015-08-12 11:21:05 -04:00
parent 47deab3915
commit de6cb78950
2 changed files with 221 additions and 6 deletions

View File

@ -3477,7 +3477,8 @@ class OperatorCloud(OpenStackCloud):
except ironic_exceptions.ClientException:
return None
def register_machine(self, nics, **kwargs):
def register_machine(self, nics, wait=False, timeout=3600,
lock_timeout=600, **kwargs):
"""Register Baremetal with Ironic
Allows for the registration of Baremetal nodes with Ironic
@ -3501,6 +3502,18 @@ class OperatorCloud(OpenStackCloud):
{'mac': 'aa:bb:cc:dd:ee:02'}
]
:param wait: Boolean value, defaulting to false, to wait for the
node to reach the available state where the node can be
provisioned. It must be noted, when set to false, the
method will still wait for locks to clear before sending
the next required command.
:param timeout: Integer value, defautling to 3600 seconds, for the
wait state to reach completion.
:param lock_timeout: Integer value, defaulting to 600 seconds, for
locks to clear.
:param kwargs: Key value pairs to be passed to the Ironic API,
including uuid, name, chassis_uuid, driver_info,
parameters.
@ -3511,8 +3524,9 @@ class OperatorCloud(OpenStackCloud):
baremetal node.
"""
try:
machine = self.manager.submitTask(
_tasks.MachineCreate(**kwargs))
machine = meta.obj_to_dict(
self.manager.submitTask(_tasks.MachineCreate(**kwargs)))
except Exception as e:
self.log.debug("ironic machine registration failed", exc_info=True)
raise OpenStackCloudException(
@ -3523,7 +3537,7 @@ class OperatorCloud(OpenStackCloud):
for row in nics:
nic = self.manager.submitTask(
_tasks.MachinePortCreate(address=row['mac'],
node_uuid=machine.uuid))
node_uuid=machine['uuid']))
created_nics.append(nic.uuid)
except Exception as e:
@ -3539,11 +3553,77 @@ class OperatorCloud(OpenStackCloud):
pass
finally:
self.manager.submitTask(
_tasks.MachineDelete(node_id=machine.uuid))
_tasks.MachineDelete(node_id=machine['uuid']))
raise OpenStackCloudException(
"Error registering NICs with the baremetal service: %s"
% str(e))
return meta.obj_to_dict(machine)
try:
if wait:
for count in _utils._iterate_timeout(
timeout,
"Timeout waiting for node transition to "
"available state"):
machine = self.get_machine(machine['uuid'])
# Note(TheJulia): Per the Ironic state code, a node
# that fails returns to enroll state, which means a failed
# node cannot be determined at this point in time.
if machine['provision_state'] in ['enroll']:
self.node_set_provision_state(
machine['uuid'], 'manage')
elif machine['provision_state'] in ['manageable']:
self.node_set_provision_state(
machine['uuid'], 'provide')
elif machine['last_error'] is not None:
raise OpenStackCloudException(
"Machine encountered a failure: %s"
% machine['last_error'])
# Note(TheJulia): Earlier versions of Ironic default to
# None and later versions default to available up until
# the introduction of enroll state.
# Note(TheJulia): The node will transition through
# cleaning if it is enabled, and we will wait for
# completion.
elif machine['provision_state'] in ['available', None]:
break
else:
if machine['provision_state'] in ['enroll']:
self.node_set_provision_state(machine['uuid'], 'manage')
# Note(TheJulia): We need to wait for the lock to clear
# before we attempt to set the machine into provide state
# which allows for the transition to available.
for count in _utils._iterate_timeout(
lock_timeout,
"Timeout waiting for reservation to clear "
"before setting provide state"):
machine = self.get_machine(machine['uuid'])
if (machine['reservation'] is None and
machine['provision_state'] is not 'enroll'):
self.node_set_provision_state(
machine['uuid'], 'provide')
machine = self.get_machine(machine['uuid'])
break
elif machine['provision_state'] in [
'cleaning',
'available']:
break
elif machine['last_error'] is not None:
raise OpenStackCloudException(
"Machine encountered a failure: %s"
% machine['last_error'])
except Exception as e:
raise OpenStackCloudException(
"Error transitioning node to available state: %s"
% e)
return machine
def unregister_machine(self, nics, uuid):
"""Unregister Baremetal from Ironic

View File

@ -367,20 +367,155 @@ class TestShadeOperator(base.TestCase):
def test_register_machine(self, mock_client):
class fake_node:
uuid = "00000000-0000-0000-0000-000000000000"
provision_state = "available"
reservation = None
last_error = None
expected_return_value = dict(
uuid="00000000-0000-0000-0000-000000000000",
provision_state="available",
reservation=None,
last_error=None
)
mock_client.node.create.return_value = fake_node
mock_client.node.get.return_value = fake_node
nics = [{'mac': '00:00:00:00:00:00'}]
return_value = self.cloud.register_machine(nics)
self.assertDictEqual(expected_return_value, return_value)
self.assertTrue(mock_client.node.create.called)
self.assertTrue(mock_client.port.create.called)
self.assertFalse(mock_client.node.get.called)
@mock.patch.object(shade.OperatorCloud, 'ironic_client')
@mock.patch.object(shade.OperatorCloud, 'node_set_provision_state')
def test_register_machine_enroll(
self,
mock_set_state,
mock_client):
machine_uuid = "00000000-0000-0000-0000-000000000000"
class fake_node_init_state:
uuid = machine_uuid
provision_state = "enroll"
reservation = None
last_error = None
class fake_node_post_manage:
uuid = machine_uuid
provision_state = "enroll"
reservation = "do you have a flag?"
last_error = None
class fake_node_post_manage_done:
uuid = machine_uuid
provision_state = "manage"
reservation = None
last_error = None
class fake_node_post_provide:
uuid = machine_uuid
provision_state = "available"
reservation = None
last_error = None
class fake_node_post_enroll_failure:
uuid = machine_uuid
provision_state = "enroll"
reservation = None
last_error = "insufficent lolcats"
expected_return_value = dict(
uuid=machine_uuid,
provision_state="available",
reservation=None,
last_error=None
)
mock_client.node.get.side_effect = iter([
fake_node_init_state,
fake_node_post_manage,
fake_node_post_manage_done,
fake_node_post_provide])
mock_client.node.create.return_value = fake_node_init_state
nics = [{'mac': '00:00:00:00:00:00'}]
return_value = self.cloud.register_machine(nics)
self.assertDictEqual(expected_return_value, return_value)
self.assertTrue(mock_client.node.create.called)
self.assertTrue(mock_client.port.create.called)
self.assertTrue(mock_client.node.get.called)
mock_client.reset_mock()
mock_client.node.get.side_effect = iter([
fake_node_init_state,
fake_node_post_manage,
fake_node_post_manage_done,
fake_node_post_provide])
return_value = self.cloud.register_machine(nics, wait=True)
self.assertDictEqual(expected_return_value, return_value)
self.assertTrue(mock_client.node.create.called)
self.assertTrue(mock_client.port.create.called)
self.assertTrue(mock_client.node.get.called)
mock_client.reset_mock()
mock_client.node.get.side_effect = iter([
fake_node_init_state,
fake_node_post_manage,
fake_node_post_enroll_failure])
self.assertRaises(
shade.OpenStackCloudException,
self.cloud.register_machine,
nics)
self.assertRaises(
shade.OpenStackCloudException,
self.cloud.register_machine,
nics,
wait=True)
@mock.patch.object(shade.OperatorCloud, 'ironic_client')
@mock.patch.object(shade.OperatorCloud, 'node_set_provision_state')
def test_register_machine_enroll_timeout(
self,
mock_set_state,
mock_client):
machine_uuid = "00000000-0000-0000-0000-000000000000"
class fake_node_init_state:
uuid = machine_uuid
provision_state = "enroll"
reservation = "do you have a flag?"
last_error = None
mock_client.node.get.return_value = fake_node_init_state
mock_client.node.create.return_value = fake_node_init_state
nics = [{'mac': '00:00:00:00:00:00'}]
self.assertRaises(
shade.OpenStackCloudException,
self.cloud.register_machine,
nics,
lock_timeout=0.001)
self.assertTrue(mock_client.node.create.called)
self.assertTrue(mock_client.port.create.called)
self.assertTrue(mock_client.node.get.called)
mock_client.node.get.reset_mock()
mock_client.node.create.reset_mock()
self.assertRaises(
shade.OpenStackCloudException,
self.cloud.register_machine,
nics,
wait=True,
timeout=0.001)
self.assertTrue(mock_client.node.create.called)
self.assertTrue(mock_client.port.create.called)
self.assertTrue(mock_client.node.get.called)
@mock.patch.object(shade.OperatorCloud, 'ironic_client')
def test_register_machine_port_create_failed(self, mock_client):
class fake_node:
uuid = "00000000-0000-0000-0000-000000000000"
provision_state = "available"
resevation = None
last_error = None
nics = [{'mac': '00:00:00:00:00:00'}]
mock_client.node.create.return_value = fake_node
mock_client.port.create.side_effect = (
exc.OpenStackCloudException("Error"))
self.assertRaises(exc.OpenStackCloudException,