Add OSC plugin for openstack cluster event list
This change implements the "openstack cluster event list" command Based on the existing senlin command: senlin event-list Change-Id: Ibcdb25978c551226d3600c80ee7a557574e338e0 Blueprint: senlin-support-python-openstackclient
This commit is contained in:
102
senlinclient/osc/v1/event.py
Normal file
102
senlinclient/osc/v1/event.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# 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.
|
||||
|
||||
"""Clustering v1 event action implementations"""
|
||||
|
||||
import logging
|
||||
|
||||
from cliff import lister
|
||||
from openstackclient.common import utils
|
||||
|
||||
from senlinclient.common.i18n import _
|
||||
from senlinclient.common import utils as senlin_utils
|
||||
|
||||
|
||||
class ListEvent(lister.Lister):
|
||||
"""List events."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListEvent")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListEvent, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--filters',
|
||||
metavar='<key1=value1;key2=value2...>',
|
||||
help=_("Filter parameters to apply on returned events. "
|
||||
"This can be specified multiple times, or once with "
|
||||
"parameters separated by a semicolon. The valid filter "
|
||||
"keys are: ['level', 'obj_type', 'obj_id' ,'cluster_id', "
|
||||
"'obj_name', 'action']"),
|
||||
action='append'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
help=_('Limit the number of events returned')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
metavar='<id>',
|
||||
help=_('Only return events that appear after the given event ID')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sort',
|
||||
metavar='<key:dir>',
|
||||
help=_("Sorting option which is a string containing a list of "
|
||||
"keys separated by commas. Each key can be optionally "
|
||||
"appended by a sort direction (:asc or :desc). The valid "
|
||||
"sort keys are: ['timestamp', 'level', 'obj_type', "
|
||||
"'obj_name', 'user', 'action', 'status']")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--global-project',
|
||||
default=False,
|
||||
action="store_true",
|
||||
help=_('Whether events from all projects should be listed. '
|
||||
' Default to False. Setting this to True may demand '
|
||||
'for an admin privilege')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--full-id',
|
||||
default=False,
|
||||
action="store_true",
|
||||
help=_('Print full IDs in list')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
senlin_client = self.app.client_manager.clustering
|
||||
columns = ['id', 'timestamp', 'obj_type', 'obj_id', 'obj_name',
|
||||
'action', 'status', 'status_reason', 'level']
|
||||
queries = {
|
||||
'sort': parsed_args.sort,
|
||||
'limit': parsed_args.limit,
|
||||
'marker': parsed_args.marker,
|
||||
'global_project': parsed_args.global_project,
|
||||
}
|
||||
|
||||
if parsed_args.filters:
|
||||
queries.update(senlin_utils.format_parameters(parsed_args.filters))
|
||||
|
||||
formatters = {}
|
||||
if not parsed_args.full_id:
|
||||
formatters['id'] = lambda x: x[:8]
|
||||
formatters['obj_id'] = lambda x: x[:8] if x else ''
|
||||
|
||||
events = senlin_client.events(**queries)
|
||||
return (
|
||||
columns,
|
||||
(utils.get_item_properties(e, columns, formatters=formatters)
|
||||
for e in events)
|
||||
)
|
||||
134
senlinclient/tests/unit/osc/v1/test_event.py
Normal file
134
senlinclient/tests/unit/osc/v1/test_event.py
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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 mock
|
||||
|
||||
from openstack.cluster.v1 import event as sdk_event
|
||||
from openstack import exceptions as sdk_exc
|
||||
|
||||
from senlinclient.osc.v1 import event as osc_event
|
||||
from senlinclient.tests.unit.osc.v1 import fakes
|
||||
|
||||
|
||||
class TestEvent(fakes.TestClusteringv1):
|
||||
def setUp(self):
|
||||
super(TestEvent, self).setUp()
|
||||
self.mock_client = self.app.client_manager.clustering
|
||||
|
||||
|
||||
class TestEventList(TestEvent):
|
||||
|
||||
columns = ['id', 'timestamp', 'obj_type', 'obj_id', 'obj_name', 'action',
|
||||
'status', 'status_reason', 'level']
|
||||
|
||||
response = {"events": [
|
||||
{
|
||||
"action": "create",
|
||||
"cluster_id": 'null',
|
||||
"id": "2d255b9c-8f36-41a2-a137-c0175ccc29c3",
|
||||
"level": "20",
|
||||
"obj_id": "0df0931b-e251-4f2e-8719-4ebfda3627ba",
|
||||
"obj_name": "node009",
|
||||
"obj_type": "NODE",
|
||||
"project": "6e18cc2bdbeb48a5b3cad2dc499f6804",
|
||||
"status": "CREATING",
|
||||
"status_reason": "Initializing",
|
||||
"timestamp": "2015-03-05T08:53:15",
|
||||
"user": "a21ded6060534d99840658a777c2af5a"
|
||||
}
|
||||
]}
|
||||
|
||||
defaults = {
|
||||
'global_project': False,
|
||||
'marker': None,
|
||||
'limit': None,
|
||||
'sort': None,
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(TestEventList, self).setUp()
|
||||
self.cmd = osc_event.ListEvent(self.app, None)
|
||||
self.mock_client.events = mock.Mock(
|
||||
return_value=sdk_event.Event(None, {}))
|
||||
|
||||
def test_event_list_defaults(self):
|
||||
arglist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**self.defaults)
|
||||
self.assertEqual(self.columns, columns)
|
||||
|
||||
def test_event_list_full_id(self):
|
||||
arglist = ['--full-id']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**self.defaults)
|
||||
self.assertEqual(self.columns, columns)
|
||||
|
||||
def test_event_list_limit(self):
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['limit'] = '3'
|
||||
arglist = ['--limit', '3']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**kwargs)
|
||||
self.assertEqual(self.columns, columns)
|
||||
|
||||
def test_event_list_sort(self):
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['sort'] = 'name:asc'
|
||||
arglist = ['--sort', 'name:asc']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**kwargs)
|
||||
self.assertEqual(self.columns, columns)
|
||||
|
||||
def test_event_list_sort_invalid_key(self):
|
||||
self.mock_client.events = mock.Mock(
|
||||
return_value=self.response)
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['sort'] = 'bad_key'
|
||||
arglist = ['--sort', 'bad_key']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
self.mock_client.events.side_effect = sdk_exc.HttpException()
|
||||
self.assertRaises(sdk_exc.HttpException,
|
||||
self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_event_list_sort_invalid_direction(self):
|
||||
self.mock_client.events = mock.Mock(
|
||||
return_value=self.response)
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['sort'] = 'name:bad_direction'
|
||||
arglist = ['--sort', 'name:bad_direction']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
self.mock_client.events.side_effect = sdk_exc.HttpException()
|
||||
self.assertRaises(sdk_exc.HttpException,
|
||||
self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_event_list_filter(self):
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['name'] = 'my_event'
|
||||
arglist = ['--filter', 'name=my_event']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**kwargs)
|
||||
self.assertEqual(self.columns, columns)
|
||||
|
||||
def test_event_list_marker(self):
|
||||
kwargs = copy.deepcopy(self.defaults)
|
||||
kwargs['marker'] = 'a9448bf6'
|
||||
arglist = ['--marker', 'a9448bf6']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.mock_client.events.assert_called_with(**kwargs)
|
||||
self.assertEqual(self.columns, columns)
|
||||
@@ -32,6 +32,7 @@ openstack.cli.extension =
|
||||
openstack.clustering.v1 =
|
||||
cluster_create = senlinclient.osc.v1.cluster:CreateCluster
|
||||
cluster_delete = senlinclient.osc.v1.cluster:DeleteCluster
|
||||
cluster_event_list = senlinclient.osc.v1.event:ListEvent
|
||||
cluster_list = senlinclient.osc.v1.cluster:ListCluster
|
||||
cluster_resize = senlinclient.osc.v1.cluster:ResizeCluster
|
||||
cluster_scale_in = senlinclient.osc.v1.cluster:ScaleInCluster
|
||||
|
||||
Reference in New Issue
Block a user