Start moving the import CLI command to the Ansible implementation

Change-Id: I2285b23282a275097512dc35628cb7fa8ac94d61
Signed-off-by: Kevin Carter <kecarter@redhat.com>
This commit is contained in:
Kevin Carter 2020-01-21 13:16:27 -06:00
parent c7d49c3079
commit 818c7a7a1a
No known key found for this signature in database
GPG Key ID: CE94BD890A47B20A
3 changed files with 245 additions and 2 deletions

View File

@ -70,7 +70,7 @@ openstack.tripleoclient.v2 =
overcloud_image_upload = tripleoclient.v1.overcloud_image:UploadOvercloudImage
overcloud_node_configure = tripleoclient.v1.overcloud_node:ConfigureNode
overcloud_node_delete = tripleoclient.v1.overcloud_node:DeleteNode
overcloud_node_import = tripleoclient.v1.overcloud_node:ImportNode
overcloud_node_import = tripleoclient.v2.overcloud_node:ImportNode
overcloud_node_introspect = tripleoclient.v2.overcloud_node:IntrospectNode
overcloud_node_provide = tripleoclient.v1.overcloud_node:ProvideNode
overcloud_node_discover = tripleoclient.v1.overcloud_node:DiscoverNode

View File

@ -13,7 +13,12 @@
# under the License.
#
import collections
import fixtures
import json
import mock
import os
import tempfile
from osc_lib.tests import utils as test_utils
@ -22,6 +27,151 @@ from tripleoclient.tests.v2.overcloud_node import fakes
from tripleoclient.v2 import overcloud_node
class TestImportNode(fakes.TestOvercloudNode):
def setUp(self):
super(TestImportNode, self).setUp()
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",
"mac": [
"00:0b:d0:69:7e:58"
]
}]
# NOTE(cloudnull): Workflow and client calls are still mocked because
# mistal is still presnet here.
self.workflow = self.app.client_manager.workflow_engine
execution = mock.Mock()
execution.id = "IDID"
self.workflow.executions.create.return_value = execution
client = self.app.client_manager.tripleoclient
self.websocket = client.messaging_websocket()
self.websocket.wait_for_messages.return_value = [{
"status": "SUCCESS",
"message": "Success",
"registered_nodes": [{
"uuid": "MOCK_NODE_UUID"
}],
"execution_id": execution.id
}]
self.json_file = tempfile.NamedTemporaryFile(
mode='w', delete=False, suffix='.json')
json.dump(self.nodes_list, self.json_file)
self.json_file.close()
self.addCleanup(os.unlink, self.json_file.name)
# Get the command object to test
self.cmd = overcloud_node.ImportNode(self.app, None)
image = collections.namedtuple('image', ['id', 'name'])
self.app.client_manager.image = mock.Mock()
self.app.client_manager.image.images.list.return_value = [
image(id=3, name='overcloud-full'),
]
self.http_boot = '/var/lib/ironic/httpboot'
self.useFixture(fixtures.MockPatch(
'os.path.exists', autospec=True,
side_effect=lambda path: path in [os.path.join(self.http_boot, i)
for i in ('agent.kernel',
'agent.ramdisk')]))
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_only(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name],
[('introspect', False),
('provide', False)])
self.cmd.take_action(parsed_args)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_and_introspect(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name,
'--introspect'],
[('introspect', True),
('provide', False)])
self.cmd.take_action(parsed_args)
mock_playbook.assert_called_once_with(
workdir=mock.ANY,
playbook=mock.ANY,
inventory=mock.ANY,
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
extra_vars={
'node_uuids': ['MOCK_NODE_UUID'],
'run_validations': False,
'concurrency': 20
}
)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_and_provide(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name,
'--provide'],
[('introspect', False),
('provide', True)])
self.cmd.take_action(parsed_args)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_and_introspect_and_provide(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name,
'--introspect',
'--provide'],
[('introspect', True),
('provide', True)])
self.cmd.take_action(parsed_args)
mock_playbook.assert_called_once_with(
workdir=mock.ANY,
playbook=mock.ANY,
inventory=mock.ANY,
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
extra_vars={
'node_uuids': ['MOCK_NODE_UUID'],
'run_validations': False,
'concurrency': 20
}
)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_with_netboot(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name,
'--no-deploy-image'],
[('no_deploy_image', True)])
self.cmd.take_action(parsed_args)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_import_with_no_deployed_image(self, mock_playbook):
parsed_args = self.check_parser(self.cmd,
[self.json_file.name,
'--instance-boot-option',
'netboot'],
[('instance_boot_option', 'netboot')])
self.cmd.take_action(parsed_args)
class TestIntrospectNode(fakes.TestOvercloudNode):
def setUp(self):

View File

@ -13,7 +13,9 @@
# under the License.
#
import argparse
import logging
import os
from osc_lib.i18n import _
@ -28,12 +30,103 @@ from tripleoclient.v1.overcloud_node import CleanNode # noqa
from tripleoclient.v1.overcloud_node import ConfigureNode # noqa
from tripleoclient.v1.overcloud_node import DeleteNode # noqa
from tripleoclient.v1.overcloud_node import DiscoverNode # noqa
from tripleoclient.v1.overcloud_node import ImportNode # noqa
from tripleoclient.v1.overcloud_node import ProvideNode # noqa
from tripleoclient.v1.overcloud_node import ProvisionNode # noqa
from tripleoclient.v1.overcloud_node import UnprovisionNode # noqa
class ImportNode(command.Command):
"""Import baremetal nodes from a JSON, YAML or CSV file.
The node status will be set to 'manageable' by default.
"""
log = logging.getLogger(__name__ + ".ImportNode")
def get_parser(self, prog_name):
parser = super(ImportNode, self).get_parser(prog_name)
parser.add_argument('--introspect',
action='store_true',
help=_('Introspect the imported nodes'))
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.'))
parser.add_argument('--validate-only', action='store_true',
default=False,
help=_('Validate the env_file and then exit '
'without actually importing the nodes.'))
parser.add_argument('--provide',
action='store_true',
help=_('Provide (make available) the nodes'))
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=None,
help=_('Whether to set instances for booting from'
' local hard drive (local) or network '
' (netboot).'))
parser.add_argument("--http-boot",
default=os.environ.get(
'HTTP_BOOT',
constants.IRONIC_HTTP_BOOT_BIND_MOUNT),
help=_("Root directory for the "
" ironic-python-agent image"))
parser.add_argument('--concurrency', type=int,
default=20,
help=_('Maximum number of nodes to introspect at '
'once.'))
parser.add_argument('env_file', type=argparse.FileType('r'))
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
nodes_config = oooutils.parse_env_file(parsed_args.env_file)
parsed_args.env_file.close()
if parsed_args.validate_only:
return baremetal.validate_nodes(self.app.client_manager,
nodes_json=nodes_config)
# Look for *specific* deploy images and update the node data if
# one is found.
if not parsed_args.no_deploy_image:
oooutils.update_nodes_deploy_data(nodes_config,
http_boot=parsed_args.http_boot)
nodes = baremetal.register_or_update(
self.app.client_manager,
nodes_json=nodes_config,
instance_boot_option=parsed_args.instance_boot_option
)
nodes_uuids = [node['uuid'] for node in nodes]
if parsed_args.introspect:
extra_vars = {
"node_uuids": nodes_uuids,
"run_validations": parsed_args.run_validations,
"concurrency": parsed_args.concurrency,
}
with oooutils.TempDirs() as tmp:
oooutils.run_ansible_playbook(
playbook='cli-baremetal-introspect.yaml',
inventory='localhost,',
workdir=tmp,
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
extra_vars=extra_vars
)
if parsed_args.provide:
baremetal.provide(
self.app.client_manager,
node_uuids=nodes_uuids
)
class IntrospectNode(command.Command):
"""Introspect specified nodes or all nodes in 'manageable' state."""