Compare commits

..

9 Commits
0.4.0 ... 0.6.0

Author SHA1 Message Date
Yuval Brik
d5842f6196 Docs: arrange guides
Change-Id: I956d0137f3c1507d58aac0d9b22b6737473e55be
2017-07-27 12:10:38 +03:00
Jenkins
423e4d5b48 Merge "Add operation log API cmd to karborclient" 2017-07-27 06:23:16 +00:00
OpenStack Proposal Bot
30ee5f4829 Updated from global requirements
Change-Id: If26478dac87f9bc018e71c8ac8f39662aa37aeb2
2017-07-23 13:51:53 +00:00
OpenStack Proposal Bot
4839860b73 Updated from global requirements
Change-Id: Id0331e836c7530a6fce73a909675a0972b52236a
2017-07-22 16:38:24 +00:00
Hangdong Zhang
28ab39e6fb Update URLs in documentation
Update URLs according to OpenStack document migration.
BTW: Do some optimization as well (http -> https)

Change-Id: Ie0a5e08a0611715c6cb775b875b4fcae3b622780
2017-07-20 15:57:42 +08:00
Akihiro Motoki
a907bc2a34 Fix wrong entry points which breaks OSC gate
Change-Id: Ia7ed435b397a1ef82a0b8133c5009e1045ee3816
2017-07-19 12:42:56 +00:00
chenying
cb0b8b0515 Add operation log API cmd to karborclient
Change-Id: I097ec3424b47939ff00f417bedb186305de39a62
blueprint: operation-log-api
2017-07-18 15:42:05 +08:00
yushangbin
05c98f7a20 Fix warning in doc generating
Doc generating shows warning "Title overline too short", this patch
fixes that.

Change-Id: I7dff4f0e4425fcf99a3da690ede4c4659cb46222
2017-07-17 15:44:52 +08:00
rajat29
2d6a97e84a Update URLs in documents according to document migration
Change-Id: Ifd15ac7b3d1ef0b4ab450f797169b83991e8e250
2017-07-14 15:50:38 +05:30
20 changed files with 492 additions and 24 deletions

View File

@@ -1,14 +1,14 @@
If you would like to contribute to the development of OpenStack, you must
follow the steps in this page:
http://docs.openstack.org/infra/manual/developers.html
https://docs.openstack.org/infra/manual/developers.html
If you already have a good understanding of how the system works and your
OpenStack accounts are set up, you can skip to the development workflow
section of this documentation to learn how changes to OpenStack should be
submitted for review via the Gerrit tool:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
https://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.

View File

@@ -1,4 +1,4 @@
Style Commandments
===============================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

View File

@@ -7,6 +7,7 @@ Team and repository tags
.. Change things from this point on
======
Karbor
======
@@ -39,8 +40,8 @@ Karbor Mission Statement
.. _Blueprints: https://blueprints.launchpad.net/python-karborclient
.. _Bugs: https://bugs.launchpad.net/python-karborclient
.. _Source: https://git.openstack.org/cgit/openstack/python-karborclient
.. _Specs: http://docs.openstack.org/developer/karbor/specs/index.html
.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html
.. _Specs: https://docs.openstack.org/karbor/latest/specs/index.html
.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html
Python Karborclient
@@ -62,7 +63,7 @@ Project status, bugs, and blueprints are tracked on Launchpad:
Developer documentation can be found here:
http://docs.openstack.org/developer/karbor
https://docs.openstack.org/karbor/latest/
Additional resources are linked from the project wiki page:

View File

@@ -1,4 +0,0 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

View File

@@ -0,0 +1,16 @@
============
Contributing
============
General Info
============
.. include:: ../../../CONTRIBUTING.rst
Approved Specs
==============
.. toctree::
:maxdepth: 1
../specs/index

View File

@@ -4,12 +4,12 @@ Welcome to karborclient's documentation!
Contents:
.. toctree::
:maxdepth: 2
:maxdepth: 1
readme
installation
usage
contributing
install/index
user/index
contributor/index
Indices and tables
==================

View File

@@ -1 +1,5 @@
############
Introduction
############
.. include:: ../../README.rst

View File

@@ -0,0 +1,13 @@
Specs
=====
This section contains detailed specification documents for
different features inside Karbor Client.
Approved Specs
--------------
.. toctree::
:maxdepth: 1
karbor-support-in-python-openstackclient

View File

@@ -89,7 +89,7 @@ Python API
None
CLI (python-karborclient)
------------------------
-------------------------
A new directory named osc will be created under /karborclient/osc
for the ``OpenStackClient`` plugin and the commands mentioned above.
@@ -158,7 +158,7 @@ OpenStack Client adoption list will be updated to include python-karborclient.
References
==========
http://docs.openstack.org/developer/python-openstackclient/commands.html
https://docs.openstack.org/python-openstackclient/latest/
Appendix
========

View File

@@ -12,7 +12,7 @@
"""oslo.i18n integration module.
See http://docs.openstack.org/developer/oslo.i18n/usage.html
See https://docs.openstack.org/oslo.i18n/latest/user/usage.html
"""

View 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()))

View 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])

View 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'})

View File

@@ -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)

View 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')

View File

@@ -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())

View File

@@ -3,12 +3,12 @@
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
keystoneauth1>=2.21.0 # Apache-2.0
keystoneauth1>=3.0.1 # Apache-2.0
requests>=2.14.2 # Apache-2.0
simplejson>=2.2.0 # MIT
Babel!=2.4.0,>=2.3.4 # BSD
six>=1.9.0 # MIT
osc-lib>=1.5.1 # Apache-2.0
osc-lib>=1.7.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
oslo.log>=3.22.0 # Apache-2.0
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0

View File

@@ -5,7 +5,7 @@ description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = https://docs.openstack.org/developer/karbor/
home-page = https://docs.openstack.org/karbor/latest
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -44,10 +44,10 @@ openstack.data_protection.v1 =
data_protection_restore_create = karborclient.osc.v1.restores:CreateRestore
data_protection_provider_list = karborclient.osc.v1.providers:ListProviders
data_protection_provider_show = karborclient.osc.v1.providers:ShowProvider
data_protection_protectable_list = karborclient.osc.v1.protectables.ListProtectables
data_protection_protectable_show = karborclient.osc.v1.protectables.ShowProtectable
data_protection_protectable_instance_list = karborclient.osc.v1.protectables.ListProtectableInstances
data_protection_protectable_instance_show = karborclient.osc.v1.protectables.ShowProtectableInstance
data_protection_protectable_list = karborclient.osc.v1.protectables:ListProtectables
data_protection_protectable_show = karborclient.osc.v1.protectables:ShowProtectable
data_protection_protectable_instance_list = karborclient.osc.v1.protectables:ListProtectableInstances
data_protection_protectable_instance_show = karborclient.osc.v1.protectables:ShowProtectableInstance
data_protection_trigger_list = karborclient.osc.v1.triggers:ListTriggers
data_protection_trigger_show = karborclient.osc.v1.triggers:ShowTrigger
data_protection_trigger_create = karborclient.osc.v1.triggers:CreateTrigger
@@ -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
@@ -80,6 +82,7 @@ output_file = karborclient/locale/karborclient.pot
source-dir = doc/source
build-dir = doc/build
all_files = 1
warning-is-error = 1
[upload_sphinx]
upload-dir = doc/build/html