summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-03-07 19:20:11 +0000
committerGerrit Code Review <review@openstack.org>2017-03-07 19:20:11 +0000
commit054060cbef033b36d22caf47ae44f47e26da597f (patch)
tree1cb6a814c03741e2927f7276aac550a24c29fa3c
parentc0a23b89b16651e0bb07adf1800aa57cbfbb564b (diff)
parentc03b9a871c4fe6b99221cb4b0d1e0eb7c90283fe (diff)
downloadpython-openstackclient-054060cbef033b36d22caf47ae44f47e26da597f.tar.gz
Merge "Add server event list and show commands"
-rw-r--r--doc/source/command-objects/server-event.rst45
-rw-r--r--doc/source/commands.rst1
-rw-r--r--openstackclient/compute/v2/server_event.py117
-rw-r--r--openstackclient/tests/functional/compute/v2/test_server_event.py97
-rw-r--r--openstackclient/tests/unit/compute/v2/fakes.py44
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_event.py167
-rw-r--r--releasenotes/notes/bug-1642030-166b2b28c8adf22e.yaml11
-rw-r--r--setup.cfg3
8 files changed, 485 insertions, 0 deletions
diff --git a/doc/source/command-objects/server-event.rst b/doc/source/command-objects/server-event.rst
new file mode 100644
index 00000000..ef4685f8
--- /dev/null
+++ b/doc/source/command-objects/server-event.rst
@@ -0,0 +1,45 @@
+============
+server event
+============
+
+Server event is the event record that had been done on a server, include: event
+type(create, delete, reboot and so on), event result(success, error), start
+time, finish time and so on. These are important information for server
+maintains.
+
+Compute v2
+
+server event list
+-----------------
+
+List recent events of a server
+
+.. program:: server event list
+.. code:: bash
+
+ openstack server event list
+ <server>
+
+.. describe:: <server>
+
+ Server to list events (name or ID)
+
+server event show
+-----------------
+
+Show server event details
+
+.. program:: server event show
+.. code:: bash
+
+ openstack server event show
+ <server>
+ <request-id>
+
+.. describe:: <server>
+
+ Server to show event details (name or ID)
+
+.. describe:: <request-id>
+
+ Request ID of the event to show (ID only)
diff --git a/doc/source/commands.rst b/doc/source/commands.rst
index a0c67cd4..f4236188 100644
--- a/doc/source/commands.rst
+++ b/doc/source/commands.rst
@@ -137,6 +137,7 @@ referring to both Compute and Volume quotas.
* ``server``: (**Compute**) virtual machine instance
* ``server backup``: (**Compute**) backup server disk image by using snapshot method
* ``server dump``: (**Compute**) a dump file of a server created by features like kdump
+* ``server event``: (**Compute**) events of a server
* ``server group``: (**Compute**) a grouping of servers
* ``server image``: (**Compute**) saved server disk image
* ``service``: (**Identity**) a cloud service
diff --git a/openstackclient/compute/v2/server_event.py b/openstackclient/compute/v2/server_event.py
new file mode 100644
index 00000000..ccb19ef7
--- /dev/null
+++ b/openstackclient/compute/v2/server_event.py
@@ -0,0 +1,117 @@
+# Copyright 2017 Huawei, Inc. All rights reserved.
+#
+# 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.
+#
+
+"""Compute v2 Server operation event implementations"""
+
+import logging
+import six
+
+from osc_lib.command import command
+from osc_lib import utils
+
+from openstackclient.i18n import _
+
+
+LOG = logging.getLogger(__name__)
+
+
+class ListServerEvent(command.Lister):
+ _description = _("List recent events of a server")
+
+ def get_parser(self, prog_name):
+ parser = super(ListServerEvent, self).get_parser(prog_name)
+ parser.add_argument(
+ 'server',
+ metavar='<server>',
+ help=_('Server to list events (name or ID)'),
+ )
+ parser.add_argument(
+ '--long',
+ action='store_true',
+ default=False,
+ help=_("List additional fields in output")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+ server_id = utils.find_resource(compute_client.servers,
+ parsed_args.server).id
+ data = compute_client.instance_action.list(server_id)
+
+ if parsed_args.long:
+ columns = (
+ 'request_id',
+ 'instance_uuid',
+ 'action',
+ 'start_time',
+ 'message',
+ 'project_id',
+ 'user_id',
+ )
+ column_headers = (
+ 'Request ID',
+ 'Server ID',
+ 'Action',
+ 'Start Time',
+ 'Message',
+ 'Project ID',
+ 'User ID',
+ )
+ else:
+ columns = (
+ 'request_id',
+ 'instance_uuid',
+ 'action',
+ 'start_time',
+ )
+ column_headers = (
+ 'Request ID',
+ 'Server ID',
+ 'Action',
+ 'Start Time',
+ )
+
+ return (column_headers,
+ (utils.get_item_properties(
+ s, columns,
+ ) for s in data))
+
+
+class ShowServerEvent(command.ShowOne):
+ _description = _("Show server event details")
+
+ def get_parser(self, prog_name):
+ parser = super(ShowServerEvent, self).get_parser(prog_name)
+ parser.add_argument(
+ 'server',
+ metavar='<server>',
+ help=_('Server to show event details (name or ID)'),
+ )
+ parser.add_argument(
+ 'request_id',
+ metavar='<request-id>',
+ help=_('Request ID of the event to show (ID only)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+ server_id = utils.find_resource(compute_client.servers,
+ parsed_args.server).id
+ action_detail = compute_client.instance_action.get(
+ server_id, parsed_args.request_id)
+
+ return zip(*sorted(six.iteritems(action_detail._info)))
diff --git a/openstackclient/tests/functional/compute/v2/test_server_event.py b/openstackclient/tests/functional/compute/v2/test_server_event.py
new file mode 100644
index 00000000..6be5822f
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_server_event.py
@@ -0,0 +1,97 @@
+# Copyright 2017 Huawei, Inc. All rights reserved.
+#
+# 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 json
+import uuid
+
+from openstackclient.tests.functional import base
+from openstackclient.tests.functional.compute.v2 import test_server
+
+
+class ServerEventTests(base.TestCase):
+ """Functional tests for server event."""
+
+ def setUp(self):
+ super(ServerEventTests, self).setUp()
+ _flavor = test_server.ServerTests.get_flavor()
+ _image = test_server.ServerTests.get_image()
+ _network = test_server.ServerTests.get_network()
+ self.server_name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'server create -f json ' +
+ '--flavor ' + _flavor + ' ' +
+ '--image ' + _image + ' ' +
+ _network + ' ' +
+ '--wait ' +
+ self.server_name
+ ))
+ if not cmd_output:
+ self.fail('Server has not been created!')
+ self.addCleanup(self.openstack, 'server delete ' + self.server_name)
+ self.assertEqual(self.server_name, cmd_output['name'])
+ self.server_id = cmd_output.get('id')
+
+ def test_server_event_list_and_show(self):
+ """Test list, show server event"""
+ # Test 'server event list' for creating
+ cmd_output = json.loads(self.openstack(
+ 'server event list -f json ' + self.server_name
+ ))
+ request_id = None
+ for each_event in cmd_output:
+ self.assertNotIn('Message', each_event)
+ self.assertNotIn('Project ID', each_event)
+ self.assertNotIn('User ID', each_event)
+ if each_event.get('Action') == 'create':
+ self.assertEqual(self.server_id, each_event.get('Server ID'))
+ request_id = each_event.get('Request ID')
+ break
+ self.assertIsNotNone(request_id)
+ # Test 'server event show' for creating
+ cmd_output = json.loads(self.openstack(
+ 'server event show -f json ' + self.server_name + ' ' + request_id
+ ))
+ self.assertEqual(self.server_id, cmd_output.get('instance_uuid'))
+ self.assertEqual(request_id, cmd_output.get('request_id'))
+ self.assertEqual('create', cmd_output.get('action'))
+ self.assertIsNotNone(cmd_output.get('events'))
+ self.assertIsInstance(cmd_output.get('events'), list)
+
+ # Reboot server, trigger reboot event
+ self.openstack('server reboot --wait ' + self.server_name)
+ # Test 'server event list --long' for rebooting
+ cmd_output = json.loads(self.openstack(
+ 'server event list --long -f json ' + self.server_name
+ ))
+ request_id = None
+ for each_event in cmd_output:
+ self.assertIn('Message', each_event)
+ self.assertIn('Project ID', each_event)
+ self.assertIn('User ID', each_event)
+ if each_event.get('Action') == 'reboot':
+ request_id = each_event.get('Request ID')
+ self.assertEqual(self.server_id, each_event.get('Server ID'))
+ break
+ self.assertIsNotNone(request_id)
+ # Test 'server event show' for rebooting
+ cmd_output = json.loads(self.openstack(
+ 'server event show -f json ' + self.server_name + ' ' + request_id
+ ))
+
+ self.assertEqual(self.server_id, cmd_output.get('instance_uuid'))
+ self.assertEqual(request_id, cmd_output.get('request_id'))
+ self.assertEqual('reboot', cmd_output.get('action'))
+ self.assertIsNotNone(cmd_output.get('events'))
+ self.assertIsInstance(cmd_output.get('events'), list)
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
index 4fe735b6..bbb770bb 100644
--- a/openstackclient/tests/unit/compute/v2/fakes.py
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -204,6 +204,9 @@ class FakeComputev2Client(object):
self.server_groups = mock.Mock()
self.server_groups.resource_class = fakes.FakeResource(None, {})
+ self.instance_action = mock.Mock()
+ self.instance_action.resource_class = fakes.FakeResource(None, {})
+
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
@@ -656,6 +659,47 @@ class FakeServer(object):
return mock.Mock(side_effect=servers)
+class FakeServerEvent(object):
+ """Fake one or more server event."""
+
+ @staticmethod
+ def create_one_server_event(attrs=None):
+ """Create a fake server event.
+
+ :param attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id and other attributes
+ """
+ attrs = attrs or {}
+
+ # Set default attributes
+ server_event_info = {
+ "instance_uuid": "server-event-" + uuid.uuid4().hex,
+ "user_id": "user-id-" + uuid.uuid4().hex,
+ "start_time": "2017-02-27T07:47:13.000000",
+ "request_id": "req-" + uuid.uuid4().hex,
+ "action": "create",
+ "message": None,
+ "project_id": "project-id-" + uuid.uuid4().hex,
+ "events": [{
+ "finish_time": "2017-02-27T07:47:25.000000",
+ "start_time": "2017-02-27T07:47:15.000000",
+ "traceback": None,
+ "event": "compute__do_build_and_run_instance",
+ "result": "Success"
+ }]
+ }
+ # Overwrite default attributes
+ server_event_info.update(attrs)
+
+ server_event = fakes.FakeResource(
+ info=copy.deepcopy(server_event_info),
+ loaded=True,
+ )
+ return server_event
+
+
class FakeService(object):
"""Fake one or more services."""
diff --git a/openstackclient/tests/unit/compute/v2/test_server_event.py b/openstackclient/tests/unit/compute/v2/test_server_event.py
new file mode 100644
index 00000000..5c94891a
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_server_event.py
@@ -0,0 +1,167 @@
+# Copyright 2017 Huawei, Inc. All rights reserved.
+#
+# 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 openstackclient.compute.v2 import server_event
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+
+
+class TestServerEvent(compute_fakes.TestComputev2):
+
+ fake_server = compute_fakes.FakeServer.create_one_server()
+
+ def setUp(self):
+ super(TestServerEvent, self).setUp()
+
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+ self.events_mock = self.app.client_manager.compute.instance_action
+ self.events_mock.reset_mock()
+
+ self.servers_mock.get.return_value = self.fake_server
+
+
+class TestListServerEvent(TestServerEvent):
+
+ fake_event = compute_fakes.FakeServerEvent.create_one_server_event()
+
+ columns = (
+ 'Request ID',
+ 'Server ID',
+ 'Action',
+ 'Start Time',
+ )
+ data = ((
+ fake_event.request_id,
+ fake_event.instance_uuid,
+ fake_event.action,
+ fake_event.start_time,
+ ), )
+
+ long_columns = (
+ 'Request ID',
+ 'Server ID',
+ 'Action',
+ 'Start Time',
+ 'Message',
+ 'Project ID',
+ 'User ID',
+ )
+ long_data = ((
+ fake_event.request_id,
+ fake_event.instance_uuid,
+ fake_event.action,
+ fake_event.start_time,
+ fake_event.message,
+ fake_event.project_id,
+ fake_event.user_id,
+ ), )
+
+ def setUp(self):
+ super(TestListServerEvent, self).setUp()
+
+ self.events_mock.list.return_value = [self.fake_event, ]
+ self.cmd = server_event.ListServerEvent(self.app, None)
+
+ def test_server_event_list(self):
+ arglist = [
+ self.fake_server.name,
+ ]
+ verifylist = [
+ ('server', self.fake_server.name),
+ ('long', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_once_with(self.fake_server.name)
+ self.events_mock.list.assert_called_once_with(self.fake_server.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
+
+ def test_server_event_list_long(self):
+ arglist = [
+ '--long',
+ self.fake_server.name,
+ ]
+ verifylist = [
+ ('server', self.fake_server.name),
+ ('long', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_once_with(self.fake_server.name)
+ self.events_mock.list.assert_called_once_with(self.fake_server.id)
+
+ self.assertEqual(self.long_columns, columns)
+ self.assertEqual(self.long_data, tuple(data))
+
+
+class TestShowServerEvent(TestServerEvent):
+
+ fake_event = compute_fakes.FakeServerEvent.create_one_server_event()
+
+ columns = (
+ 'action',
+ 'events',
+ 'instance_uuid',
+ 'message',
+ 'project_id',
+ 'request_id',
+ 'start_time',
+ 'user_id',
+ )
+ data = (
+ fake_event.action,
+ fake_event.events,
+ fake_event.instance_uuid,
+ fake_event.message,
+ fake_event.project_id,
+ fake_event.request_id,
+ fake_event.start_time,
+ fake_event.user_id,
+ )
+
+ def setUp(self):
+ super(TestShowServerEvent, self).setUp()
+
+ self.events_mock.get.return_value = self.fake_event
+ self.cmd = server_event.ShowServerEvent(self.app, None)
+
+ def test_server_event_show(self):
+ arglist = [
+ self.fake_server.name,
+ self.fake_event.request_id,
+ ]
+ verifylist = [
+ ('server', self.fake_server.name),
+ ('request_id', self.fake_event.request_id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_once_with(self.fake_server.name)
+ self.events_mock.get.assert_called_once_with(
+ self.fake_server.id, self.fake_event.request_id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/releasenotes/notes/bug-1642030-166b2b28c8adf22e.yaml b/releasenotes/notes/bug-1642030-166b2b28c8adf22e.yaml
new file mode 100644
index 00000000..200c73fb
--- /dev/null
+++ b/releasenotes/notes/bug-1642030-166b2b28c8adf22e.yaml
@@ -0,0 +1,11 @@
+---
+features:
+ - |
+ Add ``server event`` list and show commands, that is similar to nova's
+ instance action commands.
+
+ Server event is the event record that had been done on a server,
+ include: event type(create, delete, reboot and so on),
+ event result(success, error), start time, finish time and so on.
+ These are important information for server maintains.
+ [Bug `1642030 <https://bugs.launchpad.net/python-openstackclient/+bug/1642030>`_]
diff --git a/setup.cfg b/setup.cfg
index e18aa5c1..ea4691b3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -135,6 +135,9 @@ openstack.compute.v2 =
server_backup_create = openstackclient.compute.v2.server_backup:CreateServerBackup
+ server_event_list = openstackclient.compute.v2.server_event:ListServerEvent
+ server_event_show = openstackclient.compute.v2.server_event:ShowServerEvent
+
server_group_create = openstackclient.compute.v2.server_group:CreateServerGroup
server_group_delete = openstackclient.compute.v2.server_group:DeleteServerGroup
server_group_list = openstackclient.compute.v2.server_group:ListServerGroup