Compare commits
41 Commits
rocky-eol
...
ussuri-eol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ded5189ba | ||
|
|
1419988ace | ||
|
|
21addfcca0 | ||
|
|
56681c318e | ||
|
|
5bd1b2feeb | ||
|
|
05139e97e8 | ||
|
|
c4e27f2e6d | ||
|
|
1a98ae3101 | ||
|
|
4571dcb492 | ||
|
|
9cd38596cd | ||
|
|
17f75a9c00 | ||
|
|
6a5f46615c | ||
|
|
036ec8746a | ||
|
|
56474b54df | ||
|
|
998e72a03a | ||
|
|
7d93f625d9 | ||
|
|
3216f64d14 | ||
|
|
e5440f809d | ||
|
|
d45538cf41 | ||
|
|
ce7b872c26 | ||
|
|
a0a7b4a24b | ||
|
|
c2e7441444 | ||
|
|
5cf1f0d246 | ||
|
|
c992876f96 | ||
|
|
bc9ac570bf | ||
|
|
048b3a0bd9 | ||
|
|
58234ab51c | ||
|
|
1eb26df991 | ||
|
|
47d15a74a3 | ||
|
|
597e452dbc | ||
|
|
262799e3c0 | ||
|
|
f3c117e17c | ||
|
|
e3ed8939b8 | ||
|
|
38b2b847c8 | ||
|
|
2fe9422e04 | ||
|
|
b0011487e2 | ||
|
|
db689c650f | ||
|
|
1c2079ef71 | ||
|
|
038e2f6984 | ||
|
|
334ef1ec33 | ||
|
|
4455105df5 |
@@ -2,4 +2,3 @@
|
||||
host=review.opendev.org
|
||||
port=29418
|
||||
project=openstack/python-karborclient.git
|
||||
defaultbranch=stable/rocky
|
||||
|
||||
16
.zuul.yaml
16
.zuul.yaml
@@ -1,16 +1,8 @@
|
||||
- project:
|
||||
templates:
|
||||
- openstack-python-jobs
|
||||
- openstack-python35-jobs
|
||||
- check-requirements
|
||||
- publish-openstack-sphinx-docs
|
||||
- openstack-cover-jobs
|
||||
- openstack-lower-constraints-jobs
|
||||
- openstack-python3-ussuri-jobs
|
||||
- openstackclient-plugin-jobs
|
||||
check:
|
||||
jobs:
|
||||
- openstack-tox-lower-constraints
|
||||
- openstack-tox-cover:
|
||||
voting: false
|
||||
|
||||
gate:
|
||||
jobs:
|
||||
- openstack-tox-lower-constraints
|
||||
- publish-openstack-docs-pti
|
||||
|
||||
@@ -15,10 +15,6 @@ Karbor
|
||||
:target: https://pypi.org/project/python-karborclient/
|
||||
:alt: Latest Version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-karborclient.svg
|
||||
:target: https://pypi.org/project/python-karborclient/
|
||||
:alt: Downloads
|
||||
|
||||
|
||||
Karbor Mission Statement
|
||||
|
||||
@@ -40,7 +36,7 @@ Karbor Mission Statement
|
||||
.. _Launchpad project: https://launchpad.net/python-karborclient
|
||||
.. _Blueprints: https://blueprints.launchpad.net/python-karborclient
|
||||
.. _Bugs: https://bugs.launchpad.net/python-karborclient
|
||||
.. _Source: https://git.openstack.org/cgit/openstack/python-karborclient
|
||||
.. _Source: https://opendev.org/openstack/python-karborclient
|
||||
.. _Specs: https://docs.openstack.org/karbor/latest/specs/index.html
|
||||
.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
|
||||
@@ -25,14 +25,10 @@ OpenStack Client interface. Handles the REST calls and responses.
|
||||
# E0202: An attribute inherited from %s hide this method
|
||||
# pylint: disable=E0202
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import importutils
|
||||
import requests
|
||||
|
||||
@@ -132,7 +128,7 @@ class HTTPClient(object):
|
||||
def serialize(self, kwargs):
|
||||
if kwargs.get('json') is not None:
|
||||
kwargs['headers']['Content-Type'] = 'application/json'
|
||||
kwargs['data'] = json.dumps(kwargs['json'])
|
||||
kwargs['data'] = jsonutils.dumps(kwargs['json'])
|
||||
try:
|
||||
del kwargs['json']
|
||||
except KeyError:
|
||||
|
||||
@@ -24,7 +24,7 @@ places where actual behavior differs from the spec.
|
||||
# W0102: Dangerous default value %s as argument
|
||||
# pylint: disable=W0102
|
||||
|
||||
import json
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
import requests
|
||||
import six
|
||||
@@ -58,7 +58,7 @@ class TestResponse(requests.Response):
|
||||
# Fake the text attribute to streamline Response creation
|
||||
text = data.get('text', "")
|
||||
if isinstance(text, (dict, list)):
|
||||
self._content = json.dumps(text)
|
||||
self._content = jsonutils.dumps(text)
|
||||
default_headers = {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
import six
|
||||
import uuid
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import encodeutils
|
||||
|
||||
import prettytable
|
||||
@@ -138,7 +138,7 @@ def dict_prettyprint(val):
|
||||
:param val: dict.
|
||||
:return: formatted json string.
|
||||
"""
|
||||
return json.dumps(val, indent=2, sort_keys=True)
|
||||
return jsonutils.dumps(val, indent=2, sort_keys=True)
|
||||
|
||||
|
||||
def json_prettyprint(val):
|
||||
@@ -147,7 +147,8 @@ def json_prettyprint(val):
|
||||
:param val: json string.
|
||||
:return: formatted json string.
|
||||
"""
|
||||
return val and json.dumps(json.loads(val), indent=2, sort_keys=True)
|
||||
return val and jsonutils.dumps(jsonutils.loads(val),
|
||||
indent=2, sort_keys=True)
|
||||
|
||||
|
||||
def find_resource(manager, name_or_id, *args, **kwargs):
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
|
||||
"""Data protection V1 checkpoint action implementations"""
|
||||
|
||||
import json
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as osc_utils
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.common.apiclient import exceptions
|
||||
from karborclient.i18n import _
|
||||
@@ -28,7 +28,7 @@ def format_checkpoint(checkpoint_info):
|
||||
checkpoint_info['protection_plan'] = "Name: %s\nId: %s" % (
|
||||
plan['name'], plan['id'])
|
||||
if 'resource_graph' in checkpoint_info:
|
||||
checkpoint_info['resource_graph'] = json.dumps(json.loads(
|
||||
checkpoint_info['resource_graph'] = jsonutils.dumps(jsonutils.loads(
|
||||
checkpoint_info['resource_graph']), indent=2, sort_keys=True)
|
||||
checkpoint_info.pop("links", None)
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
"""Data protection V1 plan action implementations"""
|
||||
|
||||
import json
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from osc_lib.command import command
|
||||
@@ -28,7 +28,8 @@ def format_plan(plan_info):
|
||||
for key in ('resources', 'parameters'):
|
||||
if key not in plan_info:
|
||||
continue
|
||||
plan_info[key] = json.dumps(plan_info[key], indent=2, sort_keys=True)
|
||||
plan_info[key] = jsonutils.dumps(plan_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
plan_info.pop("links", None)
|
||||
|
||||
|
||||
@@ -210,6 +211,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 +233,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
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
"""Data protection V1 protectables action implementations"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as osc_utils
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.i18n import _
|
||||
from karborclient import utils
|
||||
@@ -136,7 +136,8 @@ class ListProtectableInstances(command.Lister):
|
||||
column_headers = ['Id', 'Type', 'Name', 'Dependent resources',
|
||||
'Extra info']
|
||||
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2, sort_keys=True)
|
||||
formatters = {
|
||||
"Extra info": json_dumps,
|
||||
"Dependent resources": json_dumps,
|
||||
@@ -186,7 +187,8 @@ class ShowProtectableInstance(command.ShowOne):
|
||||
parsed_args.protectable_id,
|
||||
search_opts=search_opts)
|
||||
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2, sort_keys=True)
|
||||
instance._info.pop("links", None)
|
||||
for key in ('extra_info', 'dependent_resources'):
|
||||
if key not in instance._info:
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
"""Data protection V1 provider action implementations"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as osc_utils
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.i18n import _
|
||||
|
||||
@@ -96,7 +96,8 @@ class ShowProvider(command.ShowOne):
|
||||
client = self.app.client_manager.data_protection
|
||||
provider = osc_utils.find_resource(client.providers,
|
||||
parsed_args.provider)
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2, sort_keys=True)
|
||||
provider._info.pop("links", None)
|
||||
if 'extended_info_schema' in provider._info:
|
||||
provider._info['extended_info_schema'] = json_dumps(
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
"""Data protection V1 restore action implementations"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from osc_lib.command import command
|
||||
@@ -31,8 +31,8 @@ def format_restore(restore_info):
|
||||
'resources_reason'):
|
||||
if key not in restore_info:
|
||||
continue
|
||||
restore_info[key] = json.dumps(restore_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
restore_info[key] = jsonutils.dumps(restore_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
restore_info.pop("links", None)
|
||||
|
||||
|
||||
@@ -98,7 +98,9 @@ class ListRestores(command.Lister):
|
||||
column_headers = ['Id', 'Project id', 'Provider id', 'Checkpoint id',
|
||||
'Restore target', 'Parameters', 'Status']
|
||||
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2,
|
||||
sort_keys=True)
|
||||
formatters = {
|
||||
"Parameters": json_dumps,
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
"""Data protection V1 scheduled_operations action implementations"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
import six
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from osc_lib.command import command
|
||||
@@ -30,8 +30,8 @@ def format_scheduledoperation(scheduledoperation_info):
|
||||
for key in ('operation_definition', ):
|
||||
if key not in scheduledoperation_info:
|
||||
continue
|
||||
scheduledoperation_info[key] = json.dumps(scheduledoperation_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
scheduledoperation_info[key] = jsonutils.dumps(
|
||||
scheduledoperation_info[key], indent=2, sort_keys=True)
|
||||
scheduledoperation_info.pop("links", None)
|
||||
|
||||
|
||||
@@ -118,7 +118,9 @@ class ListScheduledOperations(command.Lister):
|
||||
column_headers = ['Id', 'Name', 'Operation Type', 'Trigger Id',
|
||||
'Operation Definition']
|
||||
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2,
|
||||
sort_keys=True)
|
||||
formatters = {
|
||||
"Operation Definition": json_dumps,
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
"""Data protection V1 verification action implementations"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
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 _
|
||||
@@ -31,8 +31,8 @@ def format_verification(verification_info):
|
||||
'resources_reason'):
|
||||
if key not in verification_info:
|
||||
continue
|
||||
verification_info[key] = json.dumps(verification_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
verification_info[key] = jsonutils.dumps(verification_info[key],
|
||||
indent=2, sort_keys=True)
|
||||
verification_info.pop("links", None)
|
||||
|
||||
|
||||
@@ -98,7 +98,9 @@ class ListVerifications(command.Lister):
|
||||
column_headers = ['Id', 'Project id', 'Provider id', 'Checkpoint id',
|
||||
'Parameters', 'Status']
|
||||
|
||||
json_dumps = functools.partial(json.dumps, indent=2, sort_keys=True)
|
||||
json_dumps = functools.partial(jsonutils.dumps,
|
||||
indent=2,
|
||||
sort_keys=True)
|
||||
formatters = {
|
||||
"Parameters": json_dumps,
|
||||
}
|
||||
|
||||
@@ -400,9 +400,9 @@ class KarborShell(object):
|
||||
if args.api_timeout:
|
||||
kwargs['timeout'] = args.api_timeout
|
||||
|
||||
client = karbor_client.Client(api_version, endpoint, **kwargs)
|
||||
self.cs = karbor_client.Client(api_version, endpoint, **kwargs)
|
||||
|
||||
args.func(client, args)
|
||||
args.func(self.cs, args)
|
||||
|
||||
def do_bash_completion(self, args):
|
||||
"""Prints all of the commands and options to stdout."""
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.osc.v1 import checkpoints as osc_checkpoints
|
||||
from karborclient.tests.unit.osc.v1 import fakes
|
||||
@@ -32,7 +33,27 @@ CHECKPOINT_INFO = {
|
||||
"type": "OS::Glance::Image",
|
||||
"name": "cirros-0.3.4-x86_64-uec"}]
|
||||
},
|
||||
"resource_graph": json.dumps(
|
||||
"resource_graph": jsonutils.dumps(
|
||||
"[{'0x0': ['OS::Glance::Image', "
|
||||
"'99777fdd-8a5b-45ab-ba2c-52420008103f', "
|
||||
"'cirros-0.3.4-x86_64-uec']}, [[['0x0']]]]"
|
||||
),
|
||||
}
|
||||
|
||||
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": jsonutils.dumps(
|
||||
"[{'0x0': ['OS::Glance::Image', "
|
||||
"'99777fdd-8a5b-45ab-ba2c-52420008103f', "
|
||||
"'cirros-0.3.4-x86_64-uec']}, [[['0x0']]]]"
|
||||
@@ -51,13 +72,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 +105,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 +217,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')
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.osc.v1 import restores as osc_restores
|
||||
from karborclient.tests.unit.osc.v1 import fakes
|
||||
@@ -69,7 +70,7 @@ class TestListRestores(TestRestores):
|
||||
"cf56bd3e-97a7-4078-b6d5-f36246333fd9",
|
||||
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
|
||||
"",
|
||||
json.dumps({}),
|
||||
jsonutils.dumps({}),
|
||||
"success")]
|
||||
self.assertEqual(expected_data, list(data))
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from karborclient.osc.v1 import verifications as osc_verifications
|
||||
from karborclient.tests.unit.osc.v1 import fakes
|
||||
@@ -67,7 +68,7 @@ class TestListVerifications(TestVerifications):
|
||||
"e486a2f49695423ca9c47e589b948108",
|
||||
"cf56bd3e-97a7-4078-b6d5-f36246333fd9",
|
||||
"dcb20606-ad71-40a3-80e4-ef0fafdad0c3",
|
||||
json.dumps({}),
|
||||
jsonutils.dumps({}),
|
||||
"success")]
|
||||
self.assertEqual(expected_data, list(data))
|
||||
|
||||
|
||||
@@ -37,12 +37,13 @@ class FakeClient(fakes.FakeClient, client.Client):
|
||||
'project_id': PROJECT_ID,
|
||||
}
|
||||
client.Client.__init__(self, 'http://endpoint', **kwargs)
|
||||
self.client = FakeHTTPClient(**kwargs)
|
||||
self.client = self.http_client
|
||||
|
||||
|
||||
class FakeHTTPClient(base_client.HTTPClient):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, endpoint, **kwargs):
|
||||
super(FakeHTTPClient, self)
|
||||
self.username = 'username'
|
||||
self.password = 'password'
|
||||
self.auth_url = 'auth_url'
|
||||
@@ -50,6 +51,9 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
self.management_url = 'http://10.0.2.15:8776/v1/fake'
|
||||
self.osapi_max_limit = 1000
|
||||
self.marker = None
|
||||
self.project_id = 'project_id'
|
||||
self.auth_token = 'auth_token'
|
||||
self.region_name = 'region_name'
|
||||
|
||||
def _cs_request(self, url, method, **kwargs):
|
||||
# Check that certain things are called correctly
|
||||
@@ -92,3 +96,27 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
"headers": headers,
|
||||
})
|
||||
return r, body
|
||||
|
||||
def json_request(self, method, url, **kwargs):
|
||||
return self._cs_request(url, method, **kwargs)
|
||||
|
||||
def get_providers_1234_checkpoints(self, **kwargs):
|
||||
return 200, {}, {"checkpoints": []}
|
||||
|
||||
def get_plans(self, **kwargs):
|
||||
return 200, {}, {"plans": []}
|
||||
|
||||
def get_operation_logs(self, **kwargs):
|
||||
return 200, {}, {"operation_logs": []}
|
||||
|
||||
def get_restores(self, **kwargs):
|
||||
return 200, {}, {"restores": []}
|
||||
|
||||
def get_scheduled_operations(self, **kwargs):
|
||||
return 200, {}, {"operations": []}
|
||||
|
||||
def get_triggers(self, **kwargs):
|
||||
return 200, {}, {"triggers": []}
|
||||
|
||||
def get_verifications(self, **kwargs):
|
||||
return 200, {}, {"verifications": []}
|
||||
|
||||
@@ -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={})
|
||||
|
||||
@@ -21,6 +21,22 @@ mock_request_return = ({}, {'operation_log': {}})
|
||||
|
||||
class OperationLogsTest(base.TestCaseShell):
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.list()
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs_with_all_tenants(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.operation_logs.list(search_opts={'all_tenants': 1})
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/operation_logs?all_tenants=1', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_operation_logs_with_marker_limit(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
|
||||
@@ -30,6 +30,15 @@ class QuotaClassesTest(base.TestCaseShell):
|
||||
'/quota_classes/default',
|
||||
data={'quota_class': {'plans': 50}}, headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_quota_class_update_with_none(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.quota_classes.update('default', {'plans': None})
|
||||
mock_request.assert_called_with(
|
||||
'PUT',
|
||||
'/quota_classes/default',
|
||||
data={'quota_class': {'plans': 50}}, headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota_class(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
@@ -38,3 +47,12 @@ class QuotaClassesTest(base.TestCaseShell):
|
||||
'GET',
|
||||
'/quota_classes/default',
|
||||
headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota_class_with_headers(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.quota_classes.get('default', session_id='fake_session_id')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/quota_classes/default',
|
||||
headers={'X-Configuration-Session': 'fake_session_id'})
|
||||
|
||||
@@ -30,6 +30,15 @@ class QuotasTest(base.TestCaseShell):
|
||||
'/quotas/{project_id}'.format(project_id=fakes.PROJECT_ID),
|
||||
data={'quota': {'plans': 50}}, headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_quota_update_with_none(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.quotas.update(fakes.PROJECT_ID, {'plans': None})
|
||||
mock_request.assert_called_with(
|
||||
'PUT',
|
||||
'/quotas/{project_id}'.format(project_id=fakes.PROJECT_ID),
|
||||
data={'quota': {'plans': 50}}, headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
@@ -39,6 +48,15 @@ class QuotasTest(base.TestCaseShell):
|
||||
'/quotas/{project_id}'.format(project_id=fakes.PROJECT_ID),
|
||||
headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota_with_headers(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.quotas.get(fakes.PROJECT_ID, False, session_id='fake_session_id')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/quotas/{project_id}'.format(project_id=fakes.PROJECT_ID),
|
||||
headers={'X-Configuration-Session': 'fake_session_id'})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota_with_detail(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
@@ -58,3 +76,13 @@ class QuotasTest(base.TestCaseShell):
|
||||
'/quotas/{project_id}/defaults'.format(
|
||||
project_id=fakes.PROJECT_ID),
|
||||
headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_show_quota_default_with_headers(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.quotas.defaults(fakes.PROJECT_ID, session_id='fake_session_id')
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/quotas/{project_id}/defaults'.format(
|
||||
project_id=fakes.PROJECT_ID),
|
||||
headers={'X-Configuration-Session': 'fake_session_id'})
|
||||
|
||||
137
karborclient/tests/unit/v1/test_shell.py
Normal file
137
karborclient/tests/unit/v1/test_shell.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# 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 fixtures
|
||||
import mock
|
||||
|
||||
from karborclient import shell
|
||||
from karborclient.tests.unit import base
|
||||
from karborclient.tests.unit.v1 import fakes
|
||||
|
||||
FAKE_PROVIDER_ID = '1234'
|
||||
FAKE_ENDPOINT = 'http://127.0.0.1/identity'
|
||||
|
||||
|
||||
class ShellFixture(fixtures.Fixture):
|
||||
def setUp(self):
|
||||
super(ShellFixture, self).setUp()
|
||||
self.shell = shell.KarborShell()
|
||||
|
||||
def tearDown(self):
|
||||
# For some method like test_image_meta_bad_action we are
|
||||
# testing a SystemExit to be thrown and object self.shell has
|
||||
# no time to get instantiated which is OK in this case, so
|
||||
# we make sure the method is there before launching it.
|
||||
if hasattr(self.shell, 'cs'):
|
||||
self.shell.cs.clear_callstack()
|
||||
super(ShellFixture, self).tearDown()
|
||||
|
||||
|
||||
class ShellTest(base.TestCaseShell):
|
||||
|
||||
FAKE_ENV = {
|
||||
'OS_USERNAME': 'username',
|
||||
'OS_PASSWORD': 'password',
|
||||
'OS_TENANT_NAME': 'project_id',
|
||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
||||
'OS_AUTH_TOKEN': 'fake_token'
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test."""
|
||||
super(ShellTest, self).setUp()
|
||||
for var in self.FAKE_ENV:
|
||||
self.useFixture(fixtures.EnvironmentVariable(
|
||||
var, self.FAKE_ENV[var]))
|
||||
self.shell = self.useFixture(ShellFixture()).shell
|
||||
|
||||
get_endpoint = mock.MagicMock()
|
||||
get_endpoint.return_value = FAKE_ENDPOINT
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'keystoneauth1.identity.generic.token.Token.get_endpoint',
|
||||
get_endpoint))
|
||||
self.useFixture(fixtures.MonkeyPatch('karborclient.client.Client',
|
||||
fakes.FakeClient))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'karborclient.common.http._construct_http_client',
|
||||
fakes.FakeHTTPClient))
|
||||
|
||||
def run_command(self, cmd):
|
||||
if not isinstance(cmd, list):
|
||||
cmd = cmd.split()
|
||||
self.shell.main(cmd)
|
||||
|
||||
def assert_called(self, method, url, body=None, **kwargs):
|
||||
return self.shell.cs.assert_called(method, url, body, **kwargs)
|
||||
|
||||
def test_checkpoint_list_with_all_tenants(self):
|
||||
self.run_command(
|
||||
'checkpoint-list ' + FAKE_PROVIDER_ID + ' --all-tenants 1')
|
||||
|
||||
self.assert_called('GET',
|
||||
'/providers/1234/'
|
||||
'checkpoints?all_tenants=1')
|
||||
|
||||
def test_checkpoint_list_with_all(self):
|
||||
self.run_command(
|
||||
'checkpoint-list ' + FAKE_PROVIDER_ID + ' --all')
|
||||
self.assert_called('GET',
|
||||
'/providers/1234/'
|
||||
'checkpoints?all_tenants=1')
|
||||
|
||||
def test_plan_list_with_all_tenants(self):
|
||||
self.run_command('plan-list --all-tenants 1')
|
||||
self.assert_called('GET', '/plans?all_tenants=1')
|
||||
|
||||
def test_plan_list_with_all(self):
|
||||
self.run_command('plan-list --all')
|
||||
self.assert_called('GET', '/plans?all_tenants=1')
|
||||
|
||||
def test_resotre_list_with_all_tenants(self):
|
||||
self.run_command('restore-list --all-tenants 1')
|
||||
self.assert_called('GET', '/restores?all_tenants=1')
|
||||
|
||||
def test_resotre_list_with_all(self):
|
||||
self.run_command('restore-list --all')
|
||||
self.assert_called('GET', '/restores?all_tenants=1')
|
||||
|
||||
def test_verification_list_with_all_tenants(self):
|
||||
self.run_command('verification-list --all-tenants 1')
|
||||
self.assert_called('GET', '/verifications?all_tenants=1')
|
||||
|
||||
def test_verification_list_with_all(self):
|
||||
self.run_command('verification-list --all')
|
||||
self.assert_called('GET', '/verifications?all_tenants=1')
|
||||
|
||||
def test_trigger_list_with_all_tenants(self):
|
||||
self.run_command('trigger-list --all-tenants 1')
|
||||
self.assert_called('GET', '/triggers?all_tenants=1')
|
||||
|
||||
def test_trigger_list_with_all(self):
|
||||
self.run_command('trigger-list --all')
|
||||
self.assert_called('GET', '/triggers?all_tenants=1')
|
||||
|
||||
def test_scheduledoperation_list_with_all_tenants(self):
|
||||
self.run_command('scheduledoperation-list --all-tenants 1')
|
||||
self.assert_called('GET', '/scheduled_operations?all_tenants=1')
|
||||
|
||||
def test_scheduledoperation_list_with_all(self):
|
||||
self.run_command('scheduledoperation-list --all')
|
||||
self.assert_called('GET', '/scheduled_operations?all_tenants=1')
|
||||
|
||||
def test_operationlog_list_with_all_tenants(self):
|
||||
self.run_command('operationlog-list --all-tenants 1')
|
||||
self.assert_called('GET', '/operation_logs?all_tenants=1')
|
||||
|
||||
def test_operationlog_list_with_all(self):
|
||||
self.run_command('operationlog-list --all')
|
||||
self.assert_called('GET', '/operation_logs?all_tenants=1')
|
||||
@@ -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
|
||||
|
||||
@@ -21,6 +22,22 @@ mock_request_return = ({}, {'trigger_info': {'name': 'fake_name'}})
|
||||
|
||||
class TriggersTest(base.TestCaseShell):
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_triggers(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.triggers.list()
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/triggers', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_triggers_with_all_tenants(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
cs.triggers.list(search_opts={'all_tenants': 1})
|
||||
mock_request.assert_called_with(
|
||||
'GET',
|
||||
'/triggers?all_tenants=1', headers={})
|
||||
|
||||
@mock.patch('karborclient.common.http.HTTPClient.json_request')
|
||||
def test_list_triggers_with_marker_limit(self, mock_request):
|
||||
mock_request.return_value = mock_request_return
|
||||
@@ -46,16 +63,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
|
||||
@@ -97,3 +119,9 @@ class TriggersTest(base.TestCaseShell):
|
||||
data=body,
|
||||
headers={}
|
||||
)
|
||||
|
||||
def test_update_trigger_with_invalid_window(self):
|
||||
trigger_id = '123'
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
cs.triggers.update,
|
||||
trigger_id, {'properties': {'window': 'fake'}})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -26,6 +26,9 @@ class QuotaClassManager(base.ManagerWithFind):
|
||||
|
||||
def update(self, class_name, data):
|
||||
|
||||
if "plans" in data and data["plans"] is None:
|
||||
data["plans"] = 50
|
||||
|
||||
body = {"quota_class": data}
|
||||
|
||||
return self._update('/quota_classes/{class_name}'
|
||||
|
||||
@@ -26,6 +26,9 @@ class QuotaManager(base.ManagerWithFind):
|
||||
|
||||
def update(self, project_id, data):
|
||||
|
||||
if "plans" in data and data["plans"] is None:
|
||||
data["plans"] = 50
|
||||
|
||||
body = {"quota": data}
|
||||
|
||||
return self._update('/quotas/{project_id}'
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
from datetime import datetime
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from karborclient.common.apiclient import exceptions
|
||||
@@ -31,11 +31,6 @@ from karborclient import utils as arg_utils
|
||||
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('--name',
|
||||
metavar='<name>',
|
||||
default=None,
|
||||
@@ -188,6 +183,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 +194,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
|
||||
@@ -282,11 +281,6 @@ def do_restore_create(cs, args):
|
||||
const=1,
|
||||
default=0,
|
||||
help='Shows details for all tenants. Admin only.')
|
||||
@utils.arg('--all_tenants',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--status',
|
||||
metavar='<status>',
|
||||
default=None,
|
||||
@@ -349,7 +343,7 @@ def do_restore_list(cs, args):
|
||||
sortby_index = None
|
||||
else:
|
||||
sortby_index = 0
|
||||
formatters = {"Parameters": lambda obj: json.dumps(
|
||||
formatters = {"Parameters": lambda obj: jsonutils.dumps(
|
||||
obj.parameters, indent=2, sort_keys=True)}
|
||||
utils.print_list(restores, key_list, exclude_unavailable=True,
|
||||
sortby_index=sortby_index, formatters=formatters)
|
||||
@@ -412,11 +406,6 @@ def do_verification_create(cs, args):
|
||||
const=1,
|
||||
default=0,
|
||||
help='Shows details for all tenants. Admin only.')
|
||||
@utils.arg('--all_tenants',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--status',
|
||||
metavar='<status>',
|
||||
default=None,
|
||||
@@ -482,7 +471,7 @@ def do_verification_list(cs, args):
|
||||
sortby_index = None
|
||||
else:
|
||||
sortby_index = 0
|
||||
formatters = {"Parameters": lambda obj: json.dumps(
|
||||
formatters = {"Parameters": lambda obj: jsonutils.dumps(
|
||||
obj.parameters, indent=2, sort_keys=True)}
|
||||
utils.print_list(verifications, key_list, exclude_unavailable=True,
|
||||
sortby_index=sortby_index, formatters=formatters)
|
||||
@@ -610,7 +599,7 @@ def do_protectable_list_instances(cs, args):
|
||||
else:
|
||||
sortby_index = 0
|
||||
|
||||
formatters = {"Dependent resources": lambda obj: json.dumps(
|
||||
formatters = {"Dependent resources": lambda obj: jsonutils.dumps(
|
||||
obj.dependent_resources, indent=2, sort_keys=True)}
|
||||
utils.print_list(instances, key_list, exclude_unavailable=True,
|
||||
sortby_index=sortby_index, formatters=formatters)
|
||||
@@ -712,6 +701,14 @@ 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('provider_id',
|
||||
metavar='<provider_id>',
|
||||
help='ID of provider.')
|
||||
@@ -785,6 +782,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 +850,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>',
|
||||
@@ -860,11 +897,6 @@ def do_checkpoint_delete(cs, args):
|
||||
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('--name',
|
||||
metavar='<name>',
|
||||
default=None,
|
||||
@@ -937,7 +969,7 @@ def do_trigger_list(cs, args):
|
||||
else:
|
||||
sortby_index = 0
|
||||
|
||||
formatters = {"Properties": lambda obj: json.dumps(
|
||||
formatters = {"Properties": lambda obj: jsonutils.dumps(
|
||||
obj.properties, indent=2, sort_keys=True)}
|
||||
utils.print_list(triggers, key_list, exclude_unavailable=True,
|
||||
sortby_index=sortby_index, formatters=formatters)
|
||||
@@ -970,7 +1002,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"}
|
||||
@@ -1015,11 +1048,6 @@ def do_trigger_delete(cs, args):
|
||||
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('--name',
|
||||
metavar='<name>',
|
||||
default=None,
|
||||
@@ -1106,7 +1134,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.')
|
||||
@@ -1165,11 +1195,6 @@ def do_scheduledoperation_delete(cs, args):
|
||||
const=1,
|
||||
default=0,
|
||||
help='Shows details for all tenants. Admin only.')
|
||||
@utils.arg('--all_tenants',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--status',
|
||||
metavar='<status>',
|
||||
default=None,
|
||||
@@ -1332,7 +1357,7 @@ def _quota_set_pretty_show(quotas):
|
||||
metavar='<plans>',
|
||||
type=int,
|
||||
default=None,
|
||||
help='New value for the "plans" quota.')
|
||||
help='New value for the "plans" quota. The default value is 50.')
|
||||
def do_quota_update(cs, args):
|
||||
"""Update the quotas for a project (Admin only)."""
|
||||
project_id = args.tenant
|
||||
@@ -1375,7 +1400,7 @@ def do_quota_class_show(cs, args):
|
||||
metavar='<plans>',
|
||||
type=int,
|
||||
default=None,
|
||||
help='New value for the "plans" quota.')
|
||||
help='New value for the "plans" quota. The default value is 50.')
|
||||
def do_quota_class_update(cs, args):
|
||||
"""Update the quotas for a quota class (Admin only)."""
|
||||
class_name = args.class_name
|
||||
|
||||
@@ -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")
|
||||
|
||||
6
releasenotes/notes/drop-py-2-7-7a92a5906980666b.yaml
Normal file
6
releasenotes/notes/drop-py-2-7-7a92a5906980666b.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Python 2.7 support has been dropped. Last release of python-karborclient
|
||||
to support python 2.7 is OpenStack Train. The minimum version of Python now
|
||||
supported is Python 3.6.
|
||||
@@ -4,7 +4,7 @@ summary = Python client library for Karbor API
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
author-email = openstack-discuss@lists.openstack.org
|
||||
home-page = https://docs.openstack.org/python-karborclient/latest/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
@@ -13,10 +13,9 @@ classifier =
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
@@ -57,6 +56,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
|
||||
|
||||
18
tox.ini
18
tox.ini
@@ -1,16 +1,18 @@
|
||||
[tox]
|
||||
minversion = 2.0
|
||||
envlist = py35,py27,pypy,pep8
|
||||
minversion = 3.1.1
|
||||
envlist = py37,pypy,pep8
|
||||
skipsdist = True
|
||||
ignore_basepython_conflict = True
|
||||
|
||||
[testenv]
|
||||
basepython = python3
|
||||
usedevelop = True
|
||||
install_command = pip install {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
PYTHONWARNINGS=default::DeprecationWarning
|
||||
deps =
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/rocky}
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
whitelist_externals = rm
|
||||
@@ -19,26 +21,23 @@ commands =
|
||||
python setup.py test --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:pep8]
|
||||
basepython = python3
|
||||
commands = flake8
|
||||
|
||||
[testenv:venv]
|
||||
basepython = python3
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
basepython = python3
|
||||
commands =
|
||||
python setup.py test --coverage --testr-args='{posargs}'
|
||||
coverage report
|
||||
|
||||
[testenv:docs]
|
||||
basepython = python3
|
||||
deps = -r{toxinidir}/doc/requirements.txt
|
||||
deps =
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-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]
|
||||
@@ -49,7 +48,6 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user