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:
parent
47deab3915
commit
de6cb78950
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue