Merge tag '2.1.0' into debian/newton

python-magnumclient 2.1.0 release

meta:version: 2.1.0
meta:series: newton
meta:release-type: release
meta:announce: openstack-announce@lists.openstack.org
meta:pypi: no
meta:first: yes
This commit is contained in:
Corey Bryant
2016-05-31 14:32:38 -04:00
20 changed files with 587 additions and 27 deletions

View File

@@ -44,6 +44,12 @@ def _extract_error_json(body):
if 'error_message' in body_json:
raw_msg = body_json['error_message']
error_json = json.loads(raw_msg)
else:
error_body = body_json['errors'][0]
raw_msg = error_body['title']
error_json = {'faultstring': error_body['title'],
'debuginfo': error_body['detail']}
except ValueError:
return {}

View File

@@ -31,7 +31,7 @@ def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None):
:returns: list of string filters.
"""
filters = []
if isinstance(limit, int) and limit > 0:
if isinstance(limit, int):
filters.append('limit=%s' % limit)
if marker is not None:
filters.append('marker=%s' % marker)
@@ -88,9 +88,9 @@ def format_labels(lbls, parse_comma=True):
if parse_comma:
# expect multiple invocations of --labels but fall back
# to , delimited if only one --labels is specified
# to either , or ; delimited if only one --labels is specified
if len(lbls) == 1:
lbls = lbls[0].split(',')
lbls = lbls[0].replace(';', ',').split(',')
labels = {}
for l in lbls:

View File

@@ -31,7 +31,11 @@ class CommonFiltersTest(test_utils.BaseTestCase):
def test_limit_0(self):
result = utils.common_filters(limit=0)
self.assertEqual([], result)
self.assertEqual(['limit=0'], result)
def test_limit_negative_number(self):
result = utils.common_filters(limit=-2)
self.assertEqual(['limit=-2'], result)
def test_other(self):
for key in ('marker', 'sort_key', 'sort_dir'):
@@ -118,6 +122,30 @@ class FormatLabelsTest(test_utils.BaseTestCase):
'K5': 'V5'
}, l)
def test_format_labels_semicolon(self):
l = utils.format_labels([
'K1=V1;K2=V2;'
'K3=V3;K4=V4;'
'K5=V5'])
self.assertEqual({'K1': 'V1',
'K2': 'V2',
'K3': 'V3',
'K4': 'V4',
'K5': 'V5'
}, l)
def test_format_labels_mix_commas_semicolon(self):
l = utils.format_labels([
'K1=V1,K2=V2,'
'K3=V3;K4=V4,'
'K5=V5'])
self.assertEqual({'K1': 'V1',
'K2': 'V2',
'K3': 'V3',
'K4': 'V4',
'K5': 'V5'
}, l)
def test_format_labels_split(self):
l = utils.format_labels([
'K1=V1,'

View File

@@ -112,6 +112,48 @@ fake_responses = {
UPDATED_BAYMODEL,
),
},
'/v1/baymodels/?limit=2':
{
'GET': (
{},
{'baymodels': [BAYMODEL1, BAYMODEL2]},
),
},
'/v1/baymodels/?marker=%s' % BAYMODEL2['uuid']:
{
'GET': (
{},
{'baymodels': [BAYMODEL1, BAYMODEL2]},
),
},
'/v1/baymodels/?limit=2&marker=%s' % BAYMODEL2['uuid']:
{
'GET': (
{},
{'baymodels': [BAYMODEL1, BAYMODEL2]},
),
},
'/v1/baymodels/?sort_dir=asc':
{
'GET': (
{},
{'baymodels': [BAYMODEL1, BAYMODEL2]},
),
},
'/v1/baymodels/?sort_key=uuid':
{
'GET': (
{},
{'baymodels': [BAYMODEL1, BAYMODEL2]},
),
},
'/v1/baymodels/?sort_key=uuid&sort_dir=desc':
{
'GET': (
{},
{'baymodels': [BAYMODEL2, BAYMODEL1]},
),
},
}
@@ -130,6 +172,66 @@ class BayModelManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertThat(baymodels, matchers.HasLength(2))
def _test_baymode_list_with_fileters(
self, limit=None, marker=None,
sort_key=None, sort_dir=None,
detail=False, expect=[]):
baymodels_filter = self.mgr.list(limit=limit, marker=marker,
sort_key=sort_key,
sort_dir=sort_dir,
detail=detail)
self.assertEqual(expect, self.api.calls)
self.assertThat(baymodels_filter, matchers.HasLength(2))
def test_baymodel_list_with_limit(self):
expect = [
('GET', '/v1/baymodels/?limit=2', {}, None),
]
self._test_baymode_list_with_fileters(
limit=2,
expect=expect)
def test_baymodel_list_with_marker(self):
expect = [
('GET', '/v1/baymodels/?marker=%s' % BAYMODEL2['uuid'], {}, None),
]
self._test_baymode_list_with_fileters(
marker=BAYMODEL2['uuid'],
expect=expect)
def test_baymodel_list_with_marker_limit(self):
expect = [
('GET', '/v1/baymodels/?limit=2&marker=%s' % BAYMODEL2['uuid'],
{}, None),
]
self._test_baymode_list_with_fileters(
limit=2, marker=BAYMODEL2['uuid'],
expect=expect)
def test_baymodel_list_with_sort_dir(self):
expect = [
('GET', '/v1/baymodels/?sort_dir=asc', {}, None),
]
self._test_baymode_list_with_fileters(
sort_dir='asc',
expect=expect)
def test_baymodel_list_with_sort_key(self):
expect = [
('GET', '/v1/baymodels/?sort_key=uuid', {}, None),
]
self._test_baymode_list_with_fileters(
sort_key='uuid',
expect=expect)
def test_baymodel_list_with_sort_key_dir(self):
expect = [
('GET', '/v1/baymodels/?sort_key=uuid&sort_dir=desc', {}, None),
]
self._test_baymode_list_with_fileters(
sort_key='uuid', sort_dir='desc',
expect=expect)
def test_baymodel_show_by_id(self):
baymodel = self.mgr.get(BAYMODEL1['id'])
expect = [

View File

@@ -96,6 +96,48 @@ fake_responses = {
UPDATED_BAY,
),
},
'/v1/bays/?limit=2':
{
'GET': (
{},
{'bays': [BAY1, BAY2]},
),
},
'/v1/bays/?marker=%s' % BAY2['uuid']:
{
'GET': (
{},
{'bays': [BAY1, BAY2]},
),
},
'/v1/bays/?limit=2&marker=%s' % BAY2['uuid']:
{
'GET': (
{},
{'bays': [BAY1, BAY2]},
),
},
'/v1/bays/?sort_dir=asc':
{
'GET': (
{},
{'bays': [BAY1, BAY2]},
),
},
'/v1/bays/?sort_key=uuid':
{
'GET': (
{},
{'bays': [BAY1, BAY2]},
),
},
'/v1/bays/?sort_key=uuid&sort_dir=desc':
{
'GET': (
{},
{'bays': [BAY2, BAY1]},
),
},
}
@@ -114,6 +156,64 @@ class BayManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertThat(bays, matchers.HasLength(2))
def _test_bay_list_with_filters(self, limit=None, marker=None,
sort_key=None, sort_dir=None,
detail=False, expect=[]):
bays_filter = self.mgr.list(limit=limit, marker=marker,
sort_key=sort_key,
sort_dir=sort_dir,
detail=detail)
self.assertEqual(expect, self.api.calls)
self.assertThat(bays_filter, matchers.HasLength(2))
def test_bay_list_with_limit(self):
expect = [
('GET', '/v1/bays/?limit=2', {}, None),
]
self._test_bay_list_with_filters(
limit=2,
expect=expect)
def test_bay_list_with_marker(self):
expect = [
('GET', '/v1/bays/?marker=%s' % BAY2['uuid'], {}, None),
]
self._test_bay_list_with_filters(
marker=BAY2['uuid'],
expect=expect)
def test_bay_list_with_marker_limit(self):
expect = [
('GET', '/v1/bays/?limit=2&marker=%s' % BAY2['uuid'], {}, None),
]
self._test_bay_list_with_filters(
limit=2, marker=BAY2['uuid'],
expect=expect)
def test_bay_list_with_sort_dir(self):
expect = [
('GET', '/v1/bays/?sort_dir=asc', {}, None),
]
self._test_bay_list_with_filters(
sort_dir='asc',
expect=expect)
def test_bay_list_with_sort_key(self):
expect = [
('GET', '/v1/bays/?sort_key=uuid', {}, None),
]
self._test_bay_list_with_filters(
sort_key='uuid',
expect=expect)
def test_bay_list_with_sort_key_dir(self):
expect = [
('GET', '/v1/bays/?sort_key=uuid&sort_dir=desc', {}, None),
]
self._test_bay_list_with_filters(
sort_key='uuid', sort_dir='desc',
expect=expect)
def test_bay_show_by_id(self):
bay = self.mgr.get(BAY1['id'])
expect = [

View File

@@ -25,6 +25,25 @@ class ShellTest(shell_test_base.TestCommandLineArgument):
self._test_arg_success('bay-list')
self.assertTrue(mock_list.called)
@mock.patch('magnumclient.v1.bays.BayManager.list')
def test_bay_list_success_with_arg(self, mock_list):
self._test_arg_success('bay-list '
'--marker some_uuid '
'--limit 1 '
'--sort-dir asc '
'--sort-key uuid')
self.assertTrue(mock_list.called)
@mock.patch('magnumclient.v1.bays.BayManager.list')
def test_bay_list_failure_invalid_arg(self, mock_list):
_error_msg = [
'.*?^usage: magnum bay-list ',
'.*?^error: argument --sort-dir: invalid choice: ',
".*?^Try 'magnum help bay-list' for more information."
]
self._test_arg_failure('bay-list --sort-dir aaa', _error_msg)
self.assertFalse(mock_list.called)
@mock.patch('magnumclient.v1.bays.BayManager.list')
def test_bay_list_failure(self, mock_list):
self._test_arg_failure('bay-list --wrong',

View File

@@ -129,3 +129,33 @@ class ClientTest(testtools.TestCase):
project_id=None,
project_name=None)
http_client.assert_not_called()
@mock.patch('magnumclient.common.httpclient.SessionClient')
@mock.patch('keystoneauth1.session.Session')
def test_init_with_endpoint_override(self, mock_session, http_client):
session = mock.Mock()
client.Client(session=session, endpoint_override='magnumurl')
mock_session.assert_not_called()
http_client.assert_called_once_with(
interface='public',
region_name=None,
service_name=None,
service_type='container',
session=session,
endpoint_override='magnumurl')
@mock.patch('magnumclient.common.httpclient.SessionClient')
@mock.patch('keystoneauth1.session.Session')
def test_init_with_magnum_url_and_endpoint_override(self, mock_session,
http_client):
session = mock.Mock()
client.Client(session=session, magnum_url='magnumurl',
endpoint_override='magnumurl_override')
mock_session.assert_not_called()
http_client.assert_called_once_with(
interface='public',
region_name=None,
service_name=None,
service_type='container',
session=session,
endpoint_override='magnumurl')

View File

@@ -198,6 +198,48 @@ fake_responses = {
{'output': '/home'},
),
},
'/v1/containers/?limit=2':
{
'GET': (
{},
{'containers': [CONTAINER1, CONTAINER2]},
),
},
'/v1/containers/?marker=%s' % CONTAINER2['uuid']:
{
'GET': (
{},
{'containers': [CONTAINER1, CONTAINER2]},
),
},
'/v1/containers/?limit=2&marker=%s' % CONTAINER2['uuid']:
{
'GET': (
{},
{'containers': [CONTAINER1, CONTAINER2]},
),
},
'/v1/containers/?sort_dir=asc':
{
'GET': (
{},
{'containers': [CONTAINER1, CONTAINER2]},
),
},
'/v1/containers/?sort_key=uuid':
{
'GET': (
{},
{'containers': [CONTAINER1, CONTAINER2]},
),
},
'/v1/containers/?sort_key=uuid&sort_dir=desc':
{
'GET': (
{},
{'containers': [CONTAINER2, CONTAINER1]},
),
},
}
@@ -226,6 +268,70 @@ class ContainerManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertThat(containers, matchers.HasLength(2))
def _test_container_list_with_filters(
self, limit=None, marker=None,
sort_key=None, sort_dir=None,
detail=False, expect=[]):
containers_filter = self.mgr.list(limit=limit, marker=marker,
sort_key=sort_key,
sort_dir=sort_dir,
detail=detail)
self.assertEqual(expect, self.api.calls)
self.assertThat(containers_filter, matchers.HasLength(2))
def test_container_list_with_limit(self):
expect = [
('GET', '/v1/containers/?limit=2', {}, None),
]
self._test_container_list_with_filters(
limit=2,
expect=expect)
def test_container_list_with_marker(self):
expect = [
('GET', '/v1/containers/?marker=%s' % CONTAINER2['uuid'],
{}, None),
]
self._test_container_list_with_filters(
marker=CONTAINER2['uuid'],
expect=expect)
def test_container_list_with_marker_limit(self):
expect = [
('GET', '/v1/containers/?limit=2&marker=%s' % CONTAINER2['uuid'],
{}, None),
]
self._test_container_list_with_filters(
limit=2, marker=CONTAINER2['uuid'],
expect=expect)
def test_container_list_with_sort_dir(self):
expect = [
('GET', '/v1/containers/?sort_dir=asc',
{}, None),
]
self._test_container_list_with_filters(
sort_dir='asc',
expect=expect)
def test_container_list_with_sort_key(self):
expect = [
('GET', '/v1/containers/?sort_key=uuid',
{}, None),
]
self._test_container_list_with_filters(
sort_key='uuid',
expect=expect)
def test_container_list_with_sort_key_dir(self):
expect = [
('GET', '/v1/containers/?sort_key=uuid&sort_dir=desc',
{}, None),
]
self._test_container_list_with_filters(
sort_key='uuid', sort_dir='desc',
expect=expect)
def test_container_show(self):
container = self.mgr.get(CONTAINER1['id'])
expect = [
@@ -262,17 +368,6 @@ class ContainerManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertIsNone(container)
def test_container_update(self):
patch = {'op': 'replace',
'value': NEW_NAME,
'path': '/name'}
container = self.mgr.update(id=CONTAINER1['id'], patch=patch)
expect = [
('PATCH', '/v1/containers/%s' % CONTAINER1['id'], {}, patch),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(NEW_NAME, container.name)
def test_container_start(self):
container = self.mgr.start(CONTAINER1['id'])
expect = [

View File

@@ -25,6 +25,25 @@ class ShellTest(shell_test_base.TestCommandLineArgument):
self._test_arg_success('container-list')
self.assertTrue(mock_list.called)
@mock.patch('magnumclient.v1.containers.ContainerManager.list')
def test_container_list_success_with_arg(self, mock_list):
self._test_arg_success('container-list '
'--marker some_uuid '
'--limit 1 '
'--sort-dir asc '
'--sort-key uuid')
self.assertTrue(mock_list.called)
@mock.patch('magnumclient.v1.containers.ContainerManager.list')
def test_container_list_failure_invalid_arg(self, mock_list):
_error_msg = [
'.*?^usage: magnum container-list ',
'.*?^error: argument --sort-dir: invalid choice: ',
".*?^Try 'magnum help container-list' for more information."
]
self._test_arg_failure('container-list --sort-dir aaa', _error_msg)
self.assertFalse(mock_list.called)
@mock.patch('magnumclient.v1.containers.ContainerManager.list')
def test_container_list_success_with_bay(self, mock_list):
self._test_arg_success('container-list --bay bay_uuid')

View File

@@ -36,6 +36,48 @@ fake_responses = {
{'mservices': [SERVICE1, SERVICE2]},
),
},
'/v1/mservices/?limit=2':
{
'GET': (
{},
{'mservices': [SERVICE1, SERVICE2]},
),
},
'/v1/mservices/?marker=%s' % SERVICE2['id']:
{
'GET': (
{},
{'mservices': [SERVICE1, SERVICE2]},
),
},
'/v1/mservices/?limit=2&marker=%s' % SERVICE2['id']:
{
'GET': (
{},
{'mservices': [SERVICE2, SERVICE1]},
),
},
'/v1/mservices/?sort_dir=asc':
{
'GET': (
{},
{'mservices': [SERVICE1, SERVICE2]},
),
},
'/v1/mservices/?sort_key=id':
{
'GET': (
{},
{'mservices': [SERVICE1, SERVICE2]},
),
},
'/v1/mservices/?sort_key=id&sort_dir=desc':
{
'GET': (
{},
{'mservices': [SERVICE2, SERVICE1]},
),
},
}
@@ -53,3 +95,67 @@ class MServiceManagerTest(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertThat(mservices, matchers.HasLength(2))
def _test_coe_service_list_with_filters(
self, limit=None, marker=None,
sort_key=None, sort_dir=None,
detail=False, expect=[]):
mservices_filter = self.mgr.list(limit=limit, marker=marker,
sort_key=sort_key,
sort_dir=sort_dir,
detail=detail)
self.assertEqual(expect, self.api.calls)
self.assertThat(mservices_filter, matchers.HasLength(2))
def test_coe_service_list_with_limit(self):
expect = [
('GET', '/v1/mservices/?limit=2', {}, None),
]
self._test_coe_service_list_with_filters(
limit=2,
expect=expect)
def test_coe_service_list_with_marker(self):
expect = [
('GET', '/v1/mservices/?marker=%s' % SERVICE2['id'],
{}, None),
]
self._test_coe_service_list_with_filters(
marker=SERVICE2['id'],
expect=expect)
def test_coe_service_list_with_marker_limit(self):
expect = [
('GET', '/v1/mservices/?limit=2&marker=%s' % SERVICE2['id'],
{}, None),
]
self._test_coe_service_list_with_filters(
limit=2, marker=SERVICE2['id'],
expect=expect)
def test_coe_service_list_with_sort_dir(self):
expect = [
('GET', '/v1/mservices/?sort_dir=asc',
{}, None),
]
self._test_coe_service_list_with_filters(
sort_dir='asc',
expect=expect)
def test_coe_service_list_with_sort_key(self):
expect = [
('GET', '/v1/mservices/?sort_key=id',
{}, None),
]
self._test_coe_service_list_with_filters(
sort_key='id',
expect=expect)
def test_coe_service_list_with_sort_key_dir(self):
expect = [
('GET', '/v1/mservices/?sort_key=id&sort_dir=desc',
{}, None),
]
self._test_coe_service_list_with_filters(
sort_key='id', sort_dir='desc',
expect=expect)

View File

@@ -82,7 +82,7 @@ def _show_baymodel(baymodel):
@utils.arg('--no-proxy',
metavar='<no-proxy>',
help='The no_proxy address to use for nodes in bay.')
@utils.arg('--labels', metavar='<KEY1=VALUE1,KEY2=VALUE2...>',
@utils.arg('--labels', metavar='<KEY1=VALUE1,KEY2=VALUE2;KEY3=VALUE3...>',
action='append', default=[],
help='Arbitrary labels in the form of key=value pairs '
'to associate with a baymodel. '
@@ -132,6 +132,8 @@ def do_baymodel_delete(cs, args):
for baymodel in args.baymodels:
try:
cs.baymodels.delete(baymodel)
print("Request to delete baymodel %s has been accepted." %
baymodel)
except Exception as e:
print("Delete for baymodel %(baymodel)s failed: %(e)s" %
{'baymodel': baymodel, 'e': e})

View File

@@ -21,12 +21,31 @@ def _show_bay(bay):
utils.print_dict(bay._info)
@utils.arg('--marker',
metavar='<marker>',
default=None,
help='The last bay UUID of the previous page; '
'displays list of bays after "marker".')
@utils.arg('--limit',
metavar='<limit>',
type=int,
help='Maximum number of bays to return.')
@utils.arg('--sort-key',
metavar='<sort-key>',
help='Column to sort results by.')
@utils.arg('--sort-dir',
metavar='<sort-dir>',
choices=['desc', 'asc'],
help='Direction to sort. "asc" or "desc".')
def do_bay_list(cs, args):
"""Print a list of available bays."""
bays = cs.bays.list()
bays = cs.bays.list(marker=args.marker, limit=args.limit,
sort_key=args.sort_key,
sort_dir=args.sort_dir)
columns = ('uuid', 'name', 'node_count', 'master_count', 'status')
utils.print_list(bays, columns,
{'versions': magnum_utils.print_list_field('versions')})
{'versions': magnum_utils.print_list_field('versions')},
sortby_index=None)
@utils.arg('--name',
@@ -83,6 +102,8 @@ def do_bay_delete(cs, args):
for id in args.bay:
try:
cs.bays.delete(id)
print("Request to delete bay %s has been accepted." %
id)
except Exception as e:
print("Delete for bay %(bay)s failed: %(e)s" %
{'bay': id, 'e': e})

View File

@@ -30,7 +30,8 @@ from magnumclient.v1 import services
class Client(object):
def __init__(self, username=None, api_key=None, project_id=None,
project_name=None, auth_url=None, magnum_url=None,
endpoint_type=None, service_type='container',
endpoint_type=None, endpoint_override=None,
service_type='container',
region_name=None, input_auth_token=None,
session=None, password=None, auth_type='password',
interface='public', service_name=None, insecure=False,
@@ -46,6 +47,11 @@ class Client(object):
if endpoint_type:
interface = endpoint_type
# fix (yolanda): os-cloud-config is using endpoint_override
# instead of magnum_url
if endpoint_override and not magnum_url:
magnum_url = endpoint_override
if magnum_url and input_auth_token:
auth_type = 'admin_token'
session = None

View File

@@ -110,9 +110,6 @@ class ContainerManager(base.Manager):
def delete(self, id):
return self._delete(self._path(id))
def update(self, id, patch):
return self._update(self._path(id), patch)
def _action(self, id, action, method='PUT', qparams=None, **kwargs):
if qparams:
action = "%s?%s" % (action,

View File

@@ -60,16 +60,37 @@ def do_container_create(cs, args):
_show_container(cs.containers.create(**opts))
@utils.arg('--marker',
metavar='<marker>',
default=None,
help='The last bay UUID of the previous page; '
'displays list of bays after "marker".')
@utils.arg('--limit',
metavar='<limit>',
type=int,
help='Maximum number of containers to return')
@utils.arg('--sort-key',
metavar='<sort-key>',
help='Column to sort results by')
@utils.arg('--sort-dir',
metavar='<sort-dir>',
choices=['desc', 'asc'],
help='Direction to sort. "asc" or "desc".')
@utils.arg('--bay',
metavar='<bay>', help="UUID or Name of Bay")
def do_container_list(cs, args):
"""Print a list of available containers."""
opts = {}
opts['bay_ident'] = args.bay
opts['marker'] = args.marker
opts['limit'] = args.limit
opts['sort_key'] = args.sort_key
opts['sort_dir'] = args.sort_dir
containers = cs.containers.list(**opts)
columns = ('uuid', 'name', 'status', 'bay_uuid')
utils.print_list(containers, columns,
{'versions': magnum_utils.print_list_field('versions')})
{'versions': magnum_utils.print_list_field('versions')},
sortby_index=None)
@utils.arg('containers',
@@ -81,6 +102,8 @@ def do_container_delete(cs, args):
for container in args.containers:
try:
cs.containers.delete(container)
print("Request to delete container %s has been accepted." %
container)
except Exception as e:
print("Delete for container %(container)s failed: %(e)s" %
{'container': container, 'e': e})

View File

@@ -109,6 +109,8 @@ def do_pod_delete(cs, args):
for pod in args.pods:
try:
cs.pods.delete(pod, args.bay)
print("Request to delete pod %s has been accepted." %
pod)
except Exception as e:
print("Delete for pod %(pod)s failed: %(e)s" %
{'pod': pod, 'e': e})

View File

@@ -114,6 +114,8 @@ def do_rc_delete(cs, args):
for rc in args.rcs:
try:
cs.rcs.delete(rc, args.bay)
print("Request to delete rc %s has been accepted." %
rc)
except Exception as e:
print("Delete for rc %(rc)s failed: %(e)s" %
{'rc': rc, 'e': e})

View File

@@ -102,6 +102,8 @@ def do_coe_service_delete(cs, args):
for service in args.services:
try:
cs.services.delete(service, args.bay)
print("Request to delete service %s has been accepted." %
service)
except Exception as e:
print("Delete for service %(service)s failed: %(e)s" %
{'service': service, 'e': e})

View File

@@ -3,10 +3,10 @@
# process, which may cause wedges in the gate later.
pbr>=1.6 # Apache-2.0
Babel>=1.3 # BSD
Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # BSD
six>=1.9.0 # MIT
keystoneauth1>=2.1.0 # Apache-2.0
stevedore>=1.5.0 # Apache-2.0
stevedore>=1.9.0 # Apache-2.0
requests!=2.9.0,>=2.8.1 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0

View File

@@ -2,10 +2,10 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.0
bandit>=0.17.3 # Apache-2.0
bandit>=1.0.1 # Apache-2.0
coverage>=3.6 # Apache-2.0
discover # BSD
fixtures>=1.3.1 # Apache-2.0/BSD
fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0