Compare commits

..

6 Commits

Author SHA1 Message Date
OpenDev Sysadmins
7a8e80f62f OpenDev Migration Patch
This commit was bulk generated and pushed by the OpenDev sysadmins
as a part of the Git hosting and code review systems migration
detailed in these mailing list posts:

http://lists.openstack.org/pipermail/openstack-discuss/2019-March/003603.html
http://lists.openstack.org/pipermail/openstack-discuss/2019-April/004920.html

Attempts have been made to correct repository namespaces and
hostnames based on simple pattern matching, but it's possible some
were updated incorrectly or missed entirely. Please reach out to us
via the contact information listed at https://opendev.org/ with any
questions you may have.
2019-04-19 19:41:49 +00:00
Nguyen Hai
c138cec2ca import zuul job settings from project-config
This is a mechanically generated patch to complete step 1 of moving
the zuul job settings out of project-config and into each project
repository.

Because there will be a separate patch on each branch, the branch
specifiers for branch-specific jobs have been removed.

Because this patch is generated by a script, there may be some
cosmetic changes to the layout of the YAML file(s) as the contents are
normalized.

See the python3-first goal document for details:
https://governance.openstack.org/tc/goals/stein/python3-first.html

* This patch also fix docs failure.

Change-Id: I7e2b27289927f1b3d687dadf3e68c411269c8e08
Story: #2002586
Task: #24303
2018-08-22 23:17:17 +09:00
chenying
42066dcdf0 Fix the errors about parameter when creating a plan
Change-Id: Ibb6ab69c25cf232b15e2138bfc62f91159039a32
Closes-Bug:#1666186
(cherry picked from commit ee725acb94)
2017-02-22 09:51:48 +08:00
xiangxinyong
6702e0c62b Help info error
Modefied other command help error info.

Change-Id: I82fa9bd7524677dc84bab33f57477771198b65de
(cherry picked from commit a625f7a702)
2017-02-14 18:01:30 +08:00
xiangxinyong
3e9ace28ce 'karbor provider-list' help info error
Modified 'karbor provider-list'`s help error info.

Change-Id: I0db08456599c4db96b9effd47db568c460b7ca81
(cherry picked from commit 71b9c54d0a)
2017-02-14 16:07:05 +08:00
Yuval Brik
7426876280 Update defaultbranch for newton
Change-Id: I1a4033cb6c9a384ac6630ec071e4bbe2cfb4c63b
2017-01-29 16:17:21 +02:00
48 changed files with 278 additions and 3118 deletions

1
.gitignore vendored
View File

@@ -24,7 +24,6 @@ pip-log.txt
# Unit test / coverage reports
.coverage
cover
.tox
nosetests.xml
.testrepository

View File

@@ -1,4 +1,5 @@
[gerrit]
host=review.openstack.org
host=review.opendev.org
port=29418
project=openstack/python-karborclient.git
defaultbranch=stable/ocata

12
.zuul.yaml Normal file
View File

@@ -0,0 +1,12 @@
- project:
templates:
- openstack-python-jobs
- openstack-python35-jobs
- check-requirements
- publish-openstack-sphinx-docs
- openstackclient-plugin-jobs
check:
jobs:
- openstack-tox-cover:
voting: false

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:
https://docs.openstack.org/infra/manual/developers.html
http://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:
https://docs.openstack.org/infra/manual/developers.html#development-workflow
http://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 https://docs.openstack.org/hacking/latest/
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/

6
MANIFEST.in Normal file
View File

@@ -0,0 +1,6 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@@ -2,8 +2,8 @@
Team and repository tags
========================
.. image:: https://governance.openstack.org/badges/python-karborclient.svg
:target: https://governance.openstack.org/reference/tags/index.html
.. image:: http://governance.openstack.org/badges/python-karborclient.svg
:target: http://governance.openstack.org/reference/tags/index.html
.. Change things from this point on
@@ -39,8 +39,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: https://docs.openstack.org/karbor/latest/specs/index.html
.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html
.. _Specs: http://docs.openstack.org/developer/karbor/specs/index.html
.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html
Python Karborclient
@@ -62,7 +62,7 @@ Project status, bugs, and blueprints are tracked on Launchpad:
Developer documentation can be found here:
https://docs.openstack.org/karbor/latest/
http://docs.openstack.org/developer/karbor
Additional resources are linked from the project wiki page:

View File

@@ -23,7 +23,7 @@ sys.path.insert(0, os.path.abspath('../..'))
extensions = [
'sphinx.ext.autodoc',
#'sphinx.ext.intersphinx',
'openstackdocstheme'
'oslosphinx'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
@@ -55,15 +55,9 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
html_theme = 'openstackdocs'
# html_theme = '_theme'
# html_static_path = ['static']
# openstackdocstheme options
repository_name = 'openstack/python-karborclient'
bug_project = 'python-karborclient'
bug_tag = ''
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project

View File

@@ -1,166 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
========================================
Karbor support in python-openstackclient
========================================
Implement a new set of karbor commands as python-openstackclient plugins.
Launchpad Blueprint:
https://blueprints.launchpad.net/python-karborclient/+spec/karbor-support-python-openstackclient
Problem Description
===================
python-openstackclient is becoming the default command line client for many
OpenStack projects. Karbor would benefit from implementing all of its client
commands as a single python-openstackclient plugin implemented in the
python-karborclient repository.
Proposed Change
===============
The intent of this spec is to identify the commands to be implemented and
establish conventions for command and argument names. This spec is not
intended to be a full and correct specification of command and argument names.
The details can be left to the code reviews for the commands themselves.
The following conventions will be adopted for command names:
* As the ``OpenStackClient`` convention, the command name shall always take
the following form:
.. code-block:: bash
openstack [<global-options>] <object-1> <action> [<object-2>] \
[command-arguments]
As a example:
The following ``karbor`` commands about plan will be implemented for ``openstack``
initially suggesting these command names:
.. code-block:: bash
karbor plan-create <name> <provider_id> <resources>
openstack data protection plan create <name> <provider_id> <resources>
karbor plan-delete <plan>
openstack data protection plan delete <plan>
karbor plan-list
openstack data protection plan list
karbor plan-show <plan>
openstack data protection plan show <plan>
karbor plan-update <name> <resources> <status>
openstack data protection plan update <name> <resources> <status>
Configuration
-------------
None
Database
--------
None
Public API
----------
None
Public API Security
-------------------
None
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.
Internal API
------------
None
Guest Agent
-----------
None
Alternatives
------------
None
Dashboard Impact (UX)
=====================
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
chenying
Milestones
----------
Work Items
----------
CLI commands as stated above.
Unit tests
Upgrade Implications
====================
None
Dependencies
============
python-openstackclient
osc-lib
Testing
=======
Unit tests will be located in: /karborclient/tests/unit/osc/
Documentation Impact
====================
OpenStack Client adoption list will be updated to include python-karborclient.
References
==========
https://docs.openstack.org/python-openstackclient/latest/
Appendix
========
None

View File

@@ -54,7 +54,7 @@ def load_auth_system_opts(parser):
"""
group = parser.add_argument_group("Common auth options")
BaseAuthPlugin.add_common_opts(group)
for name, auth_plugin in _discovered_plugins.items():
for name, auth_plugin in six.iteritems(_discovered_plugins):
group = parser.add_argument_group(
"Auth-system '%s' options" % name,
conflict_handler="resolve")

View File

@@ -297,7 +297,7 @@ class CrudManager(BaseManager):
def _filter_kwargs(self, kwargs):
"""Drop null values and handle ids."""
for key, ref in kwargs.copy().items():
for key, ref in six.iteritems(kwargs.copy()):
if ref is None:
kwargs.pop(key)
else:
@@ -470,7 +470,7 @@ class Resource(object):
return None
def _add_details(self, info):
for (k, v) in info.items():
for (k, v) in six.iteritems(info):
try:
setattr(self, k, v)
self._info[k] = v

View File

@@ -22,6 +22,7 @@ Exception definitions.
import inspect
import sys
import six
from karborclient.i18n import _
@@ -409,7 +410,7 @@ class HttpVersionNotSupported(HttpServerError):
# _code_map contains all the classes that have http_status attribute.
_code_map = dict(
(getattr(obj, 'http_status', None), obj)
for name, obj in vars(sys.modules[__name__]).items()
for name, obj in six.iteritems(vars(sys.modules[__name__]))
if inspect.isclass(obj) and getattr(obj, 'http_status', False)
)

View File

@@ -18,7 +18,7 @@ import hashlib
import os
import socket
import keystoneauth1.adapter as keystone_adapter
import keystoneclient.adapter as keystone_adapter
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
@@ -27,6 +27,8 @@ import six
from six.moves import urllib
from karborclient.common.apiclient import exceptions as exc
from karborclient.i18n import _LE
from karborclient.i18n import _LW
LOG = logging.getLogger(__name__)
USER_AGENT = 'python-karborclient'
@@ -48,7 +50,7 @@ def get_system_ca_file():
if os.path.exists(ca):
LOG.debug("Using ca file %s", ca)
return ca
LOG.warning("System ca file could not be found.")
LOG.warning(_LW("System ca file could not be found."))
class HTTPClient(object):
@@ -246,7 +248,7 @@ class HTTPClient(object):
if 'data' in kwargs:
raise ValueError("Can't provide both 'data' and "
"'body' to a request")
LOG.warning("Use of 'body' is deprecated; use 'data' instead")
LOG.warning(_LW("Use of 'body' is deprecated; use 'data' instead"))
kwargs['data'] = kwargs.pop('body')
if 'data' in kwargs:
kwargs['data'] = jsonutils.dumps(kwargs['data'])
@@ -258,7 +260,7 @@ class HTTPClient(object):
try:
body = resp.json()
except ValueError:
LOG.error('Could not decode response body as JSON')
LOG.error(_LE('Could not decode response body as JSON'))
else:
body = None
@@ -269,7 +271,7 @@ class HTTPClient(object):
if 'data' in kwargs:
raise ValueError("Can't provide both 'data' and "
"'body' to a request")
LOG.warning("Use of 'body' is deprecated; use 'data' instead")
LOG.warning(_LW("Use of 'body' is deprecated; use 'data' instead"))
kwargs['data'] = kwargs.pop('body')
# Chunking happens automatically if 'body' is a
# file-like object
@@ -299,7 +301,7 @@ class HTTPClient(object):
class SessionClient(keystone_adapter.Adapter):
"""karbor specific keystoneauth Adapter.
"""karbor specific keystoneclient Adapter.
"""
@@ -326,7 +328,7 @@ class SessionClient(keystone_adapter.Adapter):
if 'data' in kwargs:
raise ValueError("Can't provide both 'data' and "
"'body' to a request")
LOG.warning("Use of 'body' is deprecated; use 'data' instead")
LOG.warning(_LW("Use of 'body' is deprecated; use 'data' instead"))
kwargs['data'] = kwargs.pop('body')
if 'data' in kwargs:
kwargs['data'] = jsonutils.dumps(kwargs['data'])
@@ -351,7 +353,7 @@ class SessionClient(keystone_adapter.Adapter):
if 'data' in kwargs:
raise ValueError("Can't provide both 'data' and "
"'body' to a request")
LOG.warning("Use of 'body' is deprecated; use 'data' instead")
LOG.warning(_LW("Use of 'body' is deprecated; use 'data' instead"))
kwargs['data'] = kwargs.pop('body')
resp = keystone_adapter.Adapter.request(self,
url,

View File

@@ -43,7 +43,7 @@ def env(*vars, **kwargs):
returns the default defined in kwargs.
"""
for v in vars:
value = os.environ.get(v)
value = os.environ.get(v, None)
if value:
return value
return kwargs.get('default', '')
@@ -120,7 +120,7 @@ def print_dict(d, property="Property", dict_format_list=None,
json_format_list=None):
pt = prettytable.PrettyTable([property, 'Value'], caching=False)
pt.align = 'l'
for r in d.items():
for r in six.iteritems(d):
r = list(r)
if isinstance(r[1], six.string_types) and "\r" in r[1]:
r[1] = r[1].replace("\r", " ")

View File

@@ -12,7 +12,7 @@
"""oslo.i18n integration module.
See https://docs.openstack.org/oslo.i18n/latest/user/usage.html
See http://docs.openstack.org/developer/oslo.i18n/usage.html
"""
@@ -23,6 +23,16 @@ _translators = oslo_i18n.TranslatorFactory(domain='karborclient')
# The primary translation function using the well-known name "_"
_ = _translators.primary
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical
def get_available_languages():
return oslo_i18n.get_available_languages('karborclient')

View File

@@ -1,56 +0,0 @@
# 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 logging
from osc_lib import utils
LOG = logging.getLogger(__name__)
DEFAULT_DATA_PROTECTION_API_VERSION = '1'
API_VERSION_OPTION = 'os_data_protection_api_version'
API_NAME = 'data_protection'
API_VERSIONS = {
'1': 'karborclient.v1.client.Client',
}
def make_client(instance):
"""Returns a data protection service client"""
data_protection_client = utils.get_client_class(
API_NAME,
instance._api_version[API_NAME],
API_VERSIONS)
LOG.debug('Instantiating data protection client: %s',
data_protection_client)
client = data_protection_client(
auth=instance.auth,
session=instance.session,
service_type="data-protect"
)
return client
def build_option_parser(parser):
"""Hook to add global options"""
parser.add_argument(
'--os-data-protection-api-version',
metavar='<data-protection-api-version>',
default=utils.env(
'OS_DATA_PROTECTION_API_VERSION',
default=DEFAULT_DATA_PROTECTION_API_VERSION),
help='Data protection API version, default=' +
DEFAULT_DATA_PROTECTION_API_VERSION +
' (Env: OS_DATA_PROTECTION_API_VERSION)')
return parser

View File

@@ -1,205 +0,0 @@
# 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 checkpoint 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.common.apiclient import exceptions
from karborclient.i18n import _
from karborclient import utils
class ListCheckpoints(command.Lister):
_description = _("List checkpoints.")
log = logging.getLogger(__name__ + ".ListCheckpoints")
def get_parser(self, prog_name):
parser = super(ListCheckpoints, self).get_parser(prog_name)
parser.add_argument(
'provider_id',
metavar='<provider_id>',
help=_('ID of provider.'),
)
parser.add_argument(
'--plan_id',
metavar='<plan_id>',
default=None,
help=_('Filters results by a plan ID. Default=None.'),
)
parser.add_argument(
'--start_date',
type=str,
metavar='<start_date>',
default=None,
help=_('Filters results by a start date("Y-m-d"). Default=None.'),
)
parser.add_argument(
'--end_date',
type=str,
metavar='<end_date>',
default=None,
help=_('Filters results by a end date("Y-m-d"). Default=None.'),
)
parser.add_argument(
'--project_id',
metavar='<project_id>',
default=None,
help=_('Filters results by a project ID. Default=None.'),
)
parser.add_argument(
'--marker',
metavar='<checkpoint>',
help=_('The last checkpoint ID of the previous page.'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-checkpoints>',
help=_('Maximum number of checkpoints 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"),
)
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
search_opts = {
'plan_id': parsed_args.plan_id,
'start_date': parsed_args.start_date,
'end_date': parsed_args.end_date,
'project_id': parsed_args.project_id,
}
data = data_protection_client.checkpoints.list(
provider_id=parsed_args.provider_id, search_opts=search_opts,
marker=parsed_args.marker, limit=parsed_args.limit,
sort=parsed_args.sort)
column_headers = ['Id', 'Project id', 'Status', 'Protection plan',
'Metadata', 'Created at']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowCheckpoint(command.ShowOne):
_description = "Shows checkpoint details"
def get_parser(self, prog_name):
parser = super(ShowCheckpoint, self).get_parser(prog_name)
parser.add_argument(
'provider_id',
metavar="<provider_id>",
help=_('Id of provider.')
)
parser.add_argument(
'checkpoint_id',
metavar="<checkpoint_id>",
help=_('Id of checkpoint.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
checkpoint = client.checkpoints.get(parsed_args.provider_id,
parsed_args.checkpoint_id)
checkpoint._info.pop("links", None)
return zip(*sorted(checkpoint._info.items()))
class CreateCheckpoint(command.ShowOne):
_description = "Creates a checkpoint"
def get_parser(self, prog_name):
parser = super(CreateCheckpoint, self).get_parser(prog_name)
parser.add_argument(
'provider_id',
metavar='<provider_id>',
help=_('ID of provider.')
)
parser.add_argument(
'plan_id',
metavar='<plan_id>',
help=_('ID of plan.')
)
parser.add_argument(
'--extra_info',
type=str,
nargs='*',
metavar='<key=value>',
default=None,
help=_('The extra info of a checkpoint.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
checkpoint_extra_info = None
if parsed_args.extra_info is not None:
checkpoint_extra_info = utils.extract_extra_info(parsed_args)
checkpoint = client.checkpoints.create(parsed_args.provider_id,
parsed_args.plan_id,
checkpoint_extra_info)
checkpoint._info.pop("links", None)
return zip(*sorted(checkpoint._info.items()))
class DeleteCheckpoint(command.Command):
_description = "Delete checkpoint"
log = logging.getLogger(__name__ + ".DeleteCheckpoint")
def get_parser(self, prog_name):
parser = super(DeleteCheckpoint, self).get_parser(prog_name)
parser.add_argument(
'provider_id',
metavar='<provider_id>',
help=_('Id of provider.')
)
parser.add_argument(
'checkpoint',
metavar='<checkpoint>',
nargs="+",
help=_('Id of checkpoint.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
failure_count = 0
for checkpoint_id in parsed_args.checkpoint:
try:
client.checkpoints.delete(parsed_args.provider_id,
checkpoint_id)
except exceptions.NotFound:
failure_count += 1
self.log.error(
"Failed to delete '{0}'; checkpoint not found".
format(checkpoint_id))
if failure_count == len(parsed_args.checkpoint):
raise exceptions.CommandError(
"Unable to find and delete any of the "
"specified checkpoint.")

View File

@@ -1,265 +0,0 @@
# 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 plan action implementations"""
from oslo_utils import uuidutils
from osc_lib.command import command
from osc_lib import utils as osc_utils
from oslo_log import log as logging
from karborclient.common.apiclient import exceptions
from karborclient.i18n import _
from karborclient import utils
class ListPlans(command.Lister):
_description = _("List plans.")
log = logging.getLogger(__name__ + ".ListPlans")
def get_parser(self, prog_name):
parser = super(ListPlans, self).get_parser(prog_name)
parser.add_argument(
'--all-projects',
action='store_true',
default=False,
help=_('Include all projects (admin only)'),
)
parser.add_argument(
'--name',
metavar='<name>',
help=_('Filter results by plan name'),
)
parser.add_argument(
'--description',
metavar='<description>',
help=_('Filter results by plan description'),
)
parser.add_argument(
'--status',
metavar='<status>',
help=_('Filter results by status'),
)
parser.add_argument(
'--marker',
metavar='<plan>',
help=_('The last plan ID of the previous page'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-plans>',
help=_('Maximum number of plans to display'),
)
parser.add_argument(
'--sort',
metavar="<key>[:<direction>]",
default=None,
help=_("Sort output by selected keys and directions(asc or desc) "
"(default: name:asc), 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,
'name': parsed_args.name,
'description': parsed_args.description,
'status': parsed_args.status,
}
data = data_protection_client.plans.list(
search_opts=search_opts, marker=parsed_args.marker,
limit=parsed_args.limit, sort=parsed_args.sort)
column_headers = ['Id', 'Name', 'Description', 'Provider id', 'Status']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowPlan(command.ShowOne):
_description = "Shows plan details"
def get_parser(self, prog_name):
parser = super(ShowPlan, self).get_parser(prog_name)
parser.add_argument(
'plan',
metavar="<plan>",
help=_('The UUID of the plan.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
plan = osc_utils.find_resource(client.plans, parsed_args.plan)
plan._info.pop("links", None)
return zip(*sorted(plan._info.items()))
class CreatePlan(command.ShowOne):
_description = "Creates a plan"
def get_parser(self, prog_name):
parser = super(CreatePlan, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help=_('The name of the plan.')
)
parser.add_argument(
'provider_id',
metavar='<provider_id>',
help=_('The UUID of the provider.')
)
parser.add_argument(
'resources',
metavar='<id=type=name=extra_info,id=type=name=extra_info>',
help=_('Resource in list must be a dict when creating'
' a plan. The keys of resource are id ,type, name and '
'extra_info. The extra_info field is optional.')
)
parser.add_argument(
'--parameters-json',
type=str,
dest='parameters_json',
metavar='<parameters>',
default=None,
help=_('Plan parameters in json format.')
)
parser.add_argument(
'--parameters',
action='append',
metavar='resource_type=<type>[,resource_id=<id>,key=val,...]',
default=[],
help=_('Plan parameters, may be specified multiple times. '
'resource_type: type of resource to apply parameters. '
'resource_id: limit the parameters to a specific resource. '
'Other keys and values: according to provider\'s protect '
'schema.')
)
parser.add_argument(
'--description',
metavar='<description>',
help=_('The description of the plan.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
if not uuidutils.is_uuid_like(parsed_args.provider_id):
raise exceptions.CommandError(
"Invalid provider id provided.")
plan_resources = utils.extract_resources(parsed_args)
utils.check_resources(client, plan_resources)
plan_parameters = utils.extract_parameters(parsed_args)
plan = client.plans.create(parsed_args.name, parsed_args.provider_id,
plan_resources, plan_parameters,
description=parsed_args.description)
plan._info.pop("links", None)
return zip(*sorted(plan._info.items()))
class UpdatePlan(command.ShowOne):
_description = "Update a plan"
def get_parser(self, prog_name):
parser = super(UpdatePlan, self).get_parser(prog_name)
parser.add_argument(
"plan_id",
metavar="<PLAN ID>",
help=_("Id of plan to update.")
)
parser.add_argument(
"--name",
metavar="<name>",
help=_("A name to which the plan will be renamed.")
)
parser.add_argument(
"--resources",
metavar="<id=type=name,id=type=name>",
help=_("Resources to which the plan will be updated.")
)
parser.add_argument(
"--status",
metavar="<suspended|started>",
help=_("status to which the plan will be updated.")
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
data = {}
if parsed_args.name is not None:
data['name'] = parsed_args.name
if parsed_args.resources is not None:
plan_resources = utils.extract_resources(parsed_args)
data['resources'] = plan_resources
if parsed_args.status is not None:
data['status'] = parsed_args.status
try:
plan = osc_utils.find_resource(client.plans,
parsed_args.plan_id)
plan = client.plans.update(plan.id, data)
except exceptions.NotFound:
raise exceptions.CommandError(
"Plan %s not found" % parsed_args.plan_id)
else:
plan._info.pop("links", None)
return zip(*sorted(plan._info.items()))
class DeletePlan(command.Command):
_description = "Delete plan"
def get_parser(self, prog_name):
parser = super(DeletePlan, self).get_parser(prog_name)
parser.add_argument(
'plan',
metavar='<plan>',
nargs="+",
help=_('ID of plan.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
failure_count = 0
for plan_id in parsed_args.plan:
try:
plan = osc_utils.find_resource(client.plans, plan_id)
client.plans.delete(plan.id)
except exceptions.NotFound:
failure_count += 1
print("Failed to delete '{0}'; plan not "
"found".format(plan_id))
if failure_count == len(parsed_args.plan):
raise exceptions.CommandError(
"Unable to find and delete any of the "
"specified plan.")

View File

@@ -1,177 +0,0 @@
# 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 protectables 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 _
from karborclient import utils
class ListProtectables(command.Lister):
_description = _("List protectable types.")
log = logging.getLogger(__name__ + ".ListProtectables")
def get_parser(self, prog_name):
parser = super(ListProtectables, self).get_parser(prog_name)
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
data = data_protection_client.protectables.list()
column_headers = ['Protectable type']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowProtectable(command.ShowOne):
_description = "Shows protectable type details"
def get_parser(self, prog_name):
parser = super(ShowProtectable, self).get_parser(prog_name)
parser.add_argument(
'protectable_type',
metavar="<protectable_type>",
help=_('Protectable type.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
protectable = osc_utils.find_resource(client.protectables,
parsed_args.protectable_type)
protectable._info.pop("links", None)
return zip(*sorted(protectable._info.items()))
class ListProtectableInstances(command.Lister):
_description = _("List protectable instances.")
log = logging.getLogger(__name__ + ".ListProtectableInstances")
def get_parser(self, prog_name):
parser = super(ListProtectableInstances, self).get_parser(prog_name)
parser.add_argument(
'protectable_type',
metavar="<protectable_type>",
help=_('Type of protectable.')
)
parser.add_argument(
'--type',
metavar="<type>",
default=None,
help=_('Filters results by protectable type. Default=None.')
)
parser.add_argument(
'--marker',
metavar="<protectable_instance>",
default=None,
help=_('The last protectable instance ID of the previous page.')
)
parser.add_argument(
'--limit',
metavar="<num-protectable_instances>",
default=None,
help=_('Maximum number of protectable instances 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(
'--parameters',
type=str,
nargs='*',
metavar="<key=value>",
default=None,
help=_('List instances by parameters key and value pair. '
'Default=None.')
)
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
search_opts = {
'type': parsed_args.type,
'parameters': (utils.extract_instances_parameters(parsed_args)
if parsed_args.parameters else None),
}
data = data_protection_client.protectables.list_instances(
parsed_args.protectable_type, search_opts=search_opts,
marker=parsed_args.marker, limit=parsed_args.limit,
sort=parsed_args.sort)
column_headers = ['Id', 'Type', 'Name', 'Dependent resources',
'Extra info']
return (column_headers, data)
class ShowProtectableInstance(command.ShowOne):
_description = "Shows protectable instance details"
def get_parser(self, prog_name):
parser = super(ShowProtectableInstance, self).get_parser(prog_name)
parser.add_argument(
'protectable_type',
metavar="<protectable_type>",
help=_('Protectable type.')
)
parser.add_argument(
'protectable_id',
metavar="<protectable_id>",
help=_('Protectable instance id.')
)
parser.add_argument(
'--parameters',
type=str,
nargs='*',
metavar="<key=value>",
default=None,
help=_('Show a instance by parameters key and value pair. '
'Default=None.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
search_opts = {
'parameters': (utils.extract_instances_parameters(parsed_args)
if parsed_args.parameters else None),
}
instance = client.protectables.get_instance(
parsed_args.protectable_type,
parsed_args.protectable_id,
search_opts=search_opts)
instance._info.pop("links", None)
return zip(*sorted(instance._info.items()))

View File

@@ -1,99 +0,0 @@
# 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 provider 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 ListProviders(command.Lister):
_description = _("List providers.")
log = logging.getLogger(__name__ + ".ListProviders")
def get_parser(self, prog_name):
parser = super(ListProviders, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar='<name>',
help=_('Filters results by a name. Default=None.'),
)
parser.add_argument(
'--description',
metavar='<description>',
help=_('Filters results by a description. Default=None.'),
)
parser.add_argument(
'--marker',
metavar='<provider>',
help=_('The last provider ID of the previous page'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-providers>',
help=_('Maximum number of providers to display'),
)
parser.add_argument(
'--sort',
metavar="<key>[:<direction>]",
default=None,
help=_("Sort output by selected keys and directions(asc or desc) "
"(default: name:asc), multiple keys and directions can be "
"specified separated by comma"),
)
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
search_opts = {
'name': parsed_args.name,
'description': parsed_args.description,
}
data = data_protection_client.providers.list(
search_opts=search_opts, marker=parsed_args.marker,
limit=parsed_args.limit, sort=parsed_args.sort)
column_headers = ['Id', 'Name', 'Description']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowProvider(command.ShowOne):
_description = "Shows provider details"
def get_parser(self, prog_name):
parser = super(ShowProvider, self).get_parser(prog_name)
parser.add_argument(
'provider',
metavar="<provider>",
help=_('The UUID of the provider.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
provider = osc_utils.find_resource(client.providers,
parsed_args.provider)
provider._info.pop("links", None)
return zip(*sorted(provider._info.items()))

View File

@@ -1,195 +0,0 @@
# 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 restore action implementations"""
from oslo_utils import uuidutils
from osc_lib.command import command
from osc_lib import utils as osc_utils
from oslo_log import log as logging
from karborclient.common.apiclient import exceptions
from karborclient.i18n import _
from karborclient import utils
class ListRestores(command.Lister):
_description = _("List restores.")
log = logging.getLogger(__name__ + ".ListRestores")
def get_parser(self, prog_name):
parser = super(ListRestores, 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='<restore>',
help=_('The last restore ID of the previous page'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-restores>',
help=_('Maximum number of restores 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.restores.list(
search_opts=search_opts, marker=parsed_args.marker,
limit=parsed_args.limit, sort=parsed_args.sort)
column_headers = ['Id', 'Project id', 'Provider id', 'Checkpoint id',
'Restore target', 'Parameters', 'Status']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowRestore(command.ShowOne):
_description = "Shows restore details"
def get_parser(self, prog_name):
parser = super(ShowRestore, self).get_parser(prog_name)
parser.add_argument(
'restore',
metavar="<restore>",
help=_('The UUID of the restore.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
restore = osc_utils.find_resource(client.restores, parsed_args.restore)
restore._info.pop("links", None)
return zip(*sorted(restore._info.items()))
class CreateRestore(command.ShowOne):
_description = "Creates a restore"
def get_parser(self, prog_name):
parser = super(CreateRestore, self).get_parser(prog_name)
parser.add_argument(
'provider_id',
metavar='<provider_id>',
help=_('The UUID of the provider.')
)
parser.add_argument(
'checkpoint_id',
metavar='<checkpoint_id>',
help=_('The UUID of the checkpoint.')
)
parser.add_argument(
'--restore_target',
metavar='<restore_target>',
help=_('The target of the restore operation.')
)
parser.add_argument(
'--restore_username',
metavar='<restore_username>',
default=None,
help=_('Username to restore target.')
)
parser.add_argument(
'--restore_password',
metavar='<restore_password>',
default=None,
help=_('Password to restore target.')
)
parser.add_argument(
'--parameters-json',
type=str,
dest='parameters_json',
metavar='<parameters>',
default=None,
help=_('Restore parameters in json format.')
)
parser.add_argument(
'--parameters',
action='append',
metavar='resource_type=<type>[,resource_id=<id>,key=val,...]',
default=[],
help=_("Restore parameters, may be specified multiple times. "
"resource_type: type of resource to apply parameters. "
"resource_id: limit the parameters to a specific resource. "
"Other keys and values: according to provider\'s "
"restore schema.")
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
if not uuidutils.is_uuid_like(parsed_args.provider_id):
raise exceptions.CommandError(
"Invalid provider id provided.")
if not uuidutils.is_uuid_like(parsed_args.checkpoint_id):
raise exceptions.CommandError(
"Invalid checkpoint id provided.")
restore_parameters = utils.extract_parameters(parsed_args)
restore_auth = None
if parsed_args.restore_target is not None:
if parsed_args.restore_username is None:
raise exceptions.CommandError(
"Must specify username for restore_target.")
if parsed_args.restore_password is None:
raise exceptions.CommandError(
"Must specify password for restore_target.")
restore_auth = {
'type': 'password',
'username': parsed_args.restore_username,
'password': parsed_args.restore_password,
}
restore = client.restores.create(parsed_args.provider_id,
parsed_args.checkpoint_id,
parsed_args.restore_target,
restore_parameters, restore_auth)
restore._info.pop("links", None)
return zip(*sorted(restore._info.items()))

View File

@@ -1,208 +0,0 @@
# 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 scheduled_operations action implementations"""
import six
from oslo_utils import uuidutils
from osc_lib.command import command
from osc_lib import utils as osc_utils
from oslo_log import log as logging
from karborclient.common.apiclient import exceptions
from karborclient.i18n import _
class ListScheduledOperations(command.Lister):
_description = _("List scheduled_operations.")
log = logging.getLogger(__name__ + ".ListScheduledOperations")
def get_parser(self, prog_name):
parser = super(ListScheduledOperations, self).get_parser(prog_name)
parser.add_argument(
'--all-projects',
action='store_true',
default=False,
help=_('Shows details for all tenants. Admin only.'),
)
parser.add_argument(
'--name',
metavar='<name>',
help=_('Filters results by a name. Default=None.'),
)
parser.add_argument(
'--operation_type',
metavar='<operation_type>',
default=None,
help=_('Filters results by a type. Default=None.'),
)
parser.add_argument(
'--trigger_id',
metavar='<trigger_id>',
default=None,
help=_('Filters results by a trigger id. Default=None.'),
)
parser.add_argument(
'--operation_definition',
metavar='<operation_definition>',
default=None,
help=_('Filters results by a operation definition. Default=None.'),
)
parser.add_argument(
'--marker',
metavar='<scheduled_operations>',
help=_('The last scheduled_operations ID of the previous page'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-scheduled_operations>',
help=_('Maximum number of scheduled_operations to display'),
)
parser.add_argument(
'--sort',
metavar="<key>[:<direction>]",
default=None,
help=_("Sort output by selected keys and directions(asc or desc) "
"(default: name:asc), 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,
'name': parsed_args.name,
'operation_type': parsed_args.operation_type,
'trigger_id': parsed_args.trigger_id,
'operation_definition': parsed_args.operation_definition,
}
data = data_protection_client.scheduled_operations.list(
search_opts=search_opts, marker=parsed_args.marker,
limit=parsed_args.limit, sort=parsed_args.sort)
column_headers = ['Id', 'Name', 'OperationType', 'TriggerId',
'OperationDefinition']
scheduled_operations = []
for s in data:
scheduled_operation = (s.id, s.name, s.operation_type,
s.trigger_id, s.operation_definition)
scheduled_operations.append(scheduled_operation)
return (column_headers, scheduled_operations)
class ShowScheduledOperation(command.ShowOne):
_description = "Shows scheduled_operation details"
def get_parser(self, prog_name):
parser = super(ShowScheduledOperation, self).get_parser(prog_name)
parser.add_argument(
'scheduledoperation',
metavar="<scheduledoperation>",
help=_('The UUID of the scheduledoperation.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
so = osc_utils.find_resource(client.scheduled_operations,
parsed_args.scheduledoperation)
so._info.pop("links", None)
return zip(*sorted(six.iteritems(so._info)))
class CreateScheduledOperation(command.ShowOne):
_description = "Creates a scheduled operation"
def get_parser(self, prog_name):
parser = super(CreateScheduledOperation, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help=_('The name of the scheduled operation.')
)
parser.add_argument(
'operation_type',
metavar='<operation_type>',
help=_('Operation Type of scheduled operation.')
)
parser.add_argument(
'trigger_id',
metavar='<trigger_id>',
help=_('Trigger id of scheduled operation.')
)
parser.add_argument(
'operation_definition',
metavar='<key=value,key=value>',
help=_('Operation definition of scheduled operation.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
if not uuidutils.is_uuid_like(parsed_args.trigger_id):
raise exceptions.CommandError(
"Invalid trigger id provided.")
so = client.scheduled_operations.create(
parsed_args.name, parsed_args.operation_type,
parsed_args.trigger_id, parsed_args.operation_definition)
so._info.pop("links", None)
return zip(*sorted(six.iteritems(so._info)))
class DeleteScheduledOperation(command.Command):
_description = "Delete scheduled operation"
def get_parser(self, prog_name):
parser = super(DeleteScheduledOperation, self).get_parser(prog_name)
parser.add_argument(
'scheduledoperation',
metavar='<scheduledoperation>',
nargs="+",
help=_('ID of scheduled operation.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
failure_count = 0
for so_id in parsed_args.scheduledoperation:
try:
so = osc_utils.find_resource(client.scheduled_operations,
so_id)
client.scheduled_operations.delete(so.id)
except exceptions.NotFound:
failure_count += 1
print("Failed to delete '%s'; scheduled operation "
"not found" % so_id)
if failure_count == len(parsed_args.scheduledoperation):
raise exceptions.CommandError(
"Unable to find and delete any of the "
"specified scheduled operation.")

View File

@@ -1,229 +0,0 @@
# 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 triggers 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.common.apiclient import exceptions
from karborclient.i18n import _
from karborclient import utils
class ListTriggers(command.Lister):
_description = _("List triggers.")
log = logging.getLogger(__name__ + ".ListTriggers")
def get_parser(self, prog_name):
parser = super(ListTriggers, self).get_parser(prog_name)
parser.add_argument(
'--all-projects',
action='store_true',
default=False,
help=_('Shows details for all tenants. Admin only.'),
)
parser.add_argument(
'--name',
metavar='<name>',
default=None,
help=_('Filters results by a name. Default=None.'),
)
parser.add_argument(
'--type',
metavar='<type>',
default=None,
help=_('Filters results by a type. Default=None.'),
)
parser.add_argument(
'--properties',
metavar='<properties>',
default=None,
help=_('Filters results by a properties. Default=None.'),
)
parser.add_argument(
'--marker',
metavar='<trigger>',
help=_('The last trigger ID of the previous page'),
)
parser.add_argument(
'--limit',
type=int,
metavar='<num-triggers>',
help=_('Maximum number of triggers to display'),
)
parser.add_argument(
'--sort',
metavar="<key>[:<direction>]",
default=None,
help=_("Sort output by selected keys and directions(asc or desc) "
"(default: name:asc), multiple keys and directions can be "
"specified separated by comma"),
)
parser.add_argument(
'--project',
metavar='<project>',
help=_('Display information from single tenant (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,
'name': parsed_args.name,
'type': parsed_args.type,
'properties': parsed_args.properties,
}
data = data_protection_client.triggers.list(
search_opts=search_opts, marker=parsed_args.marker,
limit=parsed_args.limit, sort=parsed_args.sort)
column_headers = ['Id', 'Name', 'Type', 'Properties']
return (column_headers,
(osc_utils.get_item_properties(
s, column_headers
) for s in data))
class ShowTrigger(command.ShowOne):
_description = "Shows trigger details"
def get_parser(self, prog_name):
parser = super(ShowTrigger, self).get_parser(prog_name)
parser.add_argument(
'trigger',
metavar="<trigger>",
help=_('The UUID of the trigger.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
trigger = osc_utils.find_resource(client.triggers, parsed_args.trigger)
trigger._info.pop("links", None)
return zip(*sorted(trigger._info.items()))
class CreateTrigger(command.ShowOne):
_description = "Creates a trigger"
def get_parser(self, prog_name):
parser = super(CreateTrigger, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help=_('The name of the trigger.')
)
parser.add_argument(
'type',
metavar='<type>',
help=_('Type of trigger.')
)
parser.add_argument(
'properties',
metavar='<key=value,key=value>',
help=_('Properties of trigger.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
trigger = client.triggers.create(parsed_args.name, parsed_args.type,
parsed_args.properties)
trigger._info.pop("links", None)
return zip(*sorted(trigger._info.items()))
class UpdateTrigger(command.ShowOne):
_description = "Update a trigger"
def get_parser(self, prog_name):
parser = super(UpdateTrigger, self).get_parser(prog_name)
parser.add_argument(
"trigger_id",
metavar="<TRIGGER ID>",
help=_("Id of trigger to update.")
)
parser.add_argument(
"--name",
metavar="<name>",
help=_("A name to which the trigger will be renamed.")
)
parser.add_argument(
"--properties",
metavar="<key=value,key=value>",
help=_("Properties of trigger which will be updated.")
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
data = {}
if parsed_args.name is not None:
data['name'] = parsed_args.name
if parsed_args.properties is not None:
trigger_properties = utils.extract_properties(parsed_args)
data['properties'] = trigger_properties
try:
trigger = osc_utils.find_resource(client.triggers,
parsed_args.trigger_id)
trigger = client.triggers.update(trigger.id, data)
except exceptions.NotFound:
raise exceptions.CommandError(
"Trigger %s not found" % parsed_args.trigger_id)
else:
trigger._info.pop("links", None)
return zip(*sorted(trigger._info.items()))
class DeleteTrigger(command.Command):
_description = "Delete trigger"
log = logging.getLogger(__name__ + ".DeleteTrigger")
def get_parser(self, prog_name):
parser = super(DeleteTrigger, self).get_parser(prog_name)
parser.add_argument(
'trigger',
metavar='<trigger>',
nargs="+",
help=_('ID of trigger.')
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.data_protection
failure_count = 0
for trigger_id in parsed_args.trigger:
try:
trigger = osc_utils.find_resource(client.triggers, trigger_id)
client.triggers.delete(trigger.id)
except exceptions.NotFound:
failure_count += 1
self.log.error(
"Failed to delete '{0}'; trigger not found".
format(trigger_id))
if failure_count == len(parsed_args.trigger):
raise exceptions.CommandError(
"Unable to find and delete any of the "
"specified trigger.")

View File

@@ -17,14 +17,14 @@ Command-line interface to the karbor Project.
from __future__ import print_function
import argparse
import copy
import sys
from keystoneauth1 import discover
from keystoneauth1 import exceptions as ks_exc
from keystoneauth1.identity.generic import password
from keystoneauth1.identity.generic import token
from keystoneauth1 import loading
from keystoneclient.auth.identity.generic import password
from keystoneclient.auth.identity.generic import token
from keystoneclient.auth.identity import v3 as identity
from keystoneclient import discover
from keystoneclient import exceptions as ks_exc
from keystoneclient import session as ksession
from oslo_log import handlers
from oslo_log import log as logging
from oslo_utils import encodeutils
@@ -44,20 +44,13 @@ logger = logging.getLogger(__name__)
class KarborShell(object):
def _append_global_identity_args(self, parser, argv):
loading.register_session_argparse_arguments(parser)
# Peek into argv to see if os-auth-token (or the deprecated
# os_auth_token) or the new os-token or the environment variable
# OS_AUTH_TOKEN were given. In which case, the token auth plugin is
# what the user wants. Else, we'll default to password.
default_auth_plugin = 'password'
token_opts = ['os-token', 'os-auth-token', 'os_auth-token']
if argv and any(i in token_opts for i in argv):
default_auth_plugin = 'token'
loading.register_auth_argparse_arguments(
parser, argv, default=default_auth_plugin)
def _append_global_identity_args(self, parser):
# Register the CLI arguments that have moved to the session object.
ksession.Session.register_cli_options(parser)
def get_base_parser(self, argv):
identity.Password.register_argparse_arguments(parser)
def get_base_parser(self):
parser = argparse.ArgumentParser(
prog='karbor',
@@ -106,11 +99,11 @@ class KarborShell(object):
'API response, '
'defaults to system socket timeout.')
parser.add_argument('--os_tenant_id',
parser.add_argument('--os-tenant-id',
default=utils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os_tenant_name',
parser.add_argument('--os-tenant-name',
default=utils.env('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME].')
@@ -150,12 +143,12 @@ class KarborShell(object):
action='store_true',
help='Send os-username and os-password to karbor.')
self._append_global_identity_args(parser, argv)
self._append_global_identity_args(parser)
return parser
def get_subcommand_parser(self, version, argv=None):
parser = self.get_base_parser(argv)
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
@@ -204,7 +197,7 @@ class KarborShell(object):
v2_auth_url = None
v3_auth_url = None
try:
ks_discover = discover.Discover(session=session, url=auth_url)
ks_discover = discover.Discover(session=session, auth_url=auth_url)
v2_auth_url = ks_discover.url_for('2.0')
v3_auth_url = ks_discover.url_for('3.0')
except ks_exc.ClientException as e:
@@ -296,17 +289,16 @@ class KarborShell(object):
def main(self, argv):
# Parse args once to find version
base_argv = copy.deepcopy(argv)
parser = self.get_base_parser(argv)
(options, args) = parser.parse_known_args(base_argv)
parser = self.get_base_parser()
(options, args) = parser.parse_known_args(argv)
self._setup_logging(options.debug)
# build available subcommands based on version
api_version = options.karbor_api_version
subcommand_parser = self.get_subcommand_parser(api_version, argv)
subcommand_parser = self.get_subcommand_parser(api_version)
self.parser = subcommand_parser
ks_session = None
keystone_session = None
keystone_auth = None
# Handle top-level --help/-h before attempting to parse
@@ -374,12 +366,12 @@ class KarborShell(object):
kwargs['region_name'] = args.os_region_name
else:
# Create a keystone session and keystone auth
ks_session = loading.load_session_from_argparse_arguments(args)
keystone_session = ksession.Session.load_from_cli_options(args)
project_id = args.os_project_id or args.os_tenant_id
project_name = args.os_project_name or args.os_tenant_name
keystone_auth = self._get_keystone_auth(
ks_session,
keystone_session,
args.os_auth_url,
username=args.os_username,
user_id=args.os_user_id,
@@ -396,12 +388,12 @@ class KarborShell(object):
service_type = args.os_service_type or 'data-protect'
endpoint = keystone_auth.get_endpoint(
ks_session,
keystone_session,
service_type=service_type,
region_name=args.os_region_name)
kwargs = {
'session': ks_session,
'session': keystone_session,
'auth': keystone_auth,
'service_type': service_type,
'endpoint_type': endpoint_type,

View File

@@ -44,11 +44,11 @@ class TestResponse(requests.Response):
self._text = None
super(TestResponse, self)
if isinstance(data, dict):
self.status_code = data.get('status_code')
self.headers = data.get('headers')
self.status_code = data.get('status_code', None)
self.headers = data.get('headers', None)
self.reason = data.get('reason', '')
# Fake the text attribute to streamline Response creation
self._text = data.get('text')
self._text = data.get('text', None)
else:
self.status_code = data

View File

@@ -1 +0,0 @@
__author__ = 'c00179918'

View File

@@ -1,29 +0,0 @@
# Copyright (c) 2015 Mirantis Inc.
#
# 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 osc_lib.tests import utils
class TestDataProtection(utils.TestCommand):
def setUp(self):
super(TestDataProtection, self).setUp()
self.app.client_manager.data_protection = mock.Mock()
self.app.client_manager.network = mock.Mock()
self.app.client_manager.compute = mock.Mock()
self.app.client_manager.volume = mock.Mock()

View File

@@ -1,160 +0,0 @@
# 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 checkpoints as osc_checkpoints
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import checkpoints
CHECKPOINT_INFO = {
"id": "dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
"project_id": "e486a2f49695423ca9c47e589b948108",
"status": "available",
"protection_plan": {
"id": "3523a271-68aa-42f5-b9ba-56e5200a2ebb",
"name": "My application",
"provider_id": "cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"resources": [{
"id": "99777fdd-8a5b-45ab-ba2c-52420008103f",
"type": "OS::Glance::Image",
"name": "cirros-0.3.4-x86_64-uec"}]
},
"resource_graph": "[{'0x0': ['OS::Glance::Image', "
"'99777fdd-8a5b-45ab-ba2c-52420008103f', "
"'cirros-0.3.4-x86_64-uec']}, [[['0x0']]]]"
}
class TestCheckpoints(fakes.TestDataProtection):
def setUp(self):
super(TestCheckpoints, self).setUp()
cm = self.app.client_manager
self.checkpoints_mock = cm.data_protection.checkpoints
self.checkpoints_mock.reset_mock()
class TestListCheckpoints(TestCheckpoints):
def setUp(self):
super(TestListCheckpoints, self).setUp()
self.checkpoints_mock.list.return_value = [checkpoints.Checkpoint(
None, CHECKPOINT_INFO)]
# Command to test
self.cmd = osc_checkpoints.ListCheckpoints(self.app, None)
def test_checkpoints_list(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9')]
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', 'Project id', 'Status', 'Protection plan', 'Metadata',
'Created at'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [(
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
"e486a2f49695423ca9c47e589b948108",
"available",
{
"id": "3523a271-68aa-42f5-b9ba-56e5200a2ebb",
"name": "My application",
"provider_id": "cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"resources": [{
"id": "99777fdd-8a5b-45ab-ba2c-52420008103f",
"type": "OS::Glance::Image",
"name": "cirros-0.3.4-x86_64-uec"}]
},
'',
'')]
self.assertEqual(expected_data, list(data))
class TestCreateCheckpoint(TestCheckpoints):
def setUp(self):
super(TestCreateCheckpoint, self).setUp()
self.checkpoints_mock.create.return_value = checkpoints.Checkpoint(
None, CHECKPOINT_INFO)
# Command to test
self.cmd = osc_checkpoints.CreateCheckpoint(self.app, None)
def test_checkpoint_create(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'3523a271-68aa-42f5-b9ba-56e5200a2ebb']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('plan_id', '3523a271-68aa-42f5-b9ba-56e5200a2ebb')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.checkpoints_mock.create.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'3523a271-68aa-42f5-b9ba-56e5200a2ebb',
None)
class TestShowCheckpoint(TestCheckpoints):
def setUp(self):
super(TestShowCheckpoint, self).setUp()
self.checkpoints_mock.get.return_value = checkpoints.Checkpoint(
None, CHECKPOINT_INFO)
# Command to test
self.cmd = osc_checkpoints.ShowCheckpoint(self.app, None)
def test_checkpoint_show(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('checkpoint_id',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.checkpoints_mock.get.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3')
class TestDeleteCheckpoint(TestCheckpoints):
def setUp(self):
super(TestDeleteCheckpoint, self).setUp()
self.checkpoints_mock.get.return_value = checkpoints.Checkpoint(
None, CHECKPOINT_INFO)
# Command to test
self.cmd = osc_checkpoints.DeleteCheckpoint(self.app, None)
def test_checkpoint_delete(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('checkpoint',
['dcb20606-ad71-40a3-80e4-ef0fafdad0c3'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.checkpoints_mock.delete.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3')

View File

@@ -1,180 +0,0 @@
# 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 plans as osc_plans
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import plans
PLAN_INFO = {
"status": "suspended",
"provider_id": "cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"description": "",
"parameters": {},
"id": "204c825e-eb2f-4609-95ab-70b3caa43ac8",
"resources": [{
'type': 'OS::Cinder::Volume',
'id': '71bfe64a-e0b9-4a91-9e15-a7fc9ab31b14',
'name': 'testsinglevolume'}],
"name": "OS Volume protection plan."
}
class TestPlans(fakes.TestDataProtection):
def setUp(self):
super(TestPlans, self).setUp()
self.plans_mock = self.app.client_manager.data_protection.plans
self.plans_mock.reset_mock()
class TestListPlans(TestPlans):
def setUp(self):
super(TestListPlans, self).setUp()
self.plans_mock.list.return_value = [plans.Plan(
None, PLAN_INFO)]
# Command to test
self.cmd = osc_plans.ListPlans(self.app, None)
def test_plans_list(self):
arglist = ['--status', 'suspended']
verifylist = [('status', 'suspended')]
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', 'Name', 'Description', 'Provider id', 'Status'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [("204c825e-eb2f-4609-95ab-70b3caa43ac8",
"OS Volume protection plan.",
"",
"cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"suspended")]
self.assertEqual(expected_data, list(data))
class TestCreatePlan(TestPlans):
def setUp(self):
super(TestCreatePlan, self).setUp()
self.plans_mock.create.return_value = plans.Plan(
None, PLAN_INFO)
# Command to test
self.cmd = osc_plans.CreatePlan(self.app, None)
def test_plan_create(self):
arglist = ['OS Volume protection plan.',
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
"'71bfe64a-e0b9-4a91-9e15-a7fc9ab31b14'="
"'OS::Cinder::Volume'='testsinglevolume'"]
verifylist = [('name', 'OS Volume protection plan.'),
('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('resources', "'71bfe64a-e0b9-4a91-9e15-a7fc9ab31b14'="
"'OS::Cinder::Volume'='testsinglevolume'")]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.plans_mock.create.assert_called_once_with(
'OS Volume protection plan.',
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
[{'id': "'71bfe64a-e0b9-4a91-9e15-a7fc9ab31b14'",
'type': "'OS::Cinder::Volume'",
'name': "'testsinglevolume'"}],
{}, description=None)
class TestUpdatePlan(TestPlans):
def setUp(self):
super(TestUpdatePlan, self).setUp()
self.plans_mock.get.return_value = plans.Plan(
None, PLAN_INFO)
self.plans_mock.update.return_value = plans.Plan(
None, PLAN_INFO)
# Command to test
self.cmd = osc_plans.UpdatePlan(self.app, None)
def test_plan_update(self):
arglist = ['204c825e-eb2f-4609-95ab-70b3caa43ac8',
'--status', 'started']
verifylist = [('plan_id', '204c825e-eb2f-4609-95ab-70b3caa43ac8'),
('status', 'started')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.plans_mock.update.assert_called_once_with(
'204c825e-eb2f-4609-95ab-70b3caa43ac8',
{'status': 'started'})
class TestDeletePlan(TestPlans):
def setUp(self):
super(TestDeletePlan, self).setUp()
self.plans_mock.get.return_value = plans.Plan(
None, PLAN_INFO)
# Command to test
self.cmd = osc_plans.DeletePlan(self.app, None)
def test_plan_delete(self):
arglist = ['204c825e-eb2f-4609-95ab-70b3caa43ac8']
verifylist = [('plan', ['204c825e-eb2f-4609-95ab-70b3caa43ac8'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.plans_mock.delete.assert_called_once_with(
'204c825e-eb2f-4609-95ab-70b3caa43ac8')
class TestShowPlan(TestPlans):
def setUp(self):
super(TestShowPlan, self).setUp()
self.plans_mock.get.return_value = plans.Plan(
None, PLAN_INFO)
# Command to test
self.cmd = osc_plans.ShowPlan(self.app, None)
def test_plan_show(self):
arglist = ['204c825e-eb2f-4609-95ab-70b3caa43ac8']
verifylist = [('plan', '204c825e-eb2f-4609-95ab-70b3caa43ac8')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Check that columns are correct
expected_columns = (
'description', 'id', 'name', 'parameters', 'provider_id',
'resources', 'status')
self.assertEqual(expected_columns, columns)
# Check that data is correct
self.assertEqual(PLAN_INFO['description'], data[0])
self.assertEqual(PLAN_INFO['id'], data[1])
self.assertEqual(PLAN_INFO['name'], data[2])
self.assertEqual(PLAN_INFO['parameters'], data[3])
self.assertEqual(PLAN_INFO['provider_id'], data[4])
self.assertEqual(PLAN_INFO['resources'], data[5])
self.assertEqual(PLAN_INFO['status'], data[6])

View File

@@ -1,161 +0,0 @@
# 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 protectables as osc_protectables
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import protectables
PROTECTABLE_LIST_INFO = {
"protectable_type": [
"OS::Keystone::Project",
"OS::Cinder::Volume",
"OS::Glance::Image",
"OS::Nova::Server"
]
}
PROTECTABLE_SHOW_INFO = {
"name": "OS::Nova::Server",
"dependent_types": [
"OS::Cinder::Volume",
"OS::Glance::Image"
]
}
PROTECTABLE_INSTANCE_LIST_INFO = {
"id": "25336116-f38e-4c22-81ad-e9b7bd71ba51",
"type": "OS::Cinder::Volume",
"name": "System volume",
"extra_info": {
"availability_zone": "az1"
}
}
PROTECTABLE_INSTANCE_SHOW_INFO = {
"id": "cb4ef2ff-10f5-46c9-bce4-cf7a49c65a01",
"type": "OS::Nova::Server",
"name": "My VM",
"dependent_resources": [{
"id": "99777fdd-8a5b-45ab-ba2c-52420008103f",
"type": "OS::Glance::Image",
"name": "cirros-0.3.4-x86_64-uec"}]
}
class TestProtectables(fakes.TestDataProtection):
def setUp(self):
super(TestProtectables, self).setUp()
cm = self.app.client_manager
self.protectables_mock = cm.data_protection.protectables
self.protectables_mock.reset_mock()
class TestListProtectables(TestProtectables):
def setUp(self):
super(TestListProtectables, self).setUp()
self.protectables_mock.list.return_value = [protectables.Protectable(
None, PROTECTABLE_LIST_INFO)]
# Command to test
self.cmd = osc_protectables.ListProtectables(self.app, None)
def test_protectables_list(self):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Check that columns are correct
expected_columns = (
['Protectable type'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [(['OS::Keystone::Project',
'OS::Cinder::Volume',
'OS::Glance::Image',
'OS::Nova::Server'],)]
self.assertEqual(expected_data, list(data))
class TestShowProtectable(TestProtectables):
def setUp(self):
super(TestShowProtectable, self).setUp()
self.protectables_mock.get.return_value = protectables.Protectable(
None, PROTECTABLE_SHOW_INFO)
# Command to test
self.cmd = osc_protectables.ShowProtectable(self.app, None)
def test_protectable_show(self):
arglist = ['OS::Nova::Server']
verifylist = [('protectable_type', 'OS::Nova::Server')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.protectables_mock.get.assert_called_once_with(
'OS::Nova::Server')
class TestListProtectableInstances(TestProtectables):
def setUp(self):
super(TestListProtectableInstances, self).setUp()
pm = self.protectables_mock
pm.list_instances.return_value = protectables.Instances(
None, PROTECTABLE_INSTANCE_LIST_INFO)
# Command to test
self.cmd = osc_protectables.ListProtectableInstances(self.app, None)
def test_protectable_instances_list(self):
arglist = ['OS::Cinder::Volume']
verifylist = [('protectable_type', 'OS::Cinder::Volume')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.protectables_mock.list_instances.assert_called_once_with(
'OS::Cinder::Volume', limit=None, marker=None,
search_opts={'type': None, 'parameters': None},
sort=None)
class TestShowProtectableInstance(TestProtectables):
def setUp(self):
super(TestShowProtectableInstance, self).setUp()
pm = self.protectables_mock
pm.get_instance.return_value = protectables.Instances(
None, PROTECTABLE_INSTANCE_SHOW_INFO)
# Command to test
self.cmd = osc_protectables.ShowProtectableInstance(self.app, None)
def test_protectable_instance_show(self):
arglist = ['OS::Nova::Server', 'cb4ef2ff-10f5-46c9-bce4-cf7a49c65a01']
verifylist = [('protectable_type', 'OS::Nova::Server'),
('protectable_id',
'cb4ef2ff-10f5-46c9-bce4-cf7a49c65a01')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.protectables_mock.get_instance.assert_called_once_with(
'OS::Nova::Server', 'cb4ef2ff-10f5-46c9-bce4-cf7a49c65a01',
search_opts={'parameters': None})

View File

@@ -1,141 +0,0 @@
# 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 providers as osc_providers
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import providers
PROVIDER_INFO = {
"id": "2220f8b1-975d-4621-a872-fa9afb43cb6c",
"name": "OS Infra Provider",
"description": "provider description",
"extended_info_schema": {
"options_schema": {
"OS::Cinder::Volume": {
"required": [
"backup_mode"
],
"type": "object",
"properties": {
"backup_mode": {
"default": "auto",
"enum": [
"full",
"incremental",
"auto"
],
"type": "string",
"description": "The backup mode.",
"title": "Backup Mode"
}
},
"title": "Cinder Protection Options"
}
},
"saved_info_schema": {
"OS::Cinder::Volume": {
"required": [
"name"
],
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name for this backup.",
"title": "Name"
}
},
"title": "Cinder Protection Saved Info"
}
},
"restore_schema": {
"OS::Cinder::Volume": {
"type": "object",
"properties": {
"restore_name": {
"type": "string",
"description": "The name of the restored volume.",
"title": "Restore Name"
}
},
"title": "Cinder Protection Restore"
}
}
}
}
class TestProviders(fakes.TestDataProtection):
def setUp(self):
super(TestProviders, self).setUp()
self.providers_mock = self.app.client_manager.data_protection.providers
self.providers_mock.reset_mock()
class TestListProviders(TestProviders):
def setUp(self):
super(TestListProviders, self).setUp()
self.providers_mock.list.return_value = [providers.Provider(
None, PROVIDER_INFO)]
# Command to test
self.cmd = osc_providers.ListProviders(self.app, None)
def test_providers_list(self):
arglist = ['--name', 'OS Infra Provider']
verifylist = [('name', 'OS Infra Provider')]
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', 'Name', 'Description'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [("2220f8b1-975d-4621-a872-fa9afb43cb6c",
"OS Infra Provider",
"provider description")]
self.assertEqual(expected_data, list(data))
class TestShowProvider(TestProviders):
def setUp(self):
super(TestShowProvider, self).setUp()
self.providers_mock.get.return_value = providers.Provider(
None, PROVIDER_INFO)
# Command to test
self.cmd = osc_providers.ShowProvider(self.app, None)
def test_provider_show(self):
arglist = ['2220f8b1-975d-4621-a872-fa9afb43cb6c']
verifylist = [('provider', '2220f8b1-975d-4621-a872-fa9afb43cb6c')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Check that columns are correct
expected_columns = (
'description', 'extended_info_schema', 'id', 'name')
self.assertEqual(expected_columns, columns)
# Check that data is correct
self.assertEqual(PROVIDER_INFO['description'], data[0])
self.assertEqual(PROVIDER_INFO['extended_info_schema'], data[1])
self.assertEqual(PROVIDER_INFO['id'], data[2])
self.assertEqual(PROVIDER_INFO['name'], data[3])

View File

@@ -1,134 +0,0 @@
# 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 restores as osc_restores
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import restores
RESTORE_INFO = {
"id": "22b82aa7-9179-4c71-bba2-caf5c0e68db7",
"project_id": "e486a2f49695423ca9c47e589b948108",
"provider_id": "cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"checkpoint_id": "dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
"restore_target": "",
"parameters": {},
"restore_auth": {},
"resources_status": {},
"resources_reason": {},
"status": "success"
}
class TestRestores(fakes.TestDataProtection):
def setUp(self):
super(TestRestores, self).setUp()
self.restores_mock = self.app.client_manager.data_protection.restores
self.restores_mock.reset_mock()
class TestListRestores(TestRestores):
def setUp(self):
super(TestListRestores, self).setUp()
self.restores_mock.list.return_value = [restores.Restore(
None, RESTORE_INFO)]
# Command to test
self.cmd = osc_restores.ListRestores(self.app, None)
def test_restores_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', 'Project id', 'Provider id', 'Checkpoint id',
'Restore target', 'Parameters', 'Status'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [("22b82aa7-9179-4c71-bba2-caf5c0e68db7",
"e486a2f49695423ca9c47e589b948108",
"cf56bd3e-97a7-4078-b6d5-f36246333fd9",
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
"",
{},
"success")]
self.assertEqual(expected_data, list(data))
class TestCreateRestore(TestRestores):
def setUp(self):
super(TestCreateRestore, self).setUp()
self.restores_mock.create.return_value = restores.Restore(
None, RESTORE_INFO)
# Command to test
self.cmd = osc_restores.CreateRestore(self.app, None)
def test_restore_create(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('checkpoint_id',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.restores_mock.create.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3',
None, {}, None)
class TestShowRestore(TestRestores):
def setUp(self):
super(TestShowRestore, self).setUp()
self.restores_mock.get.return_value = restores.Restore(
None, RESTORE_INFO)
# Command to test
self.cmd = osc_restores.ShowRestore(self.app, None)
def test_restore_show(self):
arglist = ['22b82aa7-9179-4c71-bba2-caf5c0e68db7']
verifylist = [('restore', '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', 'id', 'parameters', 'project_id',
'provider_id', 'resources_reason', 'resources_status',
'restore_auth', 'restore_target', 'status')
self.assertEqual(expected_columns, columns)
# Check that data is correct
self.assertEqual(RESTORE_INFO['checkpoint_id'], data[0])
self.assertEqual(RESTORE_INFO['id'], data[1])
self.assertEqual(RESTORE_INFO['parameters'], data[2])
self.assertEqual(RESTORE_INFO['project_id'], data[3])
self.assertEqual(RESTORE_INFO['provider_id'], data[4])
self.assertEqual(RESTORE_INFO['resources_reason'], data[5])
self.assertEqual(RESTORE_INFO['resources_status'], data[6])
self.assertEqual(RESTORE_INFO['restore_auth'], data[7])
self.assertEqual(RESTORE_INFO['restore_target'], data[8])
self.assertEqual(RESTORE_INFO['status'], data[9])

View File

@@ -1,167 +0,0 @@
# 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 scheduled_operations as osc_so
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import scheduled_operations
SCHEDULEDOPERATION_INFO = {
"id": "1a2c0c3d-f402-4cd8-b5db-82e85cb51fad",
"name": "My scheduled operation",
"description": "It will run everyday",
"operation_type": "protect",
"trigger_id": "23902b02-5666-4ee6-8dfe-962ac09c3995",
"operation_definition": {
"provider_id": "2a9ce1f3-cc1a-4516-9435-0ebb13caa399",
"plan_id": "2a9ce1f3-cc1a-4516-9435-0ebb13caa398"
},
"enabled": 1
}
class TestScheduledOperations(fakes.TestDataProtection):
def setUp(self):
super(TestScheduledOperations, self).setUp()
self.so_mock = self.app.client_manager.data_protection.\
scheduled_operations
self.so_mock.reset_mock()
class TestListScheduledOperations(TestScheduledOperations):
def setUp(self):
super(TestListScheduledOperations, self).setUp()
self.so_mock.list.return_value = \
[scheduled_operations.ScheduledOperation(None,
SCHEDULEDOPERATION_INFO)]
# Command to test
self.cmd = osc_so.ListScheduledOperations(self.app, None)
def test_scheduled_operations_list(self):
arglist = ['--name', 'My scheduled operation']
verifylist = [('name', 'My scheduled operation')]
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', 'Name', 'OperationType', 'TriggerId',
'OperationDefinition'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [("1a2c0c3d-f402-4cd8-b5db-82e85cb51fad",
"My scheduled operation",
"protect",
"23902b02-5666-4ee6-8dfe-962ac09c3995",
{
"provider_id":
"2a9ce1f3-cc1a-4516-9435-0ebb13caa399", # noqa
"plan_id":
"2a9ce1f3-cc1a-4516-9435-0ebb13caa398"
})]
self.assertEqual(expected_data, data)
class TestCreateScheduledOperation(TestScheduledOperations):
def setUp(self):
super(TestCreateScheduledOperation, self).setUp()
self.so_mock.create.return_value = scheduled_operations.\
ScheduledOperation(None, SCHEDULEDOPERATION_INFO)
# Command to test
self.cmd = osc_so.CreateScheduledOperation(self.app, None)
def test_scheduled_operation_create(self):
arglist = ['My scheduled operation',
'protect',
"23902b02-5666-4ee6-8dfe-962ac09c3995",
"'provider_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa399,"
"plan_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa398'"]
verifylist = [('name', 'My scheduled operation'),
('operation_type', 'protect'),
('trigger_id', "23902b02-5666-4ee6-8dfe-962ac09c3995"),
('operation_definition',
"'provider_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa399,"
"plan_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa398'")]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.so_mock.create.assert_called_once_with(
'My scheduled operation',
'protect',
'23902b02-5666-4ee6-8dfe-962ac09c3995',
"'provider_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa399,"
"plan_id=2a9ce1f3-cc1a-4516-9435-0ebb13caa398'")
class TestDeleteScheduledOperation(TestScheduledOperations):
def setUp(self):
super(TestDeleteScheduledOperation, self).setUp()
self.so_mock.get.return_value = scheduled_operations.\
ScheduledOperation(None, SCHEDULEDOPERATION_INFO)
# Command to test
self.cmd = osc_so.DeleteScheduledOperation(self.app, None)
def test_scheduled_operation_delete(self):
arglist = ['1a2c0c3d-f402-4cd8-b5db-82e85cb51fad']
verifylist = [('scheduledoperation',
['1a2c0c3d-f402-4cd8-b5db-82e85cb51fad'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.so_mock.delete.assert_called_once_with(
'1a2c0c3d-f402-4cd8-b5db-82e85cb51fad')
class TestShowScheduledOperation(TestScheduledOperations):
def setUp(self):
super(TestShowScheduledOperation, self).setUp()
self.so_mock.get.return_value = scheduled_operations.\
ScheduledOperation(None, SCHEDULEDOPERATION_INFO)
# Command to test
self.cmd = osc_so.ShowScheduledOperation(self.app, None)
def test_scheduled_operation_show(self):
arglist = ['1a2c0c3d-f402-4cd8-b5db-82e85cb51fad']
verifylist = [('scheduledoperation',
'1a2c0c3d-f402-4cd8-b5db-82e85cb51fad')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Check that columns are correct
expected_columns = (
'description', 'enabled', 'id', 'name', 'operation_definition',
'operation_type', 'trigger_id')
self.assertEqual(expected_columns, columns)
# Check that data is correct
self.assertEqual(SCHEDULEDOPERATION_INFO['description'], data[0])
self.assertEqual(SCHEDULEDOPERATION_INFO['enabled'], data[1])
self.assertEqual(SCHEDULEDOPERATION_INFO['id'], data[2])
self.assertEqual(SCHEDULEDOPERATION_INFO['name'], data[3])
self.assertEqual(SCHEDULEDOPERATION_INFO['operation_definition'],
data[4])
self.assertEqual(SCHEDULEDOPERATION_INFO['operation_type'], data[5])
self.assertEqual(SCHEDULEDOPERATION_INFO['trigger_id'], data[6])

View File

@@ -1,186 +0,0 @@
# 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 triggers as osc_triggers
from karborclient.tests.unit.osc.v1 import fakes
from karborclient.v1 import triggers
TRIGGER_INFO = {
"id": "2a9ce1f3-cc1a-4516-9435-0ebb13caa398",
"name": "My backup trigger",
"type": "time",
"properties": {
"format": "calendar",
"pattern": "BEGIN:VEVENT\\nRRULE:FREQ=HOURLY;INTERVAL=1;\\nEND:VEVENT",
"start_time": "2015-12-17T08:30:00",
"end_time": "2016-03-17T08:30:00",
"window": "3600"
}
}
class TestTriggers(fakes.TestDataProtection):
def setUp(self):
super(TestTriggers, self).setUp()
self.triggers_mock = self.app.client_manager.data_protection.triggers
self.triggers_mock.reset_mock()
class TestListTriggers(TestTriggers):
def setUp(self):
super(TestListTriggers, self).setUp()
self.triggers_mock.list.return_value = [triggers.Trigger(
None, TRIGGER_INFO)]
# Command to test
self.cmd = osc_triggers.ListTriggers(self.app, None)
def test_triggers_list(self):
arglist = ['--name', 'My backup trigger']
verifylist = [('name', 'My backup trigger')]
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', 'Name', 'Type', 'Properties'])
self.assertEqual(expected_columns, columns)
# Check that data is correct
expected_data = [("2a9ce1f3-cc1a-4516-9435-0ebb13caa398",
"My backup trigger",
"time",
{"format": "calendar",
"pattern": "BEGIN:VEVENT\\nRRULE:FREQ=HOURLY;INTERVAL=1;\\nEND:VEVENT", # noqa
"start_time": "2015-12-17T08:30:00",
"end_time": "2016-03-17T08:30:00",
"window": "3600"})]
self.assertEqual(expected_data, list(data))
class TestCreateTrigger(TestTriggers):
def setUp(self):
super(TestCreateTrigger, self).setUp()
self.triggers_mock.create.return_value = triggers.Trigger(
None, TRIGGER_INFO)
# Command to test
self.cmd = osc_triggers.CreateTrigger(self.app, None)
def test_trigger_create(self):
arglist = ['My backup trigger',
'time',
"'format'='calendar',"
"'pattern'='BEGIN:VEVENT\\nRRULE:FREQ=HOURLY;INTERVAL=1;\\nEND:VEVENT'," # noqa
"'start_time'='2015-12-17T08:30:00',"
"'end_time'='2016-03-17T08:30:00',"
"'window'='3600'"]
verifylist = [('name', 'My backup trigger'),
('type', 'time'),
('properties', "'format'='calendar',"
"'pattern'='BEGIN:VEVENT\\nRRULE:FREQ=HOURLY;INTERVAL=1;\\nEND:VEVENT'," # noqa
"'start_time'='2015-12-17T08:30:00',"
"'end_time'='2016-03-17T08:30:00',"
"'window'='3600'")]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.triggers_mock.create.assert_called_once_with(
'My backup trigger',
'time',
"'format'='calendar',"
"'pattern'='BEGIN:VEVENT\\nRRULE:FREQ=HOURLY;INTERVAL=1;\\nEND:VEVENT'," # noqa
"'start_time'='2015-12-17T08:30:00',"
"'end_time'='2016-03-17T08:30:00',"
"'window'='3600'")
class TestUpdateTrigger(TestTriggers):
def setUp(self):
super(TestUpdateTrigger, self).setUp()
self.triggers_mock.get.return_value = triggers.Trigger(
None, TRIGGER_INFO)
self.triggers_mock.update.return_value = triggers.Trigger(
None, TRIGGER_INFO)
# Command to test
self.cmd = osc_triggers.UpdateTrigger(self.app, None)
def test_trigger_update(self):
arglist = ['2a9ce1f3-cc1a-4516-9435-0ebb13caa398',
'--name', 'My backup trigger']
verifylist = [('trigger_id', '2a9ce1f3-cc1a-4516-9435-0ebb13caa398'),
('name', 'My backup trigger')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.triggers_mock.update.assert_called_once_with(
'2a9ce1f3-cc1a-4516-9435-0ebb13caa398',
{'name': 'My backup trigger'})
class TestDeleteTrigger(TestTriggers):
def setUp(self):
super(TestDeleteTrigger, self).setUp()
self.triggers_mock.get.return_value = triggers.Trigger(
None, TRIGGER_INFO)
# Command to test
self.cmd = osc_triggers.DeleteTrigger(self.app, None)
def test_trigger_delete(self):
arglist = ['2a9ce1f3-cc1a-4516-9435-0ebb13caa398']
verifylist = [('trigger', ['2a9ce1f3-cc1a-4516-9435-0ebb13caa398'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Check that correct arguments were passed
self.triggers_mock.delete.assert_called_once_with(
'2a9ce1f3-cc1a-4516-9435-0ebb13caa398')
class TestShowTrigger(TestTriggers):
def setUp(self):
super(TestShowTrigger, self).setUp()
self.triggers_mock.get.return_value = triggers.Trigger(
None, TRIGGER_INFO)
# Command to test
self.cmd = osc_triggers.ShowTrigger(self.app, None)
def test_trigger_show(self):
arglist = ['2a9ce1f3-cc1a-4516-9435-0ebb13caa398']
verifylist = [('trigger', '2a9ce1f3-cc1a-4516-9435-0ebb13caa398')]
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', 'name', 'properties', 'type')
self.assertEqual(expected_columns, columns)
# Check that data is correct
self.assertEqual(TRIGGER_INFO['id'], data[0])
self.assertEqual(TRIGGER_INFO['name'], data[1])
self.assertEqual(TRIGGER_INFO['properties'], data[2])
self.assertEqual(TRIGGER_INFO['type'], data[3])

View File

@@ -15,8 +15,8 @@ import re
import sys
import fixtures
from keystoneauth1 import fixture
from keystoneauth1.fixture import v2 as ks_v2_fixture
from keystoneclient import fixture
from keystoneclient.fixture import v2 as ks_v2_fixture
import mock
from oslo_log import handlers
from oslo_log import log
@@ -134,7 +134,7 @@ class ShellCommandTest(ShellTest):
def test_help(self):
required = [
'.*?^usage: karbor',
'.*?^\s+plan-create\s+Creates a plan.',
'.*?^\s+plan-create\s+Create a plan.',
'.*?^See "karbor help COMMAND" for help on a specific command',
]
stdout, stderr = self.shell('help')
@@ -145,7 +145,7 @@ class ShellCommandTest(ShellTest):
def test_help_on_subcommand(self):
required = [
'.*?^usage: karbor plan-create',
'.*?^Creates a plan.',
'.*?^Create a plan.',
]
stdout, stderr = self.shell('help plan-create')
for r in required:
@@ -155,7 +155,7 @@ class ShellCommandTest(ShellTest):
def test_help_no_options(self):
required = [
'.*?^usage: karbor',
'.*?^\s+plan-create\s+Creates a plan',
'.*?^\s+plan-create\s+Create a plan',
'.*?^See "karbor help COMMAND" for help on a specific command',
]
stdout, stderr = self.shell('')

View File

@@ -82,7 +82,7 @@ class FakeHTTPClient(base_client.HTTPClient):
(method, url, callback))
# Note the call
self.callstack.append((method, url, kwargs.get('body')))
self.callstack.append((method, url, kwargs.get('body', None)))
status, headers, body = getattr(self, callback)(**kwargs)
# add fake request-id header
headers['x-openstack-request-id'] = REQUEST_ID

View File

@@ -1,146 +0,0 @@
# 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 oslo_serialization import jsonutils
from oslo_utils import uuidutils
from karborclient.common.apiclient import exceptions
def extract_resources(args):
resources = []
for data in args.resources.split(','):
if '=' in data and len(data.split('=')) in [3, 4]:
resource = dict(zip(['id', 'type', 'name', 'extra_info'],
data.split('=')))
if resource.get('extra_info'):
resource['extra_info'] = jsonutils.loads(
resource.get('extra_info'))
else:
raise exceptions.CommandError(
"Unable to parse parameter resources. "
"The keys of resource are id , type, name and "
"extra_info. The extra_info field is optional.")
resources.append(resource)
return resources
def check_resources(cs, resources):
# check the resource whether it is available
for resource in resources:
try:
instance = cs.protectables.get_instance(
resource["type"], resource["id"])
except exceptions.NotFound:
raise exceptions.CommandError(
"The resource: %s can not be found." % resource["id"])
else:
if instance is None:
raise exceptions.CommandError(
"The resource: %s is invalid." % resource["id"])
def extract_parameters(args):
if all((args.parameters, args.parameters_json)):
raise exceptions.CommandError(
"Must provide parameters or parameters-json, not both")
if not any((args.parameters, args.parameters_json)):
return {}
if args.parameters_json:
return jsonutils.loads(args.parameters_json)
parameters = {}
for resource_params in args.parameters:
resource_type = None
resource_id = None
parameter = {}
for param_kv in resource_params.split(','):
try:
key, value = param_kv.split('=')
except Exception:
raise exceptions.CommandError(
'parameters must be in the form: key1=val1,key2=val2,...'
)
if key == "resource_type":
resource_type = value
elif key == "resource_id":
if not uuidutils.is_uuid_like(value):
raise exceptions.CommandError('resource_id must be a uuid')
resource_id = value
else:
parameter[key] = value
if resource_type is None:
raise exceptions.CommandError(
'Must specify resource_type for parameters'
)
if resource_id is None:
resource_key = resource_type
else:
resource_key = "%s#%s" % (resource_type, resource_id)
parameters[resource_key] = parameter
return parameters
def extract_instances_parameters(args):
parameters = {}
for parameter in args.parameters:
if '=' in parameter:
(key, value) = parameter.split('=', 1)
else:
key = parameter
value = None
parameters[key] = value
return parameters
def extract_extra_info(args):
checkpoint_extra_info = {}
for data in args.extra_info:
# unset doesn't require a val, so we have the if/else
if '=' in data:
(key, value) = data.split('=', 1)
else:
key = data
value = None
checkpoint_extra_info[key] = value
return checkpoint_extra_info
def extract_properties(args):
properties = {}
if args.properties is None:
return properties
for data in args.properties.split(','):
if '=' in data:
(resource_key, resource_value) = data.split('=', 1)
else:
raise exceptions.CommandError(
"Unable to parse parameter properties.")
properties[resource_key] = resource_value
return properties
def extract_operation_definition(args):
operation_definition = {}
for data in args.operation_definition.split(','):
if '=' in data:
(resource_key, resource_value) = data.split('=', 1)
else:
raise exceptions.CommandError(
"Unable to parse parameter operation_definition.")
operation_definition[resource_key] = resource_value
return operation_definition

View File

@@ -25,7 +25,7 @@ class Checkpoint(base.Resource):
return
plan = self.protection_plan
if plan is not None:
provider_id = plan.get("provider_id")
provider_id = plan.get("provider_id", None)
new = self.manager.get(provider_id, self.id)
if new:
self._add_details(new._info)

View File

@@ -15,12 +15,12 @@ import json
import os
from datetime import datetime
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from karborclient.common.apiclient import exceptions
from karborclient.common import base
from karborclient.common import utils
from karborclient import utils as arg_utils
@utils.arg('--all-tenants',
@@ -118,10 +118,9 @@ def do_plan_list(cs, args):
metavar='<provider_id>',
help='ID of provider.')
@utils.arg('resources',
metavar='<id=type=name=extra_info,id=type=name=extra_info>',
metavar='<id=type=name,id=type=name>',
help='Resource in list must be a dict when creating'
' a plan. The keys of resource are id ,type, name and '
'extra_info. The extra_info field is optional.')
' a plan.The keys of resource are id and type.')
@utils.arg('--parameters-json',
type=str,
dest='parameters_json',
@@ -141,13 +140,10 @@ def do_plan_list(cs, args):
metavar='<description>',
help='The description of a plan.')
def do_plan_create(cs, args):
"""Creates a plan."""
if not uuidutils.is_uuid_like(args.provider_id):
raise exceptions.CommandError(
"Invalid provider id provided.")
plan_resources = arg_utils.extract_resources(args)
arg_utils.check_resources(cs, plan_resources)
plan_parameters = arg_utils.extract_parameters(args)
"""Create a plan."""
plan_resources = _extract_resources(args)
_check_resources(cs, plan_resources)
plan_parameters = _extract_parameters(args)
plan = cs.plans.create(args.name, args.provider_id, plan_resources,
plan_parameters, description=args.description)
dict_format_list = {"resources", "parameters"}
@@ -169,7 +165,7 @@ def do_plan_show(cs, args):
nargs="+",
help='ID of plan.')
def do_plan_delete(cs, args):
"""Deletes plan."""
"""Delete plan."""
failure_count = 0
for plan_id in args.plan:
try:
@@ -193,12 +189,12 @@ def do_plan_delete(cs, args):
@utils.arg("--status", metavar="<suspended|started>",
help="status to which the plan will be updated.")
def do_plan_update(cs, args):
"""Updatas a plan."""
"""Updata a plan."""
data = {}
if args.name is not None:
data['name'] = args.name
if args.resources is not None:
plan_resources = arg_utils.extract_resources(args)
plan_resources = _extract_resources(args)
data['resources'] = plan_resources
if args.status is not None:
data['status'] = args.status
@@ -211,6 +207,39 @@ def do_plan_update(cs, args):
utils.print_dict(plan.to_dict())
def _extract_resources(args):
resources = []
for data in args.resources.split(','):
resource = {}
if '=' in data:
(resource_id, resource_type, resource_name) = data.split('=', 2)
else:
raise exceptions.CommandError(
"Unable to parse parameter resources.")
resource["id"] = resource_id
resource["type"] = resource_type
resource["name"] = resource_name
resources.append(resource)
return resources
def _check_resources(cs, resources):
# check the resource whether it is available
for resource in resources:
try:
instance = cs.protectables.get_instance(
resource["type"], resource["id"])
except exceptions.NotFound:
raise exceptions.CommandError(
"The resource: %s can not be found." % resource["id"])
else:
if instance is None:
raise exceptions.CommandError(
"The resource: %s is invalid." % resource["id"])
@utils.arg('provider_id',
metavar='<provider_id>',
help='Provider id.')
@@ -244,7 +273,7 @@ def do_plan_update(cs, args):
'Other keys and values: according to provider\'s restore schema.'
)
def do_restore_create(cs, args):
"""Creates a restore."""
"""Create a restore."""
if not uuidutils.is_uuid_like(args.provider_id):
raise exceptions.CommandError(
"Invalid provider id provided.")
@@ -253,7 +282,7 @@ def do_restore_create(cs, args):
raise exceptions.CommandError(
"Invalid checkpoint id provided.")
restore_parameters = arg_utils.extract_parameters(args)
restore_parameters = _extract_parameters(args)
restore_auth = None
if args.restore_target is not None:
if args.restore_username is None:
@@ -274,6 +303,48 @@ def do_restore_create(cs, args):
utils.print_dict(restore.to_dict(), dict_format_list=dict_format_list)
def _extract_parameters(args):
if all((args.parameters, args.parameters_json)):
raise exceptions.CommandError(
"Must provide parameters or parameters-json, not both")
if not any((args.parameters, args.parameters_json)):
return {}
if args.parameters_json:
return jsonutils.loads(args.parameters_json)
parameters = {}
for resource_params in args.parameters:
resource_type = None
resource_id = None
parameter = {}
for param_kv in resource_params.split(','):
try:
key, value = param_kv.split('=')
except Exception:
raise exceptions.CommandError(
'parameters must be in the form: key1=val1,key2=val2,...'
)
if key == "resource_type":
resource_type = value
elif key == "resource_id":
if not uuidutils.is_uuid_like(value):
raise exceptions.CommandError('resource_id must be a uuid')
resource_id = value
else:
parameter[key] = value
if resource_type is None:
raise exceptions.CommandError(
'Must specify resource_type for parameters'
)
if resource_id is None:
resource_key = resource_type
else:
resource_key = "%s#%s" % (resource_type, resource_id)
parameters[resource_key] = parameter
return parameters
@utils.arg('--all-tenants',
dest='all_tenants',
metavar='<0|1>',
@@ -366,7 +437,7 @@ def do_restore_show(cs, args):
def do_protectable_list(cs, args):
"""Lists all protectable types."""
"""Lists all protectables type."""
protectables = cs.protectables.list()
@@ -400,7 +471,7 @@ def do_protectable_show(cs, args):
def do_protectable_show_instance(cs, args):
"""Shows instance details."""
search_opts = {
'parameters': (arg_utils.extract_instances_parameters(args)
'parameters': (_extract_instances_parameters(args)
if args.parameters else None),
}
instance = cs.protectables.get_instance(args.protectable_type,
@@ -454,7 +525,7 @@ def do_protectable_list_instances(cs, args):
search_opts = {
'type': args.type,
'parameters': (arg_utils.extract_instances_parameters(args)
'parameters': (_extract_instances_parameters(args)
if args.parameters else None),
}
@@ -469,7 +540,7 @@ def do_protectable_list_instances(cs, args):
sort_key=args.sort_key,
sort_dir=args.sort_dir, sort=args.sort)
key_list = ['Id', 'Type', 'Name', 'Dependent resources', 'Extra info']
key_list = ['Id', 'Type', 'Dependent resources']
if args.sort_key or args.sort_dir or args.sort:
sortby_index = None
@@ -482,6 +553,19 @@ def do_protectable_list_instances(cs, args):
sortby_index=sortby_index, formatters=formatters)
def _extract_instances_parameters(args):
parameters = {}
for parameter in args.parameters:
if '=' in parameter:
(key, value) = parameter.split('=', 1)
else:
key = parameter
value = None
parameters[key] = value
return parameters
@utils.arg('provider_id',
metavar='<provider_id>',
help='Id of provider.')
@@ -565,11 +649,11 @@ def do_provider_list(cs, args):
default=None,
help='The extra info of a checkpoint.')
def do_checkpoint_create(cs, args):
"""Creates a checkpoint."""
"""Create a checkpoint."""
checkpoint_extra_info = None
if args.extra_info is not None:
checkpoint_extra_info = arg_utils.extract_extra_info(args)
checkpoint_extra_info = _extract_extra_info(args)
checkpoint = cs.checkpoints.create(args.provider_id, args.plan_id,
checkpoint_extra_info)
dict_format_list = {"protection_plan"}
@@ -578,27 +662,41 @@ def do_checkpoint_create(cs, args):
json_format_list=json_format_list)
def _extract_extra_info(args):
checkpoint_extra_info = {}
for data in args.extra_info:
# unset doesn't require a val, so we have the if/else
if '=' in data:
(key, value) = data.split('=', 1)
else:
key = data
value = None
checkpoint_extra_info[key] = value
return checkpoint_extra_info
@utils.arg('provider_id',
metavar='<provider_id>',
help='ID of provider.')
@utils.arg('--plan_id',
metavar='<plan_id>',
default=None,
help='Filters results by a plan ID. Default=None.')
help='Filters results by a plan_id. Default=None.')
@utils.arg('--start_date',
type=str,
metavar='<start_date>',
default=None,
help='Filters results by a start date("Y-m-d"). Default=None.')
help='Filters results by a start_date("Y-m-d"). Default=None.')
@utils.arg('--end_date',
type=str,
metavar='<end_date>',
default=None,
help='Filters results by a end date("Y-m-d"). Default=None.')
help='Filters results by a end_date("Y-m-d"). Default=None.')
@utils.arg('--project_id',
metavar='<project_id>',
default=None,
help='Filters results by a project ID. Default=None.')
help='Filters results by a project id. Default=None.')
@utils.arg('--marker',
metavar='<marker>',
default=None,
@@ -699,7 +797,7 @@ def do_checkpoint_show(cs, args):
nargs="+",
help='ID of checkpoint.')
def do_checkpoint_delete(cs, args):
"""Deletes checkpoints."""
"""Delete checkpoints."""
failure_count = 0
for checkpoint_id in args.checkpoint:
try:
@@ -816,13 +914,28 @@ def do_trigger_list(cs, args):
metavar='<key=value,key=value>',
help='Properties of trigger.')
def do_trigger_create(cs, args):
"""Creates a trigger."""
trigger_properties = arg_utils.extract_properties(args)
"""Create a trigger."""
trigger_properties = _extract_properties(args)
trigger = cs.triggers.create(args.name, args.type, trigger_properties)
dict_format_list = {"properties"}
utils.print_dict(trigger.to_dict(), dict_format_list=dict_format_list)
def _extract_properties(args):
properties = {}
if args.properties is None:
return properties
for data in args.properties.split(','):
if '=' in data:
(resource_key, resource_value) = data.split('=', 1)
else:
raise exceptions.CommandError(
"Unable to parse parameter properties.")
properties[resource_key] = resource_value
return properties
@utils.arg("trigger_id", metavar="<TRIGGER ID>",
help="Id of trigger to update.")
@utils.arg("--name", metavar="<name>",
@@ -832,7 +945,7 @@ def do_trigger_create(cs, args):
def do_trigger_update(cs, args):
"""Update a trigger."""
trigger_info = {}
trigger_properties = arg_utils.extract_properties(args)
trigger_properties = _extract_properties(args)
trigger_info['name'] = args.name
trigger_info['properties'] = trigger_properties
trigger = cs.triggers.update(args.trigger_id, trigger_info)
@@ -855,7 +968,7 @@ def do_trigger_show(cs, args):
nargs="+",
help='ID of trigger.')
def do_trigger_delete(cs, args):
"""Deletes trigger."""
"""Delete trigger."""
failure_count = 0
for trigger_id in args.trigger:
try:
@@ -898,7 +1011,7 @@ def do_trigger_delete(cs, args):
@utils.arg('--operation_definition',
metavar='<operation_definition>',
default=None,
help='Filters results by a operation definition. Default=None.')
help='Filters results by the operation_definition. Default=None.')
@utils.arg('--marker',
metavar='<marker>',
default=None,
@@ -977,8 +1090,8 @@ def do_scheduledoperation_list(cs, args):
metavar='<key=value,key=value>',
help='Operation definition of scheduled operation.')
def do_scheduledoperation_create(cs, args):
"""Creates a scheduled operation."""
operation_definition = arg_utils.extract_operation_definition(args)
"""Create a scheduled operation."""
operation_definition = _extract_operation_definition(args)
scheduledoperation = cs.scheduled_operations.create(args.name,
args.operation_type,
args.trigger_id,
@@ -988,6 +1101,19 @@ def do_scheduledoperation_create(cs, args):
dict_format_list=dict_format_list)
def _extract_operation_definition(args):
operation_definition = {}
for data in args.operation_definition.split(','):
if '=' in data:
(resource_key, resource_value) = data.split('=', 1)
else:
raise exceptions.CommandError(
"Unable to parse parameter operation_definition.")
operation_definition[resource_key] = resource_value
return operation_definition
@utils.arg('scheduledoperation',
metavar='<scheduledoperation>',
help='ID of scheduled operation.')
@@ -1004,7 +1130,7 @@ def do_scheduledoperation_show(cs, args):
nargs="+",
help='ID of scheduled operation.')
def do_scheduledoperation_delete(cs, args):
"""Deletes a scheduled operation."""
"""Delete a scheduled operation."""
failure_count = 0
for scheduledoperation_id in args.scheduledoperation:
try:

View File

@@ -1,14 +1,13 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
pbr>=1.8 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
keystoneauth1!=3.0.0,>=2.21.0 # Apache-2.0
requests>=2.14.2 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
requests!=2.12.2,>=2.10.0 # Apache-2.0
simplejson>=2.2.0 # MIT
Babel!=2.4.0,>=2.3.4 # BSD
Babel>=2.3.4 # BSD
six>=1.9.0 # MIT
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
oslo.utils>=3.18.0 # Apache-2.0
oslo.log>=3.11.0 # Apache-2.0
oslo.i18n>=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/karbor/latest
home-page = http://docs.openstack.org/developer/karbor/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -16,6 +16,7 @@ classifier =
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
[global]
@@ -30,52 +31,6 @@ packages =
console_scripts =
karbor = karborclient.shell:main
openstack.cli.extension =
data_protection = karborclient.osc.plugin
openstack.data_protection.v1 =
data_protection_plan_list = karborclient.osc.v1.plans:ListPlans
data_protection_plan_show = karborclient.osc.v1.plans:ShowPlan
data_protection_plan_create = karborclient.osc.v1.plans:CreatePlan
data_protection_plan_update = karborclient.osc.v1.plans:UpdatePlan
data_protection_plan_delete = karborclient.osc.v1.plans:DeletePlan
data_protection_restore_list = karborclient.osc.v1.restores:ListRestores
data_protection_restore_show = karborclient.osc.v1.restores:ShowRestore
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_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
data_protection_trigger_update = karborclient.osc.v1.triggers:UpdateTrigger
data_protection_trigger_delete = karborclient.osc.v1.triggers:DeleteTrigger
data_protection_checkpoint_list = karborclient.osc.v1.checkpoints:ListCheckpoints
data_protection_checkpoint_show = karborclient.osc.v1.checkpoints:ShowCheckpoint
data_protection_checkpoint_create = karborclient.osc.v1.checkpoints:CreateCheckpoint
data_protection_checkpoint_delete = karborclient.osc.v1.checkpoints:DeleteCheckpoint
data_protection_scheduledoperation_list = karborclient.osc.v1.scheduled_operations:ListScheduledOperations
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
[compile_catalog]
directory = karborclient/locale
domain = karborclient
[update_catalog]
domain = karborclient
output_dir = karborclient/locale
input_file = karborclient/locale/karborclient.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = karborclient/locale/karborclient.pot
[build_sphinx]
source-dir = doc/source
build-dir = doc/build

View File

@@ -25,5 +25,5 @@ except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
setup_requires=['pbr>=1.8'],
pbr=True)

View File

@@ -2,16 +2,14 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
hacking<0.11,>=0.10.2 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
coverage>=4.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
docutils>=0.11 # OSI-Approved Open Source, Public Domain
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.11.0 # Apache-2.0
docutils!=0.13.1,>=0.11 # OSI-Approved Open Source, Public Domain
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
oslosphinx>=4.7.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0
requests-mock>=1.1 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Client constraint file contains this client version pin that is in conflict
# with installing the client from source. We should remove the version pin in
# the constraints file before applying it for from-source installation.
CONSTRAINTS_FILE="$1"
shift 1
set -e
# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
# published to logs.openstack.org for easy debugging.
localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
if [[ "$CONSTRAINTS_FILE" != http* ]]; then
CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
fi
# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
pip install -c"$localfile" openstack-requirements
# This is the main purpose of the script: Allow local installation of
# the current repo. It is listed in constraints file and thus any
# install will be constrained and we need to unconstrain it.
edit-constraints "$localfile" -- "$CLIENT_NAME"
pip install -c"$localfile" -U "$@"
exit $?

16
tox.ini
View File

@@ -1,17 +1,18 @@
[tox]
minversion = 2.0
envlist = py35,py27,pypy,pep8
envlist = py35,py34,py27,pypy,pep8
skipsdist = True
[testenv]
usedevelop = True
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
install_command = pip install {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
BRANCH_NAME=master
CLIENT_NAME=python-karborclient
PYTHONWARNINGS=default::DeprecationWarning
deps = -r{toxinidir}/requirements.txt
deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/ocata}
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = python setup.py test --slowest --testr-args='{posargs}'
@@ -27,19 +28,18 @@ setenv =
OS_TEST_PATH = ./karborclient/tests/functional
passenv = OS_*
[testenv:cover]
commands =
python setup.py test --coverage --testr-args='{posargs}'
coverage report
commands = python setup.py test --coverage --testr-args='{posargs}'
[testenv:docs]
commands = python setup.py build_sphinx
[testenv:debug]
commands = oslo_debug_helper -t karborclient/tests {posargs}
commands = oslo_debug_helper {posargs}
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
ignore =
ignore = E123,E125
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools