Use Ironic API v1.11 to support ENROLL state
This state was introduced in Liberty as a new state for freshly enrolled nodes, but is only exposed to clients who specify an API version >= 1.11. We add a new --initial-state parameter to `openstack baremetal import` to enable use of the new state. Change-Id: If04889c3778827a77236f6d88617211ecc0f4161
This commit is contained in:
@@ -88,3 +88,5 @@ class TestBaremetal(utils.TestCommand):
|
||||
self.app.client_manager.baremetal = mock.Mock()
|
||||
self.app.client_manager.image = mock.Mock()
|
||||
self.app.client_manager.baremetal_introspection = FakeInspectorClient()
|
||||
self.app.client_manager._region_name = "Arcadia"
|
||||
self.app.client_manager.session = mock.Mock()
|
||||
|
||||
@@ -326,6 +326,22 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
self.instack_json.close()
|
||||
self.yaml_file.close()
|
||||
self.instack_yaml.close()
|
||||
self.baremetal = self.app.client_manager.baremetal
|
||||
self.baremetal.http_client.os_ironic_api_version = '1.11'
|
||||
self.baremetal.node = fakes.FakeBaremetalNodeClient(
|
||||
states={"ABCDEFGH": "enroll", "IJKLMNOP": "enroll"},
|
||||
transitions={
|
||||
("ABCDEFGH", "manage"): "manageable",
|
||||
("IJKLMNOP", "manage"): "manageable",
|
||||
("ABCDEFGH", "provide"): "available",
|
||||
("IJKLMNOP", "provide"): "available",
|
||||
|
||||
}
|
||||
)
|
||||
self.mock_initial_nodes = {
|
||||
mock.Mock(uuid="ABCDEFGH", provision_state="enroll"),
|
||||
mock.Mock(uuid="IJKLMNOP", provision_state="enroll")
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
@@ -347,13 +363,85 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
self.assertEqual(sorted([
|
||||
('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'),
|
||||
('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide')
|
||||
]), sorted(self.baremetal.node.updates))
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
def test_json_import_initial_state_enroll(self, mock_register_nodes):
|
||||
|
||||
arglist = [
|
||||
self.json_file.name,
|
||||
'--json',
|
||||
'-s', 'http://localhost',
|
||||
'--initial-state', 'enroll'
|
||||
]
|
||||
|
||||
verifylist = [
|
||||
('csv', False),
|
||||
('json', True),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
self.assertEqual([], self.baremetal.node.updates)
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
def test_available_does_not_require_api_1_11(self, mock_register_nodes):
|
||||
arglist = [self.json_file.name, '--json', '-s', 'http://localhost']
|
||||
|
||||
verifylist = [
|
||||
('csv', False),
|
||||
('json', True),
|
||||
]
|
||||
self.baremetal.http_client.os_ironic_api_version = '1.6'
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
self.assertEqual(sorted([
|
||||
('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'),
|
||||
('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide')
|
||||
]), sorted(self.baremetal.node.updates))
|
||||
|
||||
def test_enroll_requires_api_1_11(self):
|
||||
arglist = [
|
||||
self.json_file.name,
|
||||
'--json',
|
||||
'-s', 'http://localhost',
|
||||
'--initial-state', 'enroll'
|
||||
]
|
||||
|
||||
verifylist = [
|
||||
('csv', False),
|
||||
('json', True),
|
||||
]
|
||||
self.baremetal.http_client.os_ironic_api_version = '1.6'
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaisesRegexp(exceptions.InvalidConfiguration,
|
||||
'OS_BAREMETAL_API_VERSION',
|
||||
self.cmd.take_action, parsed_args)
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
def test_json_import_detect_suffix(self, mock_register_nodes):
|
||||
@@ -371,7 +459,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
@@ -385,13 +473,18 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
self.assertEqual(sorted([
|
||||
('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'),
|
||||
('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide')
|
||||
]), sorted(self.baremetal.node.updates))
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
def test_csv_import(self, mock_register_nodes):
|
||||
@@ -404,12 +497,13 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
@@ -428,7 +522,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.register_all_nodes', autospec=True)
|
||||
@@ -447,7 +541,7 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
|
||||
def test_invalid_import_filetype(self):
|
||||
@@ -476,13 +570,18 @@ pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58""")
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_register_nodes.return_value = self.mock_initial_nodes
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost', self.nodes_list,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=self.baremetal,
|
||||
keystone_client=None)
|
||||
self.assertEqual(sorted([
|
||||
('ABCDEFGH', 'manage'), ('IJKLMNOP', 'manage'),
|
||||
('ABCDEFGH', 'provide'), ('IJKLMNOP', 'provide')
|
||||
]), sorted(self.baremetal.node.updates))
|
||||
|
||||
|
||||
@mock.patch('time.sleep', lambda sec: None)
|
||||
|
||||
@@ -475,7 +475,7 @@ def set_nodes_state(baremetal_client, nodes, transition, target_state,
|
||||
continue
|
||||
|
||||
log.debug(
|
||||
"Setting provision state from {0} to '{1} for Node {2}"
|
||||
"Setting provision state from '{0}' to '{1}' for Node {2}"
|
||||
.format(node.provision_state, transition, node.uuid))
|
||||
|
||||
baremetal_client.node.set_provision_state(node.uuid, transition)
|
||||
|
||||
@@ -159,6 +159,13 @@ class ImportBaremetal(command.Command):
|
||||
'--csv', dest='csv', action='store_true',
|
||||
help=_('Deprecated, now detected via file extension.'))
|
||||
parser.add_argument('file_in', type=argparse.FileType('r'))
|
||||
parser.add_argument(
|
||||
'--initial-state',
|
||||
choices=['enroll', 'available'],
|
||||
default='available',
|
||||
help='Provision state for newly-enrolled nodes.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@@ -179,12 +186,32 @@ class ImportBaremetal(command.Command):
|
||||
if 'nodes' in nodes_config:
|
||||
nodes_config = nodes_config['nodes']
|
||||
|
||||
nodes.register_all_nodes(
|
||||
client = self.app.client_manager.baremetal
|
||||
if parsed_args.initial_state == "enroll":
|
||||
api_version = client.http_client.os_ironic_api_version
|
||||
if [int(part) for part in api_version.split('.')] < [1, 11]:
|
||||
raise exceptions.InvalidConfiguration(
|
||||
_("OS_BAREMETAL_API_VERSION must be >=1.11 for use of "
|
||||
"'enroll' provision state; currently %s") % api_version)
|
||||
new_nodes = nodes.register_all_nodes(
|
||||
parsed_args.service_host,
|
||||
nodes_config,
|
||||
client=self.app.client_manager.baremetal,
|
||||
client=client,
|
||||
keystone_client=self.app.client_manager.identity)
|
||||
|
||||
if parsed_args.initial_state == "available":
|
||||
manageable_node_uuids = list(utils.set_nodes_state(
|
||||
client, new_nodes, "manage", "manageable",
|
||||
skipped_states={'manageable', 'available'}
|
||||
))
|
||||
manageable_nodes = [
|
||||
n for n in new_nodes if n.uuid in manageable_node_uuids
|
||||
]
|
||||
list(utils.set_nodes_state(
|
||||
client, manageable_nodes, "provide", "available",
|
||||
skipped_states={'available'}
|
||||
))
|
||||
|
||||
|
||||
class StartBaremetalIntrospectionBulk(command.Command):
|
||||
"""Start bulk introspection on all baremetal nodes"""
|
||||
|
||||
Reference in New Issue
Block a user