Add operation log API cmd to karborclient
Change-Id: I097ec3424b47939ff00f417bedb186305de39a62 blueprint: operation-log-api
This commit is contained in:
111
karborclient/osc/v1/operation_logs.py
Normal file
111
karborclient/osc/v1/operation_logs.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# 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.
|
||||
|
||||
"""Data protection V1 operation_log action implementations"""
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as osc_utils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from karborclient.i18n import _
|
||||
|
||||
|
||||
class ListOperationLogs(command.Lister):
|
||||
_description = _("List operation_logs.")
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListOperationLogs")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListOperationLogs, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--all-projects',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Include all projects (admin only)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--status',
|
||||
metavar='<status>',
|
||||
help=_('Filter results by status'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
metavar='<operation_log>',
|
||||
help=_('The last operation_log ID of the previous page'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
type=int,
|
||||
metavar='<num-operation_logs>',
|
||||
help=_('Maximum number of operation_logs to display'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sort',
|
||||
metavar="<key>[:<direction>]",
|
||||
default=None,
|
||||
help=_("Sort output by selected keys and directions(asc or desc), "
|
||||
"multiple keys and directions can be "
|
||||
"specified separated by comma"),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--project',
|
||||
metavar='<project>',
|
||||
help=_('Filter results by a project(admin only)')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
data_protection_client = self.app.client_manager.data_protection
|
||||
all_projects = bool(parsed_args.project) or parsed_args.all_projects
|
||||
|
||||
search_opts = {
|
||||
'all_tenants': all_projects,
|
||||
'project_id': parsed_args.project,
|
||||
'status': parsed_args.status,
|
||||
}
|
||||
|
||||
data = data_protection_client.operation_logs.list(
|
||||
search_opts=search_opts, marker=parsed_args.marker,
|
||||
limit=parsed_args.limit, sort=parsed_args.sort)
|
||||
|
||||
column_headers = ['Id', 'Operation Type', 'Checkpoint id',
|
||||
'Plan Id', 'Provider id', 'Restore Id',
|
||||
'Scheduled Operation Id', 'Status',
|
||||
'Started At', 'Ended At', 'Error Info',
|
||||
'Extra Info']
|
||||
|
||||
return (column_headers,
|
||||
(osc_utils.get_item_properties(
|
||||
s, column_headers
|
||||
) for s in data))
|
||||
|
||||
|
||||
class ShowOperationLog(command.ShowOne):
|
||||
_description = "Shows operation_log details"
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowOperationLog, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'operation_log',
|
||||
metavar="<operation_log>",
|
||||
help=_('The UUID of the operation_log.')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.data_protection
|
||||
operation_log = osc_utils.find_resource(client.operation_logs,
|
||||
parsed_args.operation_log)
|
||||
|
||||
operation_log._info.pop("links", None)
|
||||
return zip(*sorted(operation_log._info.items()))
|
||||
124
karborclient/tests/unit/osc/v1/test_operation_logs.py
Normal file
124
karborclient/tests/unit/osc/v1/test_operation_logs.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# 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 karborclient.osc.v1 import operation_logs as osc_operation_logs
|
||||
from karborclient.tests.unit.osc.v1 import fakes
|
||||
from karborclient.v1 import operation_logs
|
||||
|
||||
|
||||
OPERATIONLOG_INFO = {
|
||||
"id": "22b82aa7-9179-4c71-bba2-caf5c0e68db7",
|
||||
"project_id": "e486a2f49695423ca9c47e589b948108",
|
||||
"operation_type": "protect",
|
||||
"checkpoint_id": "dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
|
||||
"plan_id": "cf56bd3e-97a7-4078-b6d5-f36246333fd9",
|
||||
"provider_id": "23902b02-5666-4ee6-8dfe-962ac09c3994",
|
||||
"restore_id": None,
|
||||
"scheduled_operation_id": "23902b02-5666-4ee6-8dfe-962ac09c3991",
|
||||
"started_at": "2015-08-27T09:50:58-05:00",
|
||||
"ended_at": "2015-08-27T10:50:58-05:00",
|
||||
"status": "protecting",
|
||||
"error_info": "Could not access bank",
|
||||
"extra_info": None
|
||||
}
|
||||
|
||||
|
||||
class TestOperationLogs(fakes.TestDataProtection):
|
||||
def setUp(self):
|
||||
super(TestOperationLogs, self).setUp()
|
||||
self.operation_logs_mock = (
|
||||
self.app.client_manager.data_protection.operation_logs)
|
||||
self.operation_logs_mock.reset_mock()
|
||||
|
||||
|
||||
class TestListOperationLogs(TestOperationLogs):
|
||||
def setUp(self):
|
||||
super(TestListOperationLogs, self).setUp()
|
||||
self.operation_logs_mock.list.return_value = [
|
||||
operation_logs.OperationLog(None, OPERATIONLOG_INFO)]
|
||||
|
||||
# Command to test
|
||||
self.cmd = osc_operation_logs.ListOperationLogs(self.app, None)
|
||||
|
||||
def test_operation_logs_list(self):
|
||||
arglist = ['--status', 'success']
|
||||
verifylist = [('status', 'success')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Check that columns are correct
|
||||
expected_columns = (
|
||||
['Id', 'Operation Type', 'Checkpoint id', 'Plan Id',
|
||||
'Provider id', 'Restore Id', 'Scheduled Operation Id',
|
||||
'Status', 'Started At', 'Ended At', 'Error Info',
|
||||
'Extra Info'])
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
# Check that data is correct
|
||||
expected_data = [("22b82aa7-9179-4c71-bba2-caf5c0e68db7",
|
||||
"protect",
|
||||
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
|
||||
"cf56bd3e-97a7-4078-b6d5-f36246333fd9",
|
||||
"23902b02-5666-4ee6-8dfe-962ac09c3994",
|
||||
None,
|
||||
"23902b02-5666-4ee6-8dfe-962ac09c3991",
|
||||
"protecting",
|
||||
"2015-08-27T09:50:58-05:00",
|
||||
"2015-08-27T10:50:58-05:00",
|
||||
"Could not access bank",
|
||||
None)]
|
||||
self.assertEqual(expected_data, list(data))
|
||||
|
||||
|
||||
class TestShowOperationLog(TestOperationLogs):
|
||||
def setUp(self):
|
||||
super(TestShowOperationLog, self).setUp()
|
||||
self.operation_logs_mock.get.return_value = (
|
||||
operation_logs.OperationLog(None, OPERATIONLOG_INFO))
|
||||
|
||||
# Command to test
|
||||
self.cmd = osc_operation_logs.ShowOperationLog(self.app, None)
|
||||
|
||||
def test_operation_log_show(self):
|
||||
arglist = ['22b82aa7-9179-4c71-bba2-caf5c0e68db7']
|
||||
verifylist = [('operation_log',
|
||||
'22b82aa7-9179-4c71-bba2-caf5c0e68db7')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Check that columns are correct
|
||||
expected_columns = (
|
||||
'checkpoint_id', 'ended_at', 'error_info', 'extra_info',
|
||||
'id', 'operation_type', 'plan_id', 'project_id',
|
||||
'provider_id', 'restore_id', 'scheduled_operation_id',
|
||||
'started_at', 'status')
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
# Check that data is correct
|
||||
self.assertEqual(OPERATIONLOG_INFO['checkpoint_id'], data[0])
|
||||
self.assertEqual(OPERATIONLOG_INFO['ended_at'], data[1])
|
||||
self.assertEqual(OPERATIONLOG_INFO['error_info'], data[2])
|
||||
self.assertEqual(OPERATIONLOG_INFO['extra_info'], data[3])
|
||||
self.assertEqual(OPERATIONLOG_INFO['id'], data[4])
|
||||
self.assertEqual(OPERATIONLOG_INFO['operation_type'], data[5])
|
||||
self.assertEqual(OPERATIONLOG_INFO['plan_id'], data[6])
|
||||
self.assertEqual(OPERATIONLOG_INFO['project_id'], data[7])
|
||||
self.assertEqual(OPERATIONLOG_INFO['provider_id'], data[8])
|
||||
self.assertEqual(OPERATIONLOG_INFO['restore_id'], data[9])
|
||||
self.assertEqual(OPERATIONLOG_INFO['scheduled_operation_id'], data[10])
|
||||
self.assertEqual(OPERATIONLOG_INFO['started_at'], data[11])
|
||||
self.assertEqual(OPERATIONLOG_INFO['status'], data[12])
|
||||
63
karborclient/tests/unit/v1/test_operation_logs.py
Normal file
63
karborclient/tests/unit/v1/test_operation_logs.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# 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 mock
|
||||
|
||||
from karborclient.tests.unit import base
|
||||
from karborclient.tests.unit.v1 import fakes
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
mock_request_return = ({}, {'operation_log': {}})
|
||||
|
||||
|
||||
class OperationLogsTest(base.TestCaseShell):
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs_with_marker_limit(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.list(marker=1234, limit=2)
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs?limit=2&marker=1234', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs_with_sort_key_dir(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.list(sort_key='id', sort_dir='asc')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs?'
|
||||
'sort_dir=asc&sort_key=id', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs_with_invalid_sort_key(self, mock_request):
|
||||
self.assertRaises(ValueError,
|
||||
cs.operation_logs.list,
|
||||
sort_key='invalid', sort_dir='asc')
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_operation_log(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.get('1')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs/1',
|
||||
headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_operation_log_with_headers(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.get('1', session_id='fake_session_id')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs/1',
|
||||
headers={'X-Configuration-Session': 'fake_session_id'})
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
from karborclient.common import http
|
||||
from karborclient.v1 import checkpoints
|
||||
from karborclient.v1 import operation_logs
|
||||
from karborclient.v1 import plans
|
||||
from karborclient.v1 import protectables
|
||||
from karborclient.v1 import providers
|
||||
@@ -42,3 +43,5 @@ class Client(object):
|
||||
self.triggers = triggers.TriggerManager(self.http_client)
|
||||
self.scheduled_operations = \
|
||||
scheduled_operations.ScheduledOperationManager(self.http_client)
|
||||
self.operation_logs = \
|
||||
operation_logs.OperationLogManager(self.http_client)
|
||||
|
||||
44
karborclient/v1/operation_logs.py
Normal file
44
karborclient/v1/operation_logs.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# 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 karborclient.common import base
|
||||
|
||||
|
||||
class OperationLog(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<OperationLog %s>" % self._info
|
||||
|
||||
|
||||
class OperationLogManager(base.ManagerWithFind):
|
||||
resource_class = OperationLog
|
||||
|
||||
def get(self, operation_log_id, session_id=None):
|
||||
if session_id:
|
||||
headers = {'X-Configuration-Session': session_id}
|
||||
else:
|
||||
headers = {}
|
||||
url = "/operation_logs/{operation_log_id}".format(
|
||||
operation_log_id=operation_log_id)
|
||||
return self._get(url, response_key="operation_log", headers=headers)
|
||||
|
||||
def list(self, detailed=False, search_opts=None, marker=None, limit=None,
|
||||
sort_key=None, sort_dir=None, sort=None):
|
||||
"""Lists all operation_logs.
|
||||
|
||||
"""
|
||||
resource_type = "operation_logs"
|
||||
url = self._build_list_url(
|
||||
resource_type, detailed=detailed,
|
||||
search_opts=search_opts, marker=marker,
|
||||
limit=limit, sort_key=sort_key,
|
||||
sort_dir=sort_dir, sort=sort)
|
||||
return self._list(url, 'operation_logs')
|
||||
@@ -1018,3 +1018,93 @@ def do_scheduledoperation_delete(cs, args):
|
||||
if failure_count == len(args.scheduledoperation):
|
||||
raise exceptions.CommandError("Unable to find and delete any of the "
|
||||
"specified scheduled operation.")
|
||||
|
||||
|
||||
@utils.arg('--all-tenants',
|
||||
dest='all_tenants',
|
||||
metavar='<0|1>',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
default=0,
|
||||
help='Shows details for all tenants. Admin only.')
|
||||
@utils.arg('--all_tenants',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--status',
|
||||
metavar='<status>',
|
||||
default=None,
|
||||
help='Filters results by a status. Default=None.')
|
||||
@utils.arg('--marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help='Begin returning restores that appear later in the '
|
||||
'operation_log list than that represented by this '
|
||||
'operation_logs id. Default=None.')
|
||||
@utils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
default=None,
|
||||
help='Maximum number of operation_logs to return. Default=None.')
|
||||
@utils.arg('--sort_key',
|
||||
metavar='<sort_key>',
|
||||
default=None,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--sort_dir',
|
||||
metavar='<sort_dir>',
|
||||
default=None,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--sort',
|
||||
metavar='<key>[:<direction>]',
|
||||
default=None,
|
||||
help=(('Comma-separated list of sort keys and directions in the '
|
||||
'form of <key>[:<asc|desc>]. '
|
||||
'Valid keys: %s. '
|
||||
'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
|
||||
@utils.arg('--tenant',
|
||||
type=str,
|
||||
dest='tenant',
|
||||
nargs='?',
|
||||
metavar='<tenant>',
|
||||
help='Display information from single tenant (Admin only).')
|
||||
def do_operationlog_list(cs, args):
|
||||
"""Lists all operation_logs."""
|
||||
|
||||
all_tenants = 1 if args.tenant else \
|
||||
int(os.environ.get("ALL_TENANTS", args.all_tenants))
|
||||
search_opts = {
|
||||
'all_tenants': all_tenants,
|
||||
'project_id': args.tenant,
|
||||
'status': args.status,
|
||||
}
|
||||
|
||||
if args.sort and (args.sort_key or args.sort_dir):
|
||||
raise exceptions.CommandError(
|
||||
'The --sort_key and --sort_dir arguments are deprecated and are '
|
||||
'not supported with --sort.')
|
||||
|
||||
operation_logs = cs.operation_logs.list(
|
||||
search_opts=search_opts, marker=args.marker,
|
||||
limit=args.limit, sort_key=args.sort_key,
|
||||
sort_dir=args.sort_dir, sort=args.sort)
|
||||
|
||||
key_list = ['Id', 'Operation Type', 'Checkpoint id', 'Plan Id',
|
||||
'Provider id', 'Restore Id', 'Scheduled Operation Id',
|
||||
'Status', 'Started At', 'Ended At', 'Error Info', 'Extra Info']
|
||||
|
||||
if args.sort_key or args.sort_dir or args.sort:
|
||||
sortby_index = None
|
||||
else:
|
||||
sortby_index = 0
|
||||
utils.print_list(operation_logs, key_list, exclude_unavailable=True,
|
||||
sortby_index=sortby_index)
|
||||
|
||||
|
||||
@utils.arg('operation_log',
|
||||
metavar='<operation_log>',
|
||||
help='ID of operation_log.')
|
||||
def do_operationlog_show(cs, args):
|
||||
"""Shows operation_log details."""
|
||||
operation_log = cs.operation_logs.get(args.operation_log)
|
||||
utils.print_dict(operation_log.to_dict())
|
||||
|
||||
@@ -61,6 +61,8 @@ openstack.data_protection.v1 =
|
||||
data_protection_scheduledoperation_show = karborclient.osc.v1.scheduled_operations:ShowScheduledOperation
|
||||
data_protection_scheduledoperation_create = karborclient.osc.v1.scheduled_operations:CreateScheduledOperation
|
||||
data_protection_scheduledoperation_delete = karborclient.osc.v1.scheduled_operations:DeleteScheduledOperation
|
||||
data_protection_operationlog_list = karborclient.osc.v1.operation_logs:ListOperationLogs
|
||||
data_protection_operationlog_show = karborclient.osc.v1.operation_logs:ShowOperationLog
|
||||
|
||||
[compile_catalog]
|
||||
directory = karborclient/locale
|
||||
|
||||
Reference in New Issue
Block a user