Compare commits

..

51 Commits

Author SHA1 Message Date
Zuul
3216f64d14 Merge "Add Python 3.6 classifier to setup.cfg" 2018-12-21 01:27:52 +00:00
Zuul
e5440f809d Merge "Convert trigger window from string to integer" 2018-12-10 06:26:49 +00:00
YUHAN
d45538cf41 Convert trigger window from string to integer
Change-Id: Iccdaea4b4e5aedd2548e865576eb718643e41cf9
2018-12-10 12:56:18 +08:00
98k
ce7b872c26 Change openstack-dev to openstack-discuss
Mailinglists have been updated. Openstack-discuss replaces openstack-dev.

Change-Id: I7fd74af8edb78fd95f59162f1282f1434c522cac
2018-12-04 07:38:17 +00:00
Zuul
a0a7b4a24b Merge "Add osc support to update plan description" 2018-12-04 07:17:46 +00:00
liushuai
c2e7441444 Add osc support to update plan description
Change-Id: Ibc661594342a89cc5f89084972a4fb9844da1a84
2018-12-04 13:56:51 +08:00
Zuul
5cf1f0d246 Merge "Unsubmitted name field shoud be ignored" 2018-12-04 05:48:27 +00:00
Zuul
c992876f96 Merge "Add support to update plan description" 2018-12-04 05:45:40 +00:00
Zuul
bc9ac570bf Merge "Add osc support to reset checkpoint state" 2018-12-03 08:53:48 +00:00
Jiao Pengju
048b3a0bd9 Add support to reset checkpoint state
This patch added clinet support for doing
checkpoint state reset.
Implements: bp checkpoint-status-reset

Change-Id: Id34501bd4d43c6ae0e9d0d789be7e92581cbff8c
2018-12-03 14:14:50 +08:00
liushuai
58234ab51c Add support to update plan description
Change-Id: I048e970cd449e0e51bbfc3a97e325afd0fa73d5c
2018-12-02 23:19:04 +08:00
Jiao Pengju
1eb26df991 Add osc support to reset checkpoint state
This patch added osc clinet support for doing
checkpoint state reset.
Implements: bp checkpoint-status-reset

Change-Id: If7c2ae3563ff0959c4c59f2b23a8c7c9ea11e196
2018-12-02 22:35:47 +08:00
qingszhao
47d15a74a3 Add Python 3.6 classifier to setup.cfg
Change-Id: Ibc1b7be0b55756b8768b58b04b0898b76aba8427
2018-11-30 06:56:08 +00:00
liushuai
597e452dbc Unsubmitted name field shoud be ignored
Closes-Bug: #1805815

Change-Id: Ife1a13b7b145eff7a8e8e8471bac0ee43c195c68
2018-11-30 00:11:01 +08:00
liushuai
262799e3c0 Convert trigger window from string to integer
Closes-Bug: #1805755

Change-Id: Ib2da9cb008fad3f9d686a1409c83d98b7daebe68
2018-11-29 11:21:42 +08:00
Zuul
f3c117e17c Merge "Add osc all tenants support for checkpoint listing" 2018-11-19 03:36:42 +00:00
Jiao Pengju
e3ed8939b8 Add osc all tenants support for checkpoint listing
Change-Id: I19c5461f28425377918ebc3faeaf5a7340eaead8
Implements: bp checkpoint-all-tenants
2018-11-18 21:00:08 +08:00
Jiao Pengju
38b2b847c8 Add all tenants support for checkpoint listing
Change-Id: Iffcc68efad6a218faa9a6d6d53ff1f7b833ed13e
Implements: bp checkpoint-all-tenants
2018-11-18 20:05:52 +08:00
Jiao Pengju
2fe9422e04 Limit the operation type for scheduledoperation
Now karbor only support two types of scheduledoperation,
but the client do not show and limit the values. So the
end users can type any string to execute the command of
'scheduledoperation create', but the server returns error
, this will make users confused, and they still not know
the right value. This patch will limit the operation type
in 'protect' and 'retention_protect'.

Change-Id: Ic1110124472ac455f988bb25254feeb4417caf1a
2018-11-09 12:38:52 +08:00
Zuul
b0011487e2 Merge "Use templates for cover and lower-constraints" 2018-10-10 01:03:12 +00:00
Chen
db689c650f Remove PyPI downloads
According to official site,
https://packaging.python.org/guides/analyzing-pypi-package-downloads/
PyPI package download statistics is no longer maintained and thus
should be removed.

Change-Id: I0cdc7bdfa4a8c36d57a2c0f5391a7e8c53925fed
2018-10-06 02:45:59 +00:00
Andreas Jaeger
1c2079ef71 Use templates for cover and lower-constraints
Small cleanups:

* Use openstack-tox-cover template, this runs the cover job
  in the check queue only. Remove individual cover jobs.
* Use openstack-lower-constraints-jobs template, remove individual
  jobs.
* Sort list of templates

Change-Id: I1d4176ff6a3c53c447f9d118008d3d51ac455b88
2018-09-29 19:09:06 +02:00
Nguyen Hai
038e2f6984 add python 3.6 unit test job
This is a mechanically generated patch to add a unit test job running
under Python 3.6 as part of the python3-first goal.

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

Change-Id: Ie2624ea979e19abe3feae68d8315c54fd9a9f7ff
Story: #2002586
Task: #24303
2018-08-22 15:08:13 +09:00
Nguyen Hai
334ef1ec33 switch documentation job to new PTI
This is a mechanically generated patch to switch the documentation
jobs to use the new PTI versions of the jobs as part of the
python3-first goal.

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

Change-Id: I4e3d217ba4d67fd227d532ac2ce6a36f36d68815
Story: #2002586
Task: #24303
2018-08-22 15:08:12 +09:00
Nguyen Hai
4455105df5 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

Change-Id: Ic6f174b987bd6a32af097926951bac75cb15f6ea
Story: #2002586
Task: #24303
2018-08-22 15:08:11 +09:00
Doug Hellmann
7aca76b32b fix tox python3 overrides
We want to default to running all tox environments under python 3, so
set the basepython value in each environment.

We do not want to specify a minor version number, because we do not
want to have to update the file every time we upgrade python.

We do not want to set the override once in testenv, because that
breaks the more specific versions used in default environments like
py35 and py36.

Change-Id: I8b2f1a62f8c9ca04d6c63f4a4ad22ec445bad88b
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2018-06-06 17:58:17 -04:00
Zuul
a614c845b2 Merge "Follow the new PTI for document build" 2018-04-21 07:32:13 +00:00
Zuul
8929cad166 Merge "add lower-constraints job" 2018-04-21 07:28:52 +00:00
melissaml
103d4dac05 Trivial: Update pypi url to new url
Pypi url changed from [1] to [2]

[1] https://pypi.python.org/pypi/<package>
[2] https://pypi.org/project/<package>

Change-Id: I7e141db7a05cdfb02dac362b14789c2bee51e184
2018-04-21 06:22:13 +08:00
Doug Hellmann
0fe7b7c087 add lower-constraints job
Create a tox environment for running the unit tests against the lower
bounds of the dependencies.

Create a lower-constraints.txt to be used to enforce the lower bounds
in those tests.

Add openstack-tox-lower-constraints job to the zuul configuration.

See http://lists.openstack.org/pipermail/openstack-dev/2018-March/128352.html
for more details.

Change-Id: I71c76a9173aaa7429b766225f19819715a9ccf64
Depends-On: https://review.openstack.org/555034
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2018-04-20 16:22:33 -04:00
Nguyen Hai
01d1aa0da9 Follow the new PTI for document build
- For compliance with the Project Testing Interface as described in:
https://governance.openstack.org/tc/reference/project-testing-interface.html
http://lists.openstack.org/pipermail/openstack-dev/2017-December/125710.html
- Remove the '[build_sphinx]' as described in:
http://lists.openstack.org/pipermail/openstack-dev/2018-March/128594.html
- This patch also changes minor mistakes in docs.

Change-Id: Iec58d57d59b98c6086910e532e16f1e417815c95
2018-04-12 12:33:29 +09:00
Zuul
71034945a3 Merge "Updated from global requirements" 2018-04-12 02:02:41 +00:00
Zuul
1658f71943 Merge "Update links in README" 2018-04-11 08:18:40 +00:00
OpenStack Proposal Bot
e7e720ca1d Updated from global requirements
Change-Id: I866a1aeb9dbd8c8e1ca502b23c8e4993b232b64e
2018-03-23 01:46:55 +00:00
melissaml
c3b5d573ad Update links in README
Change the outdated links to the latest links in README

Change-Id: If90de4139843539d890948d225eda64a249501b1
2018-03-11 03:04:46 +08:00
Zuul
2dd285549d Merge "Updated from global requirements" 2018-01-31 08:12:23 +00:00
Zuul
c14a1db371 Merge "Change home-page url for karborclient" 2018-01-30 02:06:31 +00:00
Zuul
26d570239d Merge "Add 'rm -f .testrepository/times.dbm' command in testenv" 2018-01-29 01:50:13 +00:00
OpenStack Proposal Bot
63c9890f21 Updated from global requirements
Change-Id: Ib644818e987386a6509ae4884b1dbc0d8418082c
2018-01-27 18:31:25 +00:00
Zuul
86fd679be3 Merge "Updated from global requirements" 2018-01-26 06:17:42 +00:00
OpenStack Proposal Bot
604007cbd3 Updated from global requirements
Change-Id: I21577f0c7cb5c622e13b13cd5e35781391d90319
2018-01-24 02:19:37 +00:00
Yuanbin.Chen
84d19ef13c Delete tox.ini functional when functional test is real.
This patch delete tox.ini functional, the
"/karborclient/tests/functional" is not exist.

Change-Id: I29b40bac7aff8e082e36a1575dc442370911088a
Signed-off-by: Yuanbin.Chen <cybing4@gmail.com>
2018-01-18 23:23:12 +08:00
chenpengzi
4c47bd020f Change home-page url for karborclient
Change-Id: I302b984078cb25b368b4aa5d47bd6f8ea7595d72
2018-01-10 13:03:10 +00:00
OpenStack Proposal Bot
4a5fe7dbc9 Updated from global requirements
Change-Id: I724d191cf50842c274a86bb53841abe28597bc13
2017-12-21 00:43:00 +00:00
Zuul
2d1ac6e744 Merge "Fixed non-ascii in README.txt" 2017-12-19 08:27:56 +00:00
Zuul
f93ac0b598 Merge "Avoid tox_install.sh for constraints support" 2017-12-15 07:32:54 +00:00
Thomas Goirand
194195a97a Fixed non-ascii in README.txt
Running "LANG=C python setup.py install" just fails because of a single
non-ascii char in README.txt. This patch fixes that.

Change-Id: I6840da97cf41891f75afebe06d00e0d3e3849a3d
2017-12-07 22:37:04 +01:00
Zuul
9cf5a90b5c Merge "Updated from global requirements" 2017-12-05 08:11:10 +00:00
OpenStack Proposal Bot
b8726f4bf5 Updated from global requirements
Change-Id: I68301a8bd7c988d507740f4f306642cc4d462d6b
2017-12-05 03:32:01 +00:00
Andreas Jaeger
0b41772728 Avoid tox_install.sh for constraints support
We do not need tox_install.sh, pip can handle constraints itself
and install the project correctly. Thus update tox.ini and remove
the now obsolete tools/tox_install.sh file.

This follows https://review.openstack.org/#/c/508061 to remove
tools/tox_install.sh.

Change-Id: I28ba0904389699268d4b256f76fbfa3a6792eda0
2017-12-02 17:01:28 +00:00
yushangbin
e11f2e8006 Add 'rm -f .testrepository/times.dbm' command in testenv
Running py2* post py3* tests results in error. Add
'rm -f .testrepository/times.dbm' command in testenv to
resolve this.

Closes-Bug: #1565928
Change-Id: I111d82a1509af03aa2e141ee3fd9b2ff9e223215
2017-10-13 08:50:31 +08:00
21 changed files with 435 additions and 88 deletions

10
.zuul.yaml Normal file
View File

@@ -0,0 +1,10 @@
- project:
templates:
- check-requirements
- openstack-cover-jobs
- openstack-lower-constraints-jobs
- openstack-python-jobs
- openstack-python35-jobs
- openstack-python36-jobs
- openstackclient-plugin-jobs
- publish-openstack-docs-pti

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:: https://governance.openstack.org/tc/badges/python-karborclient.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
.. Change things from this point on
@@ -12,17 +12,13 @@ Karbor
======
.. image:: https://img.shields.io/pypi/v/python-karborclient.svg
:target: https://pypi.python.org/pypi/python-karborclient/
:target: https://pypi.org/project/python-karborclient/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/dm/python-karborclient.svg
:target: https://pypi.python.org/pypi/python-karborclient/
:alt: Downloads
Karbor Mission Statement
* Formalize Application Data Protection in OpenStack (APIs, Services, Plugins, )
* Formalize Application Data Protection in OpenStack (APIs, Services, Plugins, ...)
* Be able to protect Any Resource in OpenStack(as well as their dependencies)
* Allow Diversity of vendor solutions, capabilities and implementations
without compromising usability
@@ -35,7 +31,8 @@ Karbor Mission Statement
* `Specs`_
* `How to Contribute`_
.. _PyPi: https://pypi.python.org/pypi/python-karborclient
.. _PyPi: https://pypi.org/project/python-karborclient
.. _Launchpad project: https://launchpad.net/python-karborclient
.. _Blueprints: https://blueprints.launchpad.net/python-karborclient
.. _Bugs: https://bugs.launchpad.net/python-karborclient

5
doc/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
# 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.
sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0

View File

@@ -3,12 +3,12 @@ Contributing
============
General Info
============
------------
.. include:: ../../../CONTRIBUTING.rst
Approved Specs
==============
--------------
.. toctree::
:maxdepth: 1

View File

@@ -1,7 +1,8 @@
Welcome to karborclient's documentation!
========================================================
========================================
Contents:
Contents
--------
.. toctree::
:maxdepth: 1
@@ -12,9 +13,8 @@ Contents:
contributor/index
Indices and tables
==================
------------------
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

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

View File

@@ -1,6 +1,6 @@
========
=====
Usage
========
=====
To use karborclient in a project::

View File

@@ -45,6 +45,12 @@ class ListCheckpoints(command.Lister):
metavar='<provider_id>',
help=_('ID of provider.'),
)
parser.add_argument(
'--all-projects',
action='store_true',
default=False,
help=_('Include all projects (admin only)'),
)
parser.add_argument(
'--plan_id',
metavar='<plan_id>',
@@ -95,12 +101,13 @@ class ListCheckpoints(command.Lister):
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_id) or parsed_args.all_projects
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,
'all_tenants': all_projects
}
data = data_protection_client.checkpoints.list(
@@ -219,3 +226,58 @@ class DeleteCheckpoint(command.Command):
raise exceptions.CommandError(
"Unable to find and delete any of the "
"specified checkpoint.")
class ResetCheckpointState(command.Command):
_description = "Reset checkpoint state"
log = logging.getLogger(__name__ + ".ResetCheckpointState")
def get_parser(self, prog_name):
parser = super(ResetCheckpointState, 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.')
)
parser.add_argument(
'--available',
action='store_const', dest='state',
default='error', const='available',
help=_('Request the checkpoint be reset to "available" state '
'instead of "error" state(the default).'),
)
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.reset_state(
parsed_args.provider_id, checkpoint_id, parsed_args.state)
except exceptions.NotFound:
failure_count += 1
self.log.error(
"Failed to reset state of '{0}'; checkpoint "
"not found".format(checkpoint_id))
except exceptions.Forbidden:
failure_count += 1
self.log.error(
"Failed to reset state of '{0}'; not "
"allowed".format(checkpoint_id))
except exceptions.BadRequest:
failure_count += 1
self.log.error(
"Failed to reset state of '{0}'; invalid input or "
"current checkpoint state".format(checkpoint_id))
if failure_count == len(parsed_args.checkpoint):
raise exceptions.CommandError(
"Unable to find or reset any of the specified "
"checkpoint's state.")

View File

@@ -210,6 +210,11 @@ class UpdatePlan(command.ShowOne):
metavar="<name>",
help=_("A name to which the plan will be renamed.")
)
parser.add_argument(
"--description",
metavar="<description>",
help=_("Description to which the plan will be updated.")
)
parser.add_argument(
"--resources",
metavar="<id=type=name,id=type=name>",
@@ -227,6 +232,8 @@ class UpdatePlan(command.ShowOne):
data = {}
if parsed_args.name is not None:
data['name'] = parsed_args.name
if parsed_args.description is not None:
data['description'] = parsed_args.description
if parsed_args.resources is not None:
plan_resources = utils.extract_resources(parsed_args)
data['resources'] = plan_resources

View File

@@ -39,6 +39,26 @@ CHECKPOINT_INFO = {
),
}
CHECKPOINT_INFO_2 = {
"id": "a6fd95fe-0892-43b2-ad3c-e56f3a1b86b8",
"project_id": "79b35e99a6a541b3bcede40f590d6878",
"status": "available",
"protection_plan": {
"id": "3b47fd5d-21f9-4e63-8409-0acb1bffc038",
"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": json.dumps(
"[{'0x0': ['OS::Glance::Image', "
"'99777fdd-8a5b-45ab-ba2c-52420008103f', "
"'cirros-0.3.4-x86_64-uec']}, [[['0x0']]]]"
),
}
class TestCheckpoints(fakes.TestDataProtection):
def setUp(self):
@@ -51,13 +71,13 @@ class TestCheckpoints(fakes.TestDataProtection):
class TestListCheckpoints(TestCheckpoints):
def setUp(self):
super(TestListCheckpoints, self).setUp()
self.checkpoints_mock.list.return_value = [checkpoints.Checkpoint(
None, copy.deepcopy(CHECKPOINT_INFO))]
# Command to test
self.cmd = osc_checkpoints.ListCheckpoints(self.app, None)
def test_checkpoints_list(self):
self.checkpoints_mock.list.return_value = [checkpoints.Checkpoint(
None, copy.deepcopy(CHECKPOINT_INFO))]
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9')]
@@ -84,6 +104,44 @@ class TestListCheckpoints(TestCheckpoints):
'')]
self.assertEqual(expected_data, list(data))
def test_checkpoints_list_with_all_projects(self):
self.checkpoints_mock.list.return_value = [checkpoints.Checkpoint(
None, copy.deepcopy(CHECKPOINT_INFO)), checkpoints.Checkpoint(
None, copy.deepcopy(CHECKPOINT_INFO_2))]
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9', '--all-projects']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('all_projects', True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
expected_columns = (
['Id', 'Project id', 'Status', 'Protection plan', 'Metadata',
'Created at'])
self.assertEqual(expected_columns, columns)
expected_data = [(
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
"e486a2f49695423ca9c47e589b948108",
"available",
"Name: %(name)s\nId: %(id)s" % {
"id": "3523a271-68aa-42f5-b9ba-56e5200a2ebb",
"name": "My application",
},
'',
''), (
"a6fd95fe-0892-43b2-ad3c-e56f3a1b86b8",
"79b35e99a6a541b3bcede40f590d6878",
"available",
"Name: %(name)s\nId: %(id)s" % {
"id": "3b47fd5d-21f9-4e63-8409-0acb1bffc038",
"name": "My application",
},
'',
'')
]
self.assertEqual(expected_data, list(data))
class TestCreateCheckpoint(TestCheckpoints):
def setUp(self):
@@ -158,3 +216,38 @@ class TestDeleteCheckpoint(TestCheckpoints):
self.checkpoints_mock.delete.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3')
class TestResetCheckpointState(TestCheckpoints):
def setUp(self):
super(TestResetCheckpointState, self).setUp()
self.cmd = osc_checkpoints.ResetCheckpointState(self.app, None)
def test_reset_checkpoint_with_default_state(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']),
('state', 'error')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.checkpoints_mock.reset_state.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3',
'error')
def test_reset_checkpoint(self):
arglist = ['cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3',
'--available']
verifylist = [('provider_id', 'cf56bd3e-97a7-4078-b6d5-f36246333fd9'),
('checkpoint',
['dcb20606-ad71-40a3-80e4-ef0fafdad0c3']),
('state', 'available')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.checkpoints_mock.reset_state.assert_called_once_with(
'cf56bd3e-97a7-4078-b6d5-f36246333fd9',
'dcb20606-ad71-40a3-80e4-ef0fafdad0c3',
'available')

View File

@@ -20,6 +20,7 @@ mock_request_return = ({}, {'checkpoint': {}})
FAKE_PROVIDER_ID = "2220f8b1-975d-4621-a872-fa9afb43cb6c"
FAKE_PLAN_ID = "3330f8b1-975d-4621-a872-fa9afb43cb6c"
FAKE_CHECKPOINT_ID = "e4381b1a-905e-4fec-8104-b4419ccaf963"
class CheckpointsTest(base.TestCaseShell):
@@ -33,6 +34,16 @@ class CheckpointsTest(base.TestCaseShell):
'/providers/{provider_id}/checkpoints'.format(
provider_id=FAKE_PROVIDER_ID), headers={})
@mock.patch('karborclient.common.http.HTTPClient.json_request')
def test_list_checkpoints_with_all_tenants(self, mock_request):
mock_request.return_value = mock_request_return
cs.checkpoints.list(provider_id=FAKE_PROVIDER_ID,
search_opts={'all_tenants': 1})
mock_request.assert_called_with(
'GET',
'/providers/{provider_id}/checkpoints?all_tenants=1'.format(
provider_id=FAKE_PROVIDER_ID), headers={})
@mock.patch('karborclient.common.http.HTTPClient.json_request')
def test_get_checkpoint(self, mock_request):
mock_request.return_value = mock_request_return
@@ -90,3 +101,17 @@ class CheckpointsTest(base.TestCaseShell):
data={
'checkpoint': {'plan_id': FAKE_PLAN_ID, 'extra-info': None}},
headers={})
@mock.patch('karborclient.common.http.HTTPClient.json_request')
def test_reset_checkpoint_state(self, mock_request):
mock_request.return_value = ({}, {})
cs.checkpoints.reset_state(
FAKE_PROVIDER_ID, FAKE_CHECKPOINT_ID, 'error')
mock_request.assert_called_with(
'PUT',
'/providers/{provider_id}/checkpoints/{checkpoint_id}'.format(
provider_id=FAKE_PROVIDER_ID,
checkpoint_id=FAKE_CHECKPOINT_ID
),
data={'os-resetState': {'state': 'error'}},
headers={})

View File

@@ -12,6 +12,7 @@
import mock
from karborclient.common.apiclient import exceptions
from karborclient.tests.unit import base
from karborclient.tests.unit.v1 import fakes
@@ -46,16 +47,21 @@ class TriggersTest(base.TestCaseShell):
@mock.patch('karborclient.common.http.HTTPClient.json_request')
def test_create_trigger(self, mock_request):
mock_request.return_value = mock_request_return
cs.triggers.create('name', 'time', 'properties')
cs.triggers.create('name', 'time', {})
mock_request.assert_called_with(
'POST',
'/triggers',
data={
'trigger_info': {'name': 'name',
'type': 'time',
'properties': 'properties'}},
'properties': {}}},
headers={})
def test_create_trigger_with_invalid_window(self):
self.assertRaises(exceptions.CommandError,
cs.triggers.create,
'name', 'time', {'window': 'fake'})
@mock.patch('karborclient.common.http.HTTPClient.raw_request')
def test_delete_trigger(self, mock_request):
mock_request.return_value = mock_request_return

View File

@@ -43,6 +43,15 @@ class CheckpointManager(base.ManagerWithFind):
"checkpoints" .format(provider_id=provider_id)
return self._create(url, body, 'checkpoint')
def reset_state(self, provider_id, checkpoint_id, state):
body = {'os-resetState': {'state': state}}
return self.update(provider_id, checkpoint_id, body)
def update(self, provider_id, checkpoint_id, values):
url = '/providers/{provider_id}/checkpoints/{checkpoint_id}'.format(
provider_id=provider_id, checkpoint_id=checkpoint_id)
return self._update(url, values)
def delete(self, provider_id, checkpoint_id):
path = '/providers/{provider_id}/checkpoints/' \
'{checkpoint_id}'.format(provider_id=provider_id,

View File

@@ -188,6 +188,8 @@ def do_plan_delete(cs, args):
help="Id of plan to update.")
@utils.arg("--name", metavar="<name>",
help="A name to which the plan will be renamed.")
@utils.arg("--description", metavar="<description>",
help="Description to which the plan will be updated.")
@utils.arg("--resources", metavar="<id=type=name,id=type=name>",
help="Resources to which the plan will be updated.")
@utils.arg("--status", metavar="<suspended|started>",
@@ -197,6 +199,8 @@ def do_plan_update(cs, args):
data = {}
if args.name is not None:
data['name'] = args.name
if args.description is not None:
data['description'] = args.description
if args.resources is not None:
plan_resources = arg_utils.extract_resources(args)
data['resources'] = plan_resources
@@ -712,6 +716,19 @@ def do_checkpoint_create(cs, args):
json_format_list=json_format_list)
@utils.arg('--all-tenants',
dest='all_tenants',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help='Shows details for all tenants. Admin only.')
@utils.arg('--all_tenants',
nargs='?',
type=int,
const=1,
help=argparse.SUPPRESS)
@utils.arg('provider_id',
metavar='<provider_id>',
help='ID of provider.')
@@ -785,6 +802,7 @@ def do_checkpoint_list(cs, args):
'start_date': args.start_date,
'end_date': args.end_date,
'project_id': args.project_id,
'all_tenants': args.all_tenants
}
if args.sort and (args.sort_key or args.sort_dir):
@@ -852,6 +870,45 @@ def do_checkpoint_delete(cs, args):
"specified checkpoint.")
@utils.arg('provider_id',
metavar='<provider_id>',
help='Id of provider.')
@utils.arg('checkpoint',
metavar='<checkpoint>',
nargs="+",
help='ID of checkpoint.')
@utils.arg('--available',
action='store_const',
dest='state',
default='error',
const='available',
help='Request the checkpoint be reset to "available" state instead '
'of "error" state(the default).')
def do_checkpoint_reset_state(cs, args):
"""Reset state of a checkpoint."""
failure_count = 0
for checkpoint_id in args.checkpoint:
try:
cs.checkpoints.reset_state(args.provider_id, checkpoint_id,
args.state)
except exceptions.NotFound:
failure_count += 1
print("Failed to reset state of '{0}'; checkpoint not found".
format(checkpoint_id))
except exceptions.Forbidden:
failure_count += 1
print("Failed to reset state of '{0}'; not allowed".
format(checkpoint_id))
except exceptions.BadRequest:
failure_count += 1
print("Failed to reset state of '{0}'; invalid input or "
"current checkpoint state".format(checkpoint_id))
if failure_count == len(args.checkpoint):
raise exceptions.CommandError("Unable to find or reset any of the "
"specified checkpoint's state.")
@utils.arg('--all-tenants',
dest='all_tenants',
metavar='<0|1>',
@@ -970,7 +1027,8 @@ def do_trigger_update(cs, args):
"""Update a trigger."""
trigger_info = {}
trigger_properties = arg_utils.extract_properties(args)
trigger_info['name'] = args.name
if args.name:
trigger_info['name'] = args.name
trigger_info['properties'] = trigger_properties
trigger = cs.triggers.update(args.trigger_id, trigger_info)
dict_format_list = {"properties"}
@@ -1106,7 +1164,9 @@ def do_scheduledoperation_list(cs, args):
help='Trigger name.')
@utils.arg('operation_type',
metavar='<operation_type>',
help='Operation Type of scheduled operation.')
choices=['protect', 'retention_protect'],
help='Operation Type of scheduled operation. Valid values are '
'"protect" or "retention_protect."')
@utils.arg('trigger_id',
metavar='<trigger_id>',
help='Trigger id of scheduled operation.')

View File

@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from karborclient.common.apiclient import exceptions
from karborclient.common import base
@@ -22,6 +23,12 @@ class TriggerManager(base.ManagerWithFind):
resource_class = Trigger
def create(self, name, type, properties):
if properties.get('window', None):
try:
properties['window'] = int(properties['window'])
except Exception:
msg = 'The trigger window is not integer'
raise exceptions.CommandError(msg)
body = {'trigger_info': {'name': name,
'type': type,
'properties': properties,
@@ -45,8 +52,14 @@ class TriggerManager(base.ManagerWithFind):
def update(self, trigger_id, data):
if data['properties'].get('window', None):
try:
data['properties']['window'] = int(
data['properties']['window'])
except Exception:
msg = 'The trigger window is not integer'
raise exceptions.CommandError(msg)
body = {"trigger_info": data}
return self._update('/triggers/{trigger_id}'
.format(trigger_id=trigger_id),
body, "trigger_info")

88
lower-constraints.txt Normal file
View File

@@ -0,0 +1,88 @@
alabaster==0.7.10
appdirs==1.3.0
asn1crypto==0.23.0
Babel==2.3.4
cffi==1.7.0
cliff==2.8.0
cmd2==0.8.0
coverage==4.0
cryptography==2.1
debtcollector==1.2.0
decorator==3.4.0
deprecation==1.0
docutils==0.11
dogpile.cache==0.6.2
dulwich==0.15.0
extras==1.0.0
fixtures==3.0.0
flake8==2.5.5
hacking==0.12.0
idna==2.6
imagesize==0.7.1
iso8601==0.1.11
Jinja2==2.10
jmespath==0.9.0
jsonpatch==1.16
jsonpointer==1.13
jsonschema==2.6.0
keystoneauth1==3.4.0
linecache2==1.0.0
MarkupSafe==1.0
mccabe==0.2.1
mock==2.0.0
monotonic==0.6
mox3==0.20.0
msgpack-python==0.4.0
munch==2.1.0
netaddr==0.7.18
netifaces==0.10.4
openstackdocstheme==1.18.1
openstacksdk==0.11.2
os-client-config==1.28.0
os-service-types==1.2.0
osc-lib==1.8.0
oslo.config==5.2.0
oslo.context==2.19.2
oslo.i18n==3.15.3
oslo.log==3.36.0
oslo.serialization==2.18.0
oslo.utils==3.33.0
oslotest==3.2.0
pbr==2.0.0
pep8==1.5.7
positional==1.2.1
prettytable==0.7.1
pycparser==2.18
pyflakes==0.8.1
Pygments==2.2.0
pyinotify==0.9.6
pyOpenSSL==17.1.0
pyparsing==2.1.0
pyperclip==1.5.27
python-cinderclient==3.3.0
python-dateutil==2.5.3
python-glanceclient==2.8.0
python-keystoneclient==3.8.0
python-mimeparse==1.6.0
python-novaclient==9.1.0
python-openstackclient==3.12.0
python-subunit==1.0.0
pytz==2013.6
PyYAML==3.12
requests-mock==1.2.0
requests==2.14.2
requestsexceptions==1.2.0
rfc3986==0.3.1
simplejson==3.5.1
six==1.10.0
snowballstemmer==1.2.1
Sphinx==1.6.2
sphinxcontrib-websupport==1.0.1
stevedore==1.20.0
testrepository==0.0.18
testscenarios==0.4
testtools==2.2.0
traceback2==1.4.0
unittest2==1.1.0
warlock==1.2.0
wrapt==1.7.0

View File

@@ -3,12 +3,12 @@
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
keystoneauth1>=3.2.0 # Apache-2.0
keystoneauth1>=3.4.0 # Apache-2.0
requests>=2.14.2 # Apache-2.0
simplejson>=3.5.1 # MIT
Babel!=2.4.0,>=2.3.4 # BSD
six>=1.10.0 # MIT
osc-lib>=1.7.0 # Apache-2.0
oslo.utils>=3.31.0 # Apache-2.0
oslo.log>=3.30.0 # Apache-2.0
osc-lib>=1.8.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0

View File

@@ -4,8 +4,8 @@ summary = Python client library for Karbor API
description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = https://docs.openstack.org/karbor/latest
author-email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/python-karborclient/latest/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -17,6 +17,7 @@ classifier =
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
[global]
setup-hooks =
@@ -57,6 +58,7 @@ openstack.data_protection.v1 =
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_checkpoint_reset_state = karborclient.osc.v1.checkpoints:ResetCheckpointState
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
@@ -89,14 +91,5 @@ 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
all_files = 1
warning-is-error = 1
[upload_sphinx]
upload-dir = doc/build/html
[wheel]
universal = 1

View File

@@ -7,11 +7,9 @@ hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
docutils>=0.11 # OSI-Approved Open Source, Public Domain
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.17.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
python-openstackclient>=3.12.0 # Apache-2.0
requests-mock>=1.1.0 # Apache-2.0
requests-mock>=1.2.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=2.2.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 $?

35
tox.ini
View File

@@ -5,41 +5,52 @@ 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}
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = python setup.py test --slowest --testr-args='{posargs}'
whitelist_externals = rm
commands =
rm -f .testrepository/times.dbm
python setup.py test --slowest --testr-args='{posargs}'
[testenv:pep8]
basepython = python3
commands = flake8
[testenv:venv]
basepython = python3
commands = {posargs}
[testenv:functional]
setenv =
{[testenv]setenv}
OS_TEST_PATH = ./karborclient/tests/functional
passenv = OS_*
[testenv:cover]
basepython = python3
commands =
python setup.py test --coverage --testr-args='{posargs}'
coverage report
[testenv:docs]
commands = python setup.py build_sphinx
basepython = python3
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -W -b html doc/source doc/build/html
[testenv:debug]
basepython = python3
commands = oslo_debug_helper -t karborclient/tests {posargs}
[flake8]
show-source = True
ignore =
ignore =
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools
[testenv:lower-constraints]
basepython = python3
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt