From ada02718a1fcbc121bfcb4fe005c3df2989a214b Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Mon, 18 Dec 2017 11:35:52 +1100 Subject: [PATCH] Remove Old baremetal commands provided by python-tripleoclient python-tripleoclient provides the following openstack baremetal commands: openstack baremetal instackenv validate: openstack baremetal import: openstack baremetal introspection bulk start: openstack baremetal introspection bulk status: openstack baremetal configure ready state: openstack baremetal configure boot: Based on the data below several of these are already deprecated and have been so longer enough to be removed. openstack baremetal instackenv validate: tripleoclient.v1.baremetal:ValidateInstackEnv NOT Deprecated openstack baremetal import: tripleoclient.v1.baremetal:ImportBaremetal DEPRECATED in b272a5c6 2017-01-03 New command: openstack overcloud node import openstack baremetal introspection bulk start: tripleoclient.v1.baremetal:StartBaremetalIntrospectionBulk DEPRECATED in b272a5c6 2017-01-03 New command: openstack overcloud node introspect openstack baremetal introspection bulk status: tripleoclient.v1.baremetal:StatusBaremetalIntrospectionBulk NOT Deprecated openstack baremetal configure ready state: tripleoclient.v1.baremetal:ConfigureReadyState NOT Deprecated openstack baremetal configure boot: tripleoclient.v1.baremetal:ConfigureBaremetalBoot DEPRECATED in b272a5c6 2017-01-03 New command: openstack overcloud node configure This leaves: openstack baremetal instackenv validate - This is somewhat superceded by the mistral validation in tripleo-common openstack baremetal introspection bulk status - This should have been deprecated along with 'openstack baremetal introspection bulk start' and isn't useful without the former. openstack baremetal configure ready state - Seems to only support drac and requires a datafile no loner generated by tools As these commands have outlived their useful lifetime and do not require deprecation we're free to remove them so let do it. Change-Id: Ie6b6a8578e4d12503a3dbfa5747309033d53466e --- setup.cfg | 6 - tripleoclient/tests/v1/baremetal/fakes.py | 50 - .../tests/v1/baremetal/test_baremetal.py | 1030 ----------------- .../overcloud_deploy/test_overcloud_deploy.py | 3 +- tripleoclient/v1/baremetal.py | 447 ------- 5 files changed, 1 insertion(+), 1535 deletions(-) delete mode 100644 tripleoclient/tests/v1/baremetal/test_baremetal.py delete mode 100644 tripleoclient/v1/baremetal.py diff --git a/setup.cfg b/setup.cfg index 02fa62a2d..20a437428 100644 --- a/setup.cfg +++ b/setup.cfg @@ -57,12 +57,6 @@ openstack.cli.extension = tripleoclient = tripleoclient.plugin openstack.tripleoclient.v1 = - baremetal_instackenv_validate = tripleoclient.v1.baremetal:ValidateInstackEnv - baremetal_import = tripleoclient.v1.baremetal:ImportBaremetal - baremetal_introspection_bulk_start = tripleoclient.v1.baremetal:StartBaremetalIntrospectionBulk - baremetal_introspection_bulk_status = tripleoclient.v1.baremetal:StatusBaremetalIntrospectionBulk - baremetal_configure_ready_state = tripleoclient.v1.baremetal:ConfigureReadyState - baremetal_configure_boot = tripleoclient.v1.baremetal:ConfigureBaremetalBoot overcloud_netenv_validate = tripleoclient.v1.overcloud_netenv_validate:ValidateOvercloudNetenv overcloud_config_download = tripleoclient.v1.overcloud_config:DownloadConfig overcloud_container_image_upload = tripleoclient.v1.container_image:UploadImage diff --git a/tripleoclient/tests/v1/baremetal/fakes.py b/tripleoclient/tests/v1/baremetal/fakes.py index bb7347bb0..1a68887c6 100644 --- a/tripleoclient/tests/v1/baremetal/fakes.py +++ b/tripleoclient/tests/v1/baremetal/fakes.py @@ -19,56 +19,6 @@ import ironic_inspector_client from osc_lib.tests import utils -class FakeBaremetalNodeClient(object): - def __init__(self, states={}, transitions={}, transition_errors={}): - """Create a new test double for the "baremetal node" command. - - :param states: dictionary of nodes' initial states. Keys are uuids and - values are states, eg {"ABC: "available"}. - :param transitions: dictionary of expected state transitions. - Keys are (uuid, transition) pairs, and values are - the states nodes end up in after that transition, - eg {("ABC", "manage"): "manageable"}. - Updates which occur are stored in "updates" for - later inspection. - :param transition_errors: dict of errors caused by state transitions. - Keys are (uuid, transition) pairs, and values - are the value of node.last_error after that - transition, - eg {("ABC", "manage"): "Node on fire."}. - """ - self.states = states - self.transitions = transitions - self.transition_errors = transition_errors - self.last_errors = {} - self.updates = [] # inspect this to see which transitions occurred - - def set_provision_state(self, node_uuid, transition): - key = (node_uuid, transition) - new_state = self.transitions[key] - self.states[node_uuid] = new_state - self.last_errors[node_uuid] = self.transition_errors.get(key, None) - self.updates.append(key) - - def _get(self, uuid, detail=False, **kwargs): - mock_node = mock.Mock(uuid=uuid, provision_state=self.states[uuid]) - if detail: - mock_node.last_error = self.last_errors.get(uuid, None) - else: - mock_node.mock_add_spec( - ('instance_uuid', 'maintenance', 'power_state', - 'provision_state', 'uuid', 'name'), - spec_set=True) - return mock_node - - def get(self, uuid): - return self._get(uuid, detail=True) - - def list(self, *args, **kwargs): - return [self._get(uuid, **kwargs) - for uuid in (sorted(self.states.keys()))] - - class FakeInspectorClient(object): def __init__(self, states=None, data=None): self.states = states or {} diff --git a/tripleoclient/tests/v1/baremetal/test_baremetal.py b/tripleoclient/tests/v1/baremetal/test_baremetal.py deleted file mode 100644 index 4d0005bbf..000000000 --- a/tripleoclient/tests/v1/baremetal/test_baremetal.py +++ /dev/null @@ -1,1030 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -import copy -import json -import os -import tempfile - -import mock -import yaml - -from tripleoclient import exceptions -from tripleoclient.tests.v1.baremetal import fakes -from tripleoclient.v1 import baremetal - - -class TestValidateInstackEnv(fakes.TestBaremetal): - - def setUp(self): - super(TestValidateInstackEnv, self).setUp() - - self.instack_json = tempfile.NamedTemporaryFile(mode='w', delete=False) - - # Get the command object to test - self.cmd = baremetal.ValidateInstackEnv(self.app, None) - - def mock_instackenv_json(self, instackenv_data): - json.dump(instackenv_data, self.instack_json) - self.instack_json.close() - - def tearDown(self): - super(TestValidateInstackEnv, self).tearDown() - os.unlink(self.instack_json.name) - - def test_success(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "SOME SSH KEY", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(0, self.cmd.error_count) - - def test_empty_password(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_no_password(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_empty_user(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "", - "pm_addr": "192.168.122.1", - "pm_password": "SOME SSH KEY", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_no_user(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_addr": "192.168.122.1", - "pm_password": "SOME SSH KEY", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_empty_mac(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "SOME SSH KEY", - "pm_type": "pxe_ssh", - "mac": [], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_no_mac(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "SOME SSH KEY", - "pm_type": "pxe_ssh", - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - def test_duplicated_mac(self): - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:58" - ], - }, { - "arch": "x86_64", - "pm_user": "stack", - "pm_addr": "192.168.122.2", - "pm_password": "KEY2", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:58" - ] - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - @mock.patch('tripleoclient.utils.run_shell') - def test_ipmitool_success(self, mock_run_shell): - mock_run_shell.return_value = 0 - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ipmitool", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(0, self.cmd.error_count) - - @mock.patch('tripleoclient.utils.run_shell') - def test_ipmitool_failure(self, mock_run_shell): - mock_run_shell.return_value = 1 - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ipmitool", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - @mock.patch('tripleoclient.utils.run_shell') - def test_duplicated_baremetal_ip(self, mock_run_shell): - mock_run_shell.return_value = 0 - self.mock_instackenv_json({ - "nodes": [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ipmitool", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }, { - "arch": "x86_64", - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY2", - "pm_type": "pxe_ipmitool", - "mac": [ - "00:0b:d0:69:7e:58" - ] - }] - }) - - arglist = ['-f', self.instack_json.name] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.cmd.error_count) - - -class TestImportBaremetal(fakes.TestBaremetal): - - def setUp(self): - super(TestImportBaremetal, self).setUp() - - # Get the command object to test - self.cmd = baremetal.ImportBaremetal(self.app, None) - - self.csv_file = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.csv') - self.json_file = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.json') - self.instack_json = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.json') - self.yaml_file = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.yaml') - self.instack_yaml = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.yaml') - self.unsupported_txt = tempfile.NamedTemporaryFile( - mode='w', delete=False, suffix='.txt') - - self.csv_file.write("""\ -pxe_ssh,192.168.122.1,stack,"KEY1",00:0b:d0:69:7e:59 -pxe_ssh,192.168.122.2,stack,"KEY2",00:0b:d0:69:7e:58,6230""") - - self.nodes_list = [{ - "pm_user": "stack", - "pm_addr": "192.168.122.1", - "pm_password": "KEY1", - "pm_type": "pxe_ssh", - "mac": [ - "00:0b:d0:69:7e:59" - ], - }, { - "pm_user": "stack", - "pm_addr": "192.168.122.2", - "pm_password": "KEY2", - "pm_type": "pxe_ssh", - "pm_port": "6230", - "mac": [ - "00:0b:d0:69:7e:58" - ] - }] - - json.dump(self.nodes_list, self.json_file) - json.dump({"nodes": self.nodes_list}, self.instack_json) - self.yaml_file.write(yaml.safe_dump(self.nodes_list, indent=2)) - self.instack_yaml.write( - yaml.safe_dump({"nodes": self.nodes_list}, indent=2)) - - self.csv_file.close() - self.json_file.close() - 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_websocket_success = [{ - "status": "SUCCESS", - "registered_nodes": [ - {"uuid": "MOCK_NODE_UUID", "provision_state": "manageable"}, - {"uuid": "MOCK_NODE_UUID2", "provision_state": "available"}, - ], - }, { - "status": "SUCCESS" - }, { - "status": "SUCCESS" - }] - - self.workflow = self.app.client_manager.workflow_engine - tripleoclient = self.app.client_manager.tripleoclient - websocket = tripleoclient.messaging_websocket() - websocket.wait_for_messages.return_value = self.mock_websocket_success - self.websocket = websocket - - def tearDown(self): - - super(TestImportBaremetal, self).tearDown() - os.unlink(self.csv_file.name) - os.unlink(self.json_file.name) - os.unlink(self.instack_json.name) - os.unlink(self.yaml_file.name) - os.unlink(self.instack_yaml.name) - - def _check_workflow_call(self, local=True, provide=True, - kernel_name='bm-deploy-kernel', - ramdisk_name='bm-deploy-ramdisk'): - - call_list = [mock.call( - 'tripleo.baremetal.v1.register_or_update', workflow_input={ - 'kernel_name': kernel_name, - 'nodes_json': self.nodes_list, - 'ramdisk_name': ramdisk_name, - 'instance_boot_option': 'local' if local else 'netboot', - 'initial_state': 'available', - } - )] - - self.workflow.executions.create.assert_has_calls(call_list) - - self.assertEqual(self.workflow.executions.create.call_count, 1) - - def test_json_import(self): - - arglist = [self.json_file.name, '--json', '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_available_does_not_require_api_1_11(self): - 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) - - self.cmd.take_action(parsed_args) - self._check_workflow_call() - - 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.assertRaisesRegex(exceptions.InvalidConfiguration, - 'OS_BAREMETAL_API_VERSION', - self.cmd.take_action, parsed_args) - self.workflow.executions.create.assert_not_called() - - def test_json_import_detect_suffix(self): - - arglist = [self.json_file.name, '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_instack_json_import(self): - - arglist = [self.instack_json.name, '--json', '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_csv_import(self): - - arglist = [self.csv_file.name, '--csv', '-s', 'http://localhost'] - - verifylist = [ - ('csv', True), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_csv_import_detect_suffix(self): - - arglist = [self.csv_file.name, '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_yaml_import(self): - - arglist = [self.yaml_file.name, '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_invalid_import_filetype(self): - - arglist = [self.unsupported_txt.name, '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaisesRegex(exceptions.InvalidConfiguration, - 'Invalid file extension', - self.cmd.take_action, parsed_args) - - def test_instack_yaml_import(self): - - arglist = [self.instack_yaml.name, '-s', 'http://localhost'] - - verifylist = [ - ('csv', False), - ('json', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_netboot(self): - - arglist = [self.json_file.name, '-s', 'http://localhost', - '--instance-boot-option', 'netboot'] - - verifylist = [ - ('instance_boot_option', 'netboot') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call(local=False) - - def test_custom_image(self): - - arglist = [self.json_file.name, '-s', 'http://localhost', - '--deploy-kernel', 'k', '--deploy-ramdisk', 'r'] - - verifylist = [ - ('deploy_kernel', 'k'), - ('deploy_ramdisk', 'r') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call(kernel_name='k', ramdisk_name='r') - - def test_no_image(self): - - arglist = [self.json_file.name, '-s', 'http://localhost', - '--no-deploy-image'] - - verifylist = [ - ('no_deploy_image', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self._check_workflow_call(kernel_name=None, ramdisk_name=None) - - -class TestStartBaremetalIntrospectionBulk(fakes.TestBaremetal): - - def setUp(self): - super(TestStartBaremetalIntrospectionBulk, self).setUp() - - self.workflow = self.app.client_manager.workflow_engine - tripleoclients = self.app.client_manager.tripleoclient - websocket = tripleoclients.messaging_websocket() - self.websocket = websocket - - # Get the command object to test - self.cmd = baremetal.StartBaremetalIntrospectionBulk(self.app, None) - - def _check_workflow_call(self, provide=True): - - call_list = [mock.call( - 'tripleo.baremetal.v1.introspect_manageable_nodes', - workflow_input={ - 'run_validations': False, - } - )] - - if provide: - call_list.append(mock.call( - 'tripleo.baremetal.v1.provide_manageable_nodes', - workflow_input={} - )) - - self.workflow.executions.create.assert_has_calls(call_list) - - self.assertEqual(self.workflow.executions.create.call_count, - 2 if provide else 1) - - def test_introspect_bulk(self): - client = self.app.client_manager.baremetal - client.node = fakes.FakeBaremetalNodeClient( - states={"ABCDEFGH": "available"}, - transitions={ - ("ABCDEFGH", "manage"): "manageable", - ("ABCDEFGH", "provide"): "available", - } - ) - - self.websocket.wait_for_messages.return_value = iter([{ - "status": "SUCCESS", - "message": "Success", - "introspected_nodes": {}, - }] * 2) - - parsed_args = self.check_parser(self.cmd, [], []) - self.cmd.take_action(parsed_args) - - self._check_workflow_call() - - def test_introspect_bulk_failed(self): - client = self.app.client_manager.baremetal - client.node = fakes.FakeBaremetalNodeClient( - states={"ABCDEFGH": "available"}, - transitions={ - ("ABCDEFGH", "manage"): "manageable", - ("ABCDEFGH", "provide"): "available", - } - ) - - self.websocket.wait_for_messages.return_value = iter([{ - "status": "ERROR", - "message": "Failed", - }]) - - parsed_args = self.check_parser(self.cmd, [], []) - - self.assertRaises( - exceptions.IntrospectionError, - self.cmd.take_action, parsed_args) - - self._check_workflow_call(provide=False) - - -class TestStatusBaremetalIntrospectionBulk(fakes.TestBaremetal): - - def setUp(self): - super(TestStatusBaremetalIntrospectionBulk, self).setUp() - - # Get the command object to test - self.cmd = baremetal.StatusBaremetalIntrospectionBulk(self.app, None) - - def test_status_bulk_one(self): - client = self.app.client_manager.baremetal - client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH") - ] - inspector_client = self.app.client_manager.baremetal_introspection - inspector_client.states['ABCDEFGH'] = {'finished': False, - 'error': None} - - parsed_args = self.check_parser(self.cmd, [], []) - result = self.cmd.take_action(parsed_args) - - self.assertEqual(result, ( - ('Node UUID', 'Finished', 'Error'), - [('ABCDEFGH', False, None)])) - - def test_status_bulk(self): - client = self.app.client_manager.baremetal - client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH"), - mock.Mock(uuid="IJKLMNOP"), - mock.Mock(uuid="QRSTUVWX"), - ] - inspector_client = self.app.client_manager.baremetal_introspection - for node in client.node.list.return_value: - inspector_client.states[node.uuid] = {'finished': False, - 'error': None} - - parsed_args = self.check_parser(self.cmd, [], []) - result = self.cmd.take_action(parsed_args) - - self.assertEqual(result, ( - ('Node UUID', 'Finished', 'Error'), - [ - ('ABCDEFGH', False, None), - ('IJKLMNOP', False, None), - ('QRSTUVWX', False, None) - ] - )) - - def test_missing_nodes(self): - client = self.app.client_manager.baremetal - client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH"), - mock.Mock(uuid="IJKLMNOP"), - mock.Mock(uuid="QRSTUVWX"), - ] - inspector_client = self.app.client_manager.baremetal_introspection - inspector_client.states['IJKLMNOP'] = {'finished': False, - 'error': None} - - parsed_args = self.check_parser(self.cmd, [], []) - result = self.cmd.take_action(parsed_args) - - self.assertEqual(result, ( - ('Node UUID', 'Finished', 'Error'), - [ - ('IJKLMNOP', False, None), - ] - )) - - -class TestConfigureReadyState(fakes.TestBaremetal): - - def setUp(self): - super(TestConfigureReadyState, self).setUp() - self.cmd = baremetal.ConfigureReadyState(self.app, None) - self.node = mock.Mock(uuid='foo') - self.ready_state_data = """{ - "compute" :{ - "bios_settings": {"ProcVirtualization": "Enabled"} - }, - "storage" :{ - "bios_settings": {"ProcVirtualization": "Disabled"} - } -} -""" - self.ready_state_config = { - "compute": { - "bios_settings": {"ProcVirtualization": "Enabled"} - }, - "storage": { - "bios_settings": {"ProcVirtualization": "Disabled"}, - } - } - - @mock.patch('tripleoclient.utils.node_get_capabilities') - @mock.patch('tripleoclient.v1.baremetal.ConfigureReadyState.' - '_apply_changes') - @mock.patch('tripleoclient.v1.baremetal.ConfigureReadyState.' - '_configure_bios') - @mock.patch('tripleoclient.v1.baremetal.ConfigureReadyState.' - '_change_power_state') - def test_configure_ready_state( - self, mock_change_power_state, mock_configure_bios, - mock_apply_changes, mock_node_get_capabilities): - - nodes = [mock.Mock(uuid='foo', driver='drac'), - mock.Mock(uuid='bar', driver='ilo'), - mock.Mock(uuid='baz', driver='drac')] - drac_nodes = [node for node in nodes if 'drac' in node.driver] - drac_nodes_with_profiles = [(drac_nodes[0], 'compute'), - (drac_nodes[1], 'storage')] - - bm_client = self.app.client_manager.baremetal - bm_client.node.list.return_value = nodes - - mock_node_get_capabilities.side_effect = [ - {'profile': 'compute'}, {'profile': 'storage'}] - mock_configure_bios.return_value = set([nodes[0]]) - - arglist = ['ready-state.json'] - verifylist = [('file', 'ready-state.json')] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - with mock.patch('six.moves.builtins.open', - mock.mock_open(read_data=self.ready_state_data)): - self.cmd.take_action(parsed_args) - - mock_node_get_capabilities.assert_has_calls( - [mock.call(nodes[0]), mock.call(nodes[2])]) - mock_configure_bios.assert_called_once_with(drac_nodes_with_profiles) - mock_apply_changes.assert_has_calls([ - # configure BIOS - mock.call(set([nodes[0]]))]) - mock_change_power_state.assert_called_once_with(drac_nodes, 'off') - - @mock.patch.object(baremetal.ConfigureReadyState, 'sleep_time', - new_callable=mock.PropertyMock, - return_value=0) - def test__configure_bios(self, mock_sleep_time): - nodes = [(self.node, 'compute')] - bm_client = self.app.client_manager.baremetal - self.cmd.bm_client = bm_client - self.cmd.ready_state_config = self.ready_state_config - - self.cmd._configure_bios(nodes) - - bm_client.node.vendor_passthru.assert_has_calls([ - mock.call('foo', 'set_bios_config', - args={'ProcVirtualization': 'Enabled'}, - http_method='POST'), - mock.call('foo', 'commit_bios_config', http_method='POST')]) - - @mock.patch.object(baremetal.ConfigureReadyState, 'sleep_time', - new_callable=mock.PropertyMock, - return_value=0) - def test__wait_for_drac_config_jobs(self, mock_sleep_time): - nodes = [self.node] - bm_client = self.app.client_manager.baremetal - bm_client.node.vendor_passthru.side_effect = [ - mock.Mock(unfinished_jobs={'percent_complete': '34', - 'id': 'JID_343938731947', - 'name': 'ConfigBIOS:BIOS.Setup.1-1'}), - mock.Mock(unfinished_jobs={}), - ] - self.cmd.bm_client = bm_client - - self.cmd._wait_for_drac_config_jobs(nodes) - - self.assertEqual(2, bm_client.node.vendor_passthru.call_count) - bm_client.node.vendor_passthru.assert_has_calls( - [mock.call('foo', 'list_unfinished_jobs', http_method='GET')] - ) - - @mock.patch.object(baremetal.ConfigureReadyState, 'sleep_time', - new_callable=mock.PropertyMock, - return_value=0) - def test__wait_for_drac_config_jobs_times_out(self, mock_sleep_time): - nodes = [self.node] - bm_client = self.app.client_manager.baremetal - bm_client.node.vendor_passthru.return_value = mock.Mock( - unfinished_jobs={'percent_complete': '34', - 'id': 'JID_343938731947', - 'name': 'ConfigBIOS:BIOS.Setup.1-1'}) - self.cmd.bm_client = bm_client - - self.assertRaises(exceptions.Timeout, - self.cmd._wait_for_drac_config_jobs, - nodes) - - def test__change_power_state(self): - nodes = [self.node] - bm_client = self.app.client_manager.baremetal - self.cmd.bm_client = bm_client - - self.cmd._change_power_state(nodes, 'reboot') - - bm_client.node.set_power_state.assert_called_once_with('foo', 'reboot') - - @mock.patch('tripleoclient.v1.baremetal.ConfigureReadyState.' - '_change_power_state') - @mock.patch('tripleoclient.v1.baremetal.ConfigureReadyState.' - '_wait_for_drac_config_jobs') - def test__apply_changes(self, mock_wait_for_drac_config_jobs, - mock_change_power_state): - nodes = [self.node] - bm_client = self.app.client_manager.baremetal - self.cmd.bm_client = bm_client - - self.cmd._apply_changes(nodes) - - mock_change_power_state.assert_called_once_with(nodes, 'reboot') - mock_wait_for_drac_config_jobs.assert_called_once_with(nodes) - - -class TestConfigureBaremetalBoot(fakes.TestBaremetal): - - def setUp(self): - super(TestConfigureBaremetalBoot, self).setUp() - - # Get the command object to test - self.cmd = baremetal.ConfigureBaremetalBoot(self.app, None) - - # Mistral-related mocks - self.workflow = self.app.client_manager.workflow_engine - client = self.app.client_manager.tripleoclient - self.websocket = client.messaging_websocket() - self.websocket.wait_for_messages.return_value = iter([{ - "status": "SUCCESS", - "message": "" - }] * 2) - - self.workflow_input = {'node_uuids': ['ABCDEFGH'], - 'kernel_name': 'bm-deploy-kernel', - 'ramdisk_name': 'bm-deploy-ramdisk', - 'root_device': None, - 'root_device_minimum_size': 4, - 'overwrite_root_device_hints': False} - # Ironic mocks - self.bm_client = self.app.client_manager.baremetal - self.bm_client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH"), - ] - - self.node = mock.Mock(uuid="ABCDEFGH", properties={}) - self.bm_client.node.get.return_value = self.node - - def test_configure_boot(self): - self.bm_client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH"), - mock.Mock(uuid="IJKLMNOP"), - ] - - self.bm_client.node.get.side_effect = [ - mock.Mock(uuid="ABCDEFGH", properties={}), - mock.Mock(uuid="IJKLMNOP", properties={}), - ] - - parsed_args = self.check_parser(self.cmd, [], []) - self.cmd.take_action(parsed_args) - - call_list = [mock.call('tripleo.baremetal.v1.configure', - workflow_input=self.workflow_input)] - - workflow_input = copy.copy(self.workflow_input) - workflow_input['node_uuids'] = ["IJKLMNOP"] - call_list.append(mock.call('tripleo.baremetal.v1.configure', - workflow_input=workflow_input)) - - self.workflow.executions.create.assert_has_calls(call_list) - - def test_configure_boot_with_suffix(self): - self.bm_client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH"), - mock.Mock(uuid="IJKLMNOP"), - ] - - self.bm_client.node.get.side_effect = [ - mock.Mock(uuid="ABCDEFGH", properties={}), - mock.Mock(uuid="IJKLMNOP", properties={}), - ] - - arglist = ['--deploy-kernel', 'bm-deploy-kernel_20150101T100620', - '--deploy-ramdisk', 'bm-deploy-ramdisk_20150101T100620'] - verifylist = [('deploy_kernel', 'bm-deploy-kernel_20150101T100620'), - ('deploy_ramdisk', 'bm-deploy-ramdisk_20150101T100620')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.workflow_input['kernel_name'] = 'bm-deploy-kernel_20150101T100620' - self.workflow_input['ramdisk_name'] = ( - 'bm-deploy-ramdisk_20150101T100620') - - call_list = [mock.call('tripleo.baremetal.v1.configure', - workflow_input=self.workflow_input)] - - workflow_input = copy.copy(self.workflow_input) - workflow_input['node_uuids'] = ["IJKLMNOP"] - call_list.append(mock.call('tripleo.baremetal.v1.configure', - workflow_input=workflow_input)) - - self.workflow.executions.create.assert_has_calls(call_list) - - @mock.patch.object(baremetal.ConfigureBaremetalBoot, 'sleep_time', - new_callable=mock.PropertyMock, - return_value=0) - def test_configure_boot_in_transition(self, _): - self.bm_client.node.list.return_value = [mock.Mock(uuid="ABCDEFGH", - power_state=None)] - - self.bm_client.node.get.side_effect = [ - mock.Mock(uuid="ABCDEFGH", power_state=None, properties={}), - mock.Mock(uuid="ABCDEFGH", power_state=None, properties={}), - mock.Mock(uuid="ABCDEFGH", power_state='available', properties={}), - mock.Mock(uuid="ABCDEFGH", power_state='available', properties={}), - ] - - parsed_args = self.check_parser(self.cmd, [], []) - self.cmd.take_action(parsed_args) - - self.assertEqual(1, self.bm_client.node.list.call_count) - self.assertEqual(3, self.bm_client.node.get.call_count) - self.assertEqual(1, self.workflow.executions.create.call_count) - - @mock.patch.object(baremetal.ConfigureBaremetalBoot, 'sleep_time', - new_callable=mock.PropertyMock, - return_value=0) - def test_configure_boot_timeout(self, _): - self.bm_client.node.list.return_value = [mock.Mock(uuid="ABCDEFGH", - power_state=None)] - self.bm_client.node.get.return_value = mock.Mock(uuid="ABCDEFGH", - power_state=None) - parsed_args = self.check_parser(self.cmd, [], []) - self.assertRaises(exceptions.Timeout, - self.cmd.take_action, - parsed_args) - - def test_configure_boot_skip_maintenance(self): - self.bm_client.node.list.return_value = [ - mock.Mock(uuid="ABCDEFGH", maintenance=False), - ] - - self.bm_client.node.get.return_value = mock.Mock(uuid="ABCDEFGH", - maintenance=False, - properties={}) - - parsed_args = self.check_parser(self.cmd, [], []) - self.cmd.take_action(parsed_args) - - self.assertEqual(self.bm_client.node.list.mock_calls, [mock.call( - maintenance=False)]) - - def test_root_device_options(self): - argslist = ['--root-device', 'smallest', - '--root-device-minimum-size', '2', - '--overwrite-root-device-hints'] - verifylist = [('root_device', 'smallest'), - ('root_device_minimum_size', 2), - ('overwrite_root_device_hints', True)] - parsed_args = self.check_parser(self.cmd, argslist, verifylist) - self.cmd.take_action(parsed_args) - - self.workflow_input['root_device'] = 'smallest' - self.workflow_input['root_device_minimum_size'] = 2 - self.workflow_input['overwrite_root_device_hints'] = True - self.workflow.executions.create.assert_called_once_with( - 'tripleo.baremetal.v1.configure', - workflow_input=self.workflow_input - ) diff --git a/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py b/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py index 6fc0cd4b2..5ef699aff 100644 --- a/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py +++ b/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py @@ -1592,7 +1592,6 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud): autospec=True) @mock.patch('tripleoclient.utils.wait_for_provision_state') @mock.patch('tripleoclient.workflows.baremetal', autospec=True) - @mock.patch('tripleoclient.v1.baremetal', autospec=True) @mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True) @mock.patch('tripleoclient.utils.write_overcloudrc', autospec=True) @mock.patch('tripleoclient.workflows.deployment.overcloudrc', @@ -1602,7 +1601,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud): def test_deployed_server(self, mock_deploy_tmpdir, mock_overcloudrc, mock_write_overcloudrc, mock_get_overcloud_endpoint, - mock_baremetal, mock_workflows_bm, + mock_workflows_bm, mock_provision, mock_tempest_deploy_input, mock_get_horizon_url): arglist = ['--templates', '--deployed-server', '--disable-validations'] diff --git a/tripleoclient/v1/baremetal.py b/tripleoclient/v1/baremetal.py deleted file mode 100644 index fd43f7af4..000000000 --- a/tripleoclient/v1/baremetal.py +++ /dev/null @@ -1,447 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -from __future__ import print_function - -import argparse -import logging -import simplejson -import time - -import ironic_inspector_client -from osc_lib.i18n import _ - -from tripleoclient import command -from tripleoclient import exceptions -from tripleoclient import utils -from tripleoclient.workflows import baremetal - - -class ValidateInstackEnv(command.Command): - """Validate `instackenv.json` which is used in `baremetal import`.""" - - auth_required = False - log = logging.getLogger(__name__ + ".ValidateInstackEnv") - - def get_parser(self, prog_name): - parser = super(ValidateInstackEnv, self).get_parser(prog_name) - parser.add_argument( - '-f', '--file', dest='instackenv', - help=_("Path to the instackenv.json file."), - default='instackenv.json') - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - - self.error_count = 0 - - with open(parsed_args.instackenv, 'r') as net_file: - env_data = simplejson.load(net_file) - - maclist = [] - baremetal_ips = [] - for node in env_data['nodes']: - self.log.info("Checking node %s" % node['pm_addr']) - - try: - if len(node['pm_password']) == 0: - self.log.error('ERROR: Password 0 length.') - self.error_count += 1 - except Exception as e: - self.log.error('ERROR: Password does not exist: %s', e) - self.error_count += 1 - try: - if len(node['pm_user']) == 0: - self.log.error('ERROR: User 0 length.') - self.error_count += 1 - except Exception as e: - self.log.error('ERROR: User does not exist: %s', e) - self.error_count += 1 - try: - if len(node['mac']) == 0: - self.log.error('ERROR: MAC address 0 length.') - self.error_count += 1 - maclist.extend(node['mac']) - except Exception as e: - self.log.error('ERROR: MAC address does not exist: %s', e) - self.error_count += 1 - - if node['pm_type'] == "pxe_ssh": - self.log.debug("Identified virtual node") - - if node['pm_type'] == "pxe_ipmitool": - self.log.debug("Identified baremetal node") - - cmd = ('ipmitool -R 1 -I lanplus -H %s -U %s -P %s chassis ' - 'status' % (node['pm_addr'], node['pm_user'], - node['pm_password'])) - self.log.debug("Executing: %s", cmd) - status = utils.run_shell(cmd) - if status != 0: - self.log.error('ERROR: ipmitool failed') - self.error_count += 1 - baremetal_ips.append(node['pm_addr']) - - if not utils.all_unique(baremetal_ips): - self.log.error('ERROR: Baremetals IPs are not all unique.') - self.error_count += 1 - else: - self.log.debug('Baremetal IPs are all unique.') - - if not utils.all_unique(maclist): - self.log.error('ERROR: MAC addresses are not all unique.') - self.error_count += 1 - else: - self.log.debug('MAC addresses are all unique.') - - if self.error_count == 0: - print('SUCCESS: found 0 errors') - else: - print('FAILURE: found %d errors' % self.error_count) - - -class ImportBaremetal(command.Command): - """Import baremetal nodes from a JSON, YAML or CSV file (DEPRECATED). - - Please use 'openstack overcloud node import' instead. - """ - - log = logging.getLogger(__name__ + ".ImportBaremetal") - - def get_parser(self, prog_name): - parser = super(ImportBaremetal, self).get_parser(prog_name) - parser.add_argument('-s', '--service-host', dest='service_host', - help=_('Deprecated, this argument has no impact.')) - parser.add_argument( - '--json', dest='json', action='store_true', - help=_('Deprecated, now detected via file extension.')) - parser.add_argument( - '--csv', dest='csv', action='store_true', - help=_('Deprecated, now detected via file extension.')) - parser.add_argument('--deploy-kernel', - default='bm-deploy-kernel', - help=_('Image with deploy kernel.')) - parser.add_argument('--deploy-ramdisk', - default='bm-deploy-ramdisk', - help=_('Image with deploy ramdisk.')) - parser.add_argument('--no-deploy-image', action='store_true', - help=_('Skip setting the deploy kernel and ' - 'ramdisk.')) - parser.add_argument('--instance-boot-option', - choices=['local', 'netboot'], default='local', - help=_('Whether to set instances for booting from ' - 'local hard drive (local) or network ' - '(netboot).')) - parser.add_argument('file_in', type=argparse.FileType('r')) - parser.add_argument( - '--initial-state', - choices=['enroll', 'manageable', 'available'], - default='available', - help=_('Provision state for newly-enrolled nodes.') - ) - - return parser - - def take_action(self, parsed_args): - - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning('This command is deprecated. Please use "openstack ' - 'overcloud node import" to register nodes instead.') - - file_type = None - if parsed_args.json: - file_type = 'json' - elif parsed_args.csv: - file_type = 'csv' - - nodes_config = utils.parse_env_file(parsed_args.file_in, file_type) - - 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) - - if parsed_args.no_deploy_image: - deploy_kernel = None - deploy_ramdisk = None - else: - deploy_kernel = parsed_args.deploy_kernel - deploy_ramdisk = parsed_args.deploy_ramdisk - - baremetal.register_or_update( - self.app.client_manager, - nodes_json=nodes_config, - kernel_name=deploy_kernel, - ramdisk_name=deploy_ramdisk, - instance_boot_option=parsed_args.instance_boot_option, - initial_state=parsed_args.initial_state, - ) - - -class StartBaremetalIntrospectionBulk(command.Command): - """Start bulk introspection on all baremetal nodes (DEPRECATED). - - Please use 'openstack overcloud node introspect' instead. The nodes - should be in 'manageable' state before running the command. - """ - - log = logging.getLogger(__name__ + ".StartBaremetalIntrospectionBulk") - - def get_parser(self, prog_name): - parser = super(StartBaremetalIntrospectionBulk, self).get_parser( - prog_name) - parser.add_argument('--run-validations', action='store_true', - default=False, - help=_('Run the pre-deployment validations. These ' - 'external validations are from the TripleO ' - 'Validations project.')) - return parser - - def take_action(self, parsed_args): - - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning('This command is deprecated. Please use "openstack ' - 'overcloud node introspect" to introspect manageable ' - 'nodes instead.') - - clients = self.app.client_manager - client = self.app.client_manager.baremetal - - # TODO(d0ugal): We don't yet have a workflow to move from available - # or enroll to manageable. Once we do, this should be switched over. - print("Setting nodes for introspection to manageable...") - self.log.debug("Moving available/enroll nodes to manageable state.") - available_nodes = utils.nodes_in_states(client, ("available", - "enroll")) - for node_uuid in utils.set_nodes_state(client, available_nodes, - 'manage', 'manageable'): - self.log.debug( - "Node {0} has been set to manageable.".format(node_uuid)) - - print("Starting introspection of manageable nodes") - baremetal.introspect_manageable_nodes( - clients, - run_validations=parsed_args.run_validations - ) - print("Setting manageable nodes to available...") - self.log.debug("Moving manageable nodes to available state.") - - baremetal.provide_manageable_nodes(clients) - - -class StatusBaremetalIntrospectionBulk(command.Lister): - """Get the status of all baremetal nodes""" - - log = logging.getLogger(__name__ + ".StatusBaremetalIntrospectionBulk") - - def take_action(self, parsed_args): - - self.log.debug("take_action(%s)" % parsed_args) - client = self.app.client_manager.baremetal - inspector_client = self.app.client_manager.baremetal_introspection - - statuses = [] - - for node in client.node.list(): - self.log.debug("Getting introspection status of Ironic node {0}" - .format(node.uuid)) - - try: - status = inspector_client.get_status(node.uuid) - except ironic_inspector_client.ClientError as exc: - # This API returns an error when the node was never - # introspected before. Exclude it from output in this case. - self.log.debug('Introspection status for node %(node)s ' - 'returned error %(exc)s', - {'node': node.uuid, 'exc': exc}) - else: - statuses.append((node.uuid, status)) - - return ( - ("Node UUID", "Finished", "Error"), - list((node_uuid, status['finished'], status['error']) - for (node_uuid, status) in statuses) - ) - - -class ConfigureReadyState(command.Command): - """Configure all baremetal nodes for enrollment""" - - log = logging.getLogger(__name__ + ".ConfigureReadyState") - sleep_time = 15 - loops = 120 - - def _configure_bios(self, nodes): - nodes_with_reboot_request = set() - - for node, profile in nodes: - if (profile in self.ready_state_config and - 'bios_settings' in self.ready_state_config[profile]): - - print("Configuring BIOS for node {0}".format(node.uuid)) - settings = self.ready_state_config[profile]['bios_settings'] - resp = self.bm_client.node.vendor_passthru( - node.uuid, 'set_bios_config', http_method='POST', - args=settings) - - if resp.commit_required: - nodes_with_reboot_request.add(node) - self.bm_client.node.vendor_passthru( - node.uuid, 'commit_bios_config', http_method='POST') - - # NOTE(ifarkas): give the DRAC card some time to process the job - time.sleep(self.sleep_time) - - return nodes_with_reboot_request - - def _wait_for_drac_config_jobs(self, nodes): - for node in nodes: - print("Waiting for DRAC config jobs to finish on node {0}" - .format(node.uuid)) - - for _r in range(self.loops): - resp = self.bm_client.node.vendor_passthru( - node.uuid, 'list_unfinished_jobs', http_method='GET') - if not resp.unfinished_jobs: - break - - time.sleep(self.sleep_time) - else: - msg = ("Timed out waiting for DRAC config jobs on node {0}" - .format(node.uuid)) - raise exceptions.Timeout(msg) - - def _change_power_state(self, nodes, target_power_state): - for node in nodes: - print("Changing power state on " - "node {0} to {1}".format(node.uuid, target_power_state)) - self.bm_client.node.set_power_state(node.uuid, target_power_state) - - def _apply_changes(self, nodes): - self._change_power_state(nodes, 'reboot') - self._wait_for_drac_config_jobs(nodes) - - def get_parser(self, prog_name): - parser = super(ConfigureReadyState, self).get_parser(prog_name) - parser.add_argument('file', help=_('JSON file containing the ' - 'ready-state configuration for each profile')) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - - self.bm_client = self.app.client_manager.baremetal - - with open(parsed_args.file, 'r') as fp: - self.ready_state_config = simplejson.load(fp) - - drac_nodes = [] - for node in self.bm_client.node.list(detail=True): - if 'drac' not in node.driver: - continue - - selected_profile = utils.node_get_capabilities(node).get('profile') - if selected_profile is None: - continue - - drac_nodes.append((node, selected_profile)) - - changed_nodes = self._configure_bios(drac_nodes) - self._apply_changes(changed_nodes) - - self._change_power_state([node for node, profile in drac_nodes], 'off') - - -class ConfigureBaremetalBoot(command.Command): - """Configure baremetal boot for all nodes (DEPRECATED). - - Please use 'openstack overcloud node configure' instead. - """ - - log = logging.getLogger(__name__ + ".ConfigureBaremetalBoot") - loops = 12 - sleep_time = 10 - - def get_parser(self, prog_name): - parser = super(ConfigureBaremetalBoot, self).get_parser(prog_name) - parser.add_argument('--deploy-kernel', - default='bm-deploy-kernel', - help=_('Image with deploy kernel.')) - parser.add_argument('--deploy-ramdisk', - default='bm-deploy-ramdisk', - help=_('Image with deploy ramdisk.')) - parser.add_argument('--root-device', - help=_('Define the root device for nodes. ' - 'Can be either a list of device names ' - '(without /dev) to choose from or one of ' - 'two strategies: largest or smallest. For ' - 'it to work this command should be run ' - 'after the introspection.')) - parser.add_argument('--root-device-minimum-size', - type=int, default=4, - help=_('Minimum size (in GiB) of the detected ' - 'root device. Used with --root-device.')) - parser.add_argument('--overwrite-root-device-hints', - action='store_true', - help=_('Whether to overwrite existing root device ' - 'hints when --root-device is used.')) - return parser - - def take_action(self, parsed_args): - - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning('This command is deprecated. Please use "openstack ' - 'overcloud node configure" to configure manageable ' - 'nodes instead.') - - bm_client = self.app.client_manager.baremetal - - for node in bm_client.node.list(maintenance=False): - # NOTE(bnemec): Ironic won't let us update the node while the - # power_state is transitioning. - # Make sure we have the current node state, and not a cached one - # from the list call above, which may have happened minutes ago. - node_detail = bm_client.node.get(node.uuid) - if node_detail.power_state is None: - self.log.warning('Node %s power state is in transition. ' - 'Waiting up to %d seconds for it to ' - 'complete.', - node_detail.uuid, - self.loops * self.sleep_time) - for _r in range(self.loops): - time.sleep(self.sleep_time) - node_detail = bm_client.node.get(node.uuid) - if node_detail.power_state is not None: - break - else: - msg = ('Timed out waiting for node %s power state.' % - node.uuid) - raise exceptions.Timeout(msg) - - baremetal.configure( - self.app.client_manager, - node_uuids=[node.uuid], - kernel_name=parsed_args.deploy_kernel, - ramdisk_name=parsed_args.deploy_ramdisk, - root_device=parsed_args.root_device, - root_device_minimum_size=parsed_args.root_device_minimum_size, - overwrite_root_device_hints=( - parsed_args.overwrite_root_device_hints) - )