Compare commits

...

16 Commits

Author SHA1 Message Date
Ghanshyam Mann
6ded5189ba [ussuri][goal] Drop python 2.7 support and testing
OpenStack is dropping the py2.7 support in ussuri cycle.

python-karborclient is ready with python 3 and ok to drop the
python 2.7 support.

Complete discussion & schedule can be found in
- http://lists.openstack.org/pipermail/openstack-discuss/2019-October/010142.html
- https://etherpad.openstack.org/p/drop-python2-support

Ussuri Communtiy-wide goal:
https://governance.openstack.org/tc/goals/selected/ussuri/drop-py27.html

Change-Id: I777e4ecb3dbb1bea98a9a8c2e5bde1ee4129cc0f
2019-12-15 01:15:10 +00:00
Zuul
1419988ace Merge "Add unit test for quotas" 2019-11-09 07:28:19 +00:00
liushuai
21addfcca0 Add unit test for quotas
Change-Id: Id0d6ee5142687f64cbf448a8983683b19eb4b1f6
2019-11-07 23:44:37 +08:00
liushuai
56681c318e Add unit test for triggers
Change-Id: I3b6aaead255b51c742e8602d09b4b3f7f152ec6c
2019-11-07 17:34:58 +08:00
liushuai
5bd1b2feeb Add unit test for operation logs
Change-Id: I812ccf4ac1e5ab3f3d2402bcf9a9dd5b88781513
2019-11-05 22:44:18 +08:00
liushuai
05139e97e8 optional argument should have default values
Change-Id: I5ff5447f8ceec0a8ff25d46208a59eb2d6c8e307
Closes-Bug: #1844488
2019-09-23 17:29:28 +08:00
Zuul
c4e27f2e6d Merge "Add Python 3 Train unit tests" 2019-09-09 12:09:39 +00:00
jacky06
1a98ae3101 Replace git.openstack.org URLs with opendev.org URLs
Change-Id: Ia80a351665da5428d3c7c4cb518ecf0afc2ef8c1
2019-08-24 10:52:37 +08:00
chenke
4571dcb492 Switch to the new canonical constraints URL on master
Reference:
1. http://lists.openstack.org/pipermail/openstack-discuss/2019-May/006478.html
2. https://github.com/openstack/nova/blob/master/tox.ini#L17

Change-Id: Ie02a59eaee3807432c111e301163e87ab5afe2bd
2019-07-03 15:55:53 +08:00
Corey Bryant
9cd38596cd Add Python 3 Train unit tests
This is a mechanically generated patch to ensure unit testing is in place
for all of the Tested Runtimes for Train.

See the Train python3-updates goal document for details:
https://governance.openstack.org/tc/goals/train/python3-updates.html

Change-Id: Ia67bc92c85694a6be8eea65b9c4bb661ecc13b36
Story: #2005924
Task: #34214
2019-06-24 15:16:41 -04:00
Jiao Pengju
17f75a9c00 Fix listing with --all error
When executing command "karbor xxx-list --all", it will raise
error as 'error: ambiguous option: --all could match --all-tenants,
--all_tenants'. The reason is we have both '--all-tenants' and
'--all_tenants' in the specify operations, '--all' matches two
args, so it can not work, but when using '--all-' or '--all_',
it return the correct result. We should fix it, so we remove the
arg '--all_tenants' which is not in the help info.
Story: 2005874
Task: 33686

Change-Id: Iafa70c35594af732435122ebd50c114fd7f0b9df
2019-06-16 12:07:15 +08:00
OpenDev Sysadmins
6a5f46615c 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
Zuul
036ec8746a Merge "Update json module to jsonutils" 2019-03-21 09:05:28 +00:00
cao.yuan
56474b54df Update json module to jsonutils
oslo project provide jsonutils, and karborclient use it in many place[1],
this PS to update the remained json module to oslo jsonutils for
consistency.

[1]: https://github.com/openstack/python-karborclient/search?utf8=%E2%9C%93&q=jsonutils&type=

Change-Id: I8c2c0383eac12a5562f205640d6c8c7d062266b1
2019-02-25 20:15:46 +08:00
ZhongShengping
998e72a03a add python 3.7 unit test job
This is a mechanically generated patch to add a unit test job running
under Python 3.7.

See ML discussion here [1] for context.

[1] http://lists.openstack.org/pipermail/openstack-dev/2018-October/135626.html

Change-Id: I207e95619a8f4e8948f0d71404738a32daa7b5ba
Story: #2004073
Task: #27421
2019-02-19 17:06:02 +08:00
98k
7d93f625d9 Add doc/requirements.txt to docs tox environment
Without these dependencies, the releasenotes build does not actually
work.

Change-Id: Ie38200dafb86dbf4cc604ae837fc04f42c47b399
2019-01-09 17:46:52 +00:00
29 changed files with 334 additions and 104 deletions

View File

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

View File

@@ -3,8 +3,6 @@
- check-requirements
- openstack-cover-jobs
- openstack-lower-constraints-jobs
- openstack-python-jobs
- openstack-python35-jobs
- openstack-python36-jobs
- openstack-python3-ussuri-jobs
- openstackclient-plugin-jobs
- publish-openstack-docs-pti

View File

@@ -36,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

View File

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

View File

@@ -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",
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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."""

View File

@@ -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,7 @@ 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']]]]"
@@ -52,7 +53,7 @@ CHECKPOINT_INFO_2 = {
"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']]]]"

View File

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

View File

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

View File

@@ -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": []}

View File

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

View File

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

View File

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

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

View File

@@ -22,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
@@ -103,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'}})

View File

@@ -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}'

View File

@@ -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}'

View File

@@ -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,
@@ -286,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,
@@ -353,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)
@@ -416,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,
@@ -486,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)
@@ -614,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)
@@ -724,11 +709,6 @@ def do_checkpoint_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('provider_id',
metavar='<provider_id>',
help='ID of provider.')
@@ -917,11 +897,6 @@ def do_checkpoint_reset_state(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,
@@ -994,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)
@@ -1073,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,
@@ -1225,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,
@@ -1392,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
@@ -1435,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

View 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.

View File

@@ -13,11 +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 =

18
tox.ini
View File

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