Introduce command to abort introspection
The Inspector API now supports introspection aborting for a node. This change purpose is to expose that API through the client. Usage: openstack baremetal introspection abort <node-UUID> Change-Id: Ibfb515087fcc4740bbd2c2bd88459958f74647bf Related-Bug: #1525235
This commit is contained in:
parent
f7283cdf2d
commit
94a7730b27
11
README.rst
11
README.rst
@ -121,6 +121,17 @@ If file name is not provided, the data is dumped to stdout.
|
||||
This feature requires Swift support to be enabled in **Ironic Inspector**
|
||||
by setting ``[processing]store_data`` configuration option to ``swift``.
|
||||
|
||||
Aborting introspection
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``client.abort(uuid)``
|
||||
|
||||
* ``uuid`` - Ironic node UUID.
|
||||
|
||||
CLI::
|
||||
|
||||
$ openstack baremetal introspection abort UUID
|
||||
|
||||
Introspection Rules API
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -116,6 +116,19 @@ class StatusCommand(show.ShowOne):
|
||||
return zip(*sorted(status.items()))
|
||||
|
||||
|
||||
class AbortCommand(command.Command):
|
||||
"""Abort running introspection for node."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(AbortCommand, self).get_parser(prog_name)
|
||||
parser.add_argument('uuid', help='baremetal node UUID')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.baremetal_introspection
|
||||
client.abort(parsed_args.uuid)
|
||||
|
||||
|
||||
class RuleImportCommand(command.Command):
|
||||
"""Import one or several introspection rules from a json file."""
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
import eventlet
|
||||
eventlet.monkey_patch()
|
||||
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
from ironic_inspector.test import functional
|
||||
@ -46,6 +47,32 @@ class TestV1PythonAPI(functional.Base):
|
||||
status = self.client.get_status(self.uuid)
|
||||
self.assertEqual({'finished': True, 'error': None}, status)
|
||||
|
||||
def test_abort_introspection(self):
|
||||
# assert abort doesn't work before introspect request
|
||||
self.assertRaises(client.ClientError, self.client.abort,
|
||||
self.uuid)
|
||||
|
||||
self.client.introspect(self.uuid)
|
||||
eventlet.greenthread.sleep(functional.DEFAULT_SLEEP)
|
||||
self.cli.node.set_power_state.assert_called_once_with(self.uuid,
|
||||
'reboot')
|
||||
|
||||
status = self.client.get_status(self.uuid)
|
||||
self.assertEqual({'finished': False, 'error': None}, status)
|
||||
|
||||
res = self.client.abort(self.uuid)
|
||||
eventlet.greenthread.sleep(functional.DEFAULT_SLEEP)
|
||||
|
||||
self.assertEqual(202, res.status_code)
|
||||
self.assertEqual('', res.text)
|
||||
|
||||
status = self.client.get_status(self.uuid)
|
||||
self.assertEqual({'finished': True, 'error': 'Canceled by '
|
||||
'operator'}, status)
|
||||
|
||||
# assert continue doesn't work after abort
|
||||
self.assertRaises(requests.HTTPError, self.call_continue, self.data)
|
||||
|
||||
def test_setup_ipmi(self):
|
||||
self.node.provision_state = 'enroll'
|
||||
self.client.introspect(self.uuid, new_ipmi_username='admin',
|
||||
|
@ -125,6 +125,21 @@ class TestIntrospect(BaseTest):
|
||||
self.assertEqual([('uuid1', None), ('uuid2', 'boom'), ('uuid3', None)],
|
||||
sorted(values))
|
||||
|
||||
def test_abort(self):
|
||||
node = 'uuid1'
|
||||
arglist = [node]
|
||||
verifylist = [('uuid', node)]
|
||||
response_mock = mock.Mock(status_code=202, content=b'')
|
||||
self.client.abort.return_value = response_mock
|
||||
|
||||
cmd = shell.AbortCommand(self.app, None)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
self.client.abort.assert_called_once_with(node)
|
||||
self.assertIs(None, result)
|
||||
|
||||
|
||||
class TestRules(BaseTest):
|
||||
def test_import_single(self):
|
||||
|
@ -264,3 +264,14 @@ class TestRules(BaseTest):
|
||||
self.get_rules().delete_all()
|
||||
|
||||
mock_req.assert_called_once_with('delete', '/rules')
|
||||
|
||||
|
||||
@mock.patch.object(http.BaseClient, 'request')
|
||||
class TestAbort(BaseTest):
|
||||
def test(self, mock_req):
|
||||
self.get_client().abort(self.uuid)
|
||||
mock_req.assert_called_once_with('post',
|
||||
'/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_invalid_input(self, _):
|
||||
self.assertRaises(TypeError, self.get_client().abort, 42)
|
||||
|
@ -154,6 +154,21 @@ class ClientV1(http.BaseClient):
|
||||
else:
|
||||
return resp.json()
|
||||
|
||||
def abort(self, uuid):
|
||||
"""Abort running introspection for a node.
|
||||
|
||||
:param uuid: node UUID.
|
||||
:raises: ClientError on error reported from a server.
|
||||
:raises: VersionNotSupported if requested api_version is not supported.
|
||||
:raises: *requests* library exception on connection problems.
|
||||
:raises: TypeError if uuid is not a string.
|
||||
"""
|
||||
if not isinstance(uuid, six.string_types):
|
||||
raise TypeError(_("Expected string for uuid argument, got"
|
||||
" %r") % uuid)
|
||||
|
||||
return self.request('post', '/introspection/%s/abort' % uuid)
|
||||
|
||||
|
||||
class _RulesAPI(object):
|
||||
"""Introspection rules API."""
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Introduced command "openstack baremetal introspection abort <UUID>"
|
||||
to abort running introspection for a node.
|
@ -23,6 +23,7 @@ openstack.cli.extension =
|
||||
openstack.baremetal_introspection.v1 =
|
||||
baremetal_introspection_start = ironic_inspector_client.shell:StartCommand
|
||||
baremetal_introspection_status = ironic_inspector_client.shell:StatusCommand
|
||||
baremetal_introspection_abort = ironic_inspector_client.shell:AbortCommand
|
||||
baremetal_introspection_data_save = ironic_inspector_client.shell:DataSaveCommand
|
||||
baremetal_introspection_rule_import = ironic_inspector_client.shell:RuleImportCommand
|
||||
baremetal_introspection_rule_list = ironic_inspector_client.shell:RuleListCommand
|
||||
|
Loading…
Reference in New Issue
Block a user