diff -Nru python-glareclient-0.4.1/AUTHORS python-glareclient-0.5.2/AUTHORS --- python-glareclient-0.4.1/AUTHORS 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/AUTHORS 2018-01-18 12:20:04.000000000 +0000 @@ -1,9 +1,12 @@ Andreas Jaeger Darja Malyavkina +Idan Narotzki IlyaMenkov Mike Fedosin Mike Fedosin +Mike Fedosin Mike Fedosin Rui Yuan Dou Sergey Skripnick +Zuul ricolin diff -Nru python-glareclient-0.4.1/ChangeLog python-glareclient-0.5.2/ChangeLog --- python-glareclient-0.4.1/ChangeLog 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/ChangeLog 2018-01-18 12:20:04.000000000 +0000 @@ -1,10 +1,40 @@ CHANGES ======= +0.5.2 +----- + +* Adopt new api for artifact listing +* Rename -s option to -S + +0.5.1 +----- + +* Look the list of artifacts in 'artifacts' section +* Avoid tox\_install.sh for constraints support +* Remove setting of version/release from releasenotes +* Updated from global requirements +* Updated from global requirements + +0.5.0 +----- + +* Don't create client for help and bash completion +* Allow to work in secure mode without certificate + +0.4.2 +----- + +* Add content\_length to header in upload\_blob +* Allow to delete blobs with external urls +* Add ssl options to keycloak auth module +* Add ssl options to glare cli + 0.4.1 ----- * Return missing 'return' in build\_option\_parser +* Updated from global requirements 0.4.0 ----- diff -Nru python-glareclient-0.4.1/debian/changelog python-glareclient-0.5.2/debian/changelog --- python-glareclient-0.4.1/debian/changelog 2017-08-23 15:46:55.000000000 +0000 +++ python-glareclient-0.5.2/debian/changelog 2018-02-20 20:55:54.000000000 +0000 @@ -1,3 +1,14 @@ +python-glareclient (0.5.2-0ubuntu1) bionic; urgency=medium + + * New upstream release. + * d/*: wrap-and-sort -bast. + * d/control: Update Standards-Version to 4.1.2. + * d/control: Bump debhelper compat to 10. + * d/control: Align (Build-)Depends with upstream. + * d/p/skip-tests.patch: Rebased. + + -- Corey Bryant Tue, 20 Feb 2018 15:55:54 -0500 + python-glareclient (0.4.1-0ubuntu3) artful; urgency=medium * d/p/skip-test.patch: Updated to include TestController.test_get_type_list. diff -Nru python-glareclient-0.4.1/debian/compat python-glareclient-0.5.2/debian/compat --- python-glareclient-0.4.1/debian/compat 2017-08-23 15:46:55.000000000 +0000 +++ python-glareclient-0.5.2/debian/compat 2018-02-20 20:55:54.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru python-glareclient-0.4.1/debian/control python-glareclient-0.5.2/debian/control --- python-glareclient-0.4.1/debian/control 2017-08-23 15:46:55.000000000 +0000 +++ python-glareclient-0.5.2/debian/control 2018-02-20 20:55:54.000000000 +0000 @@ -2,57 +2,60 @@ Section: python Priority: extra Maintainer: Ubuntu Developers -Build-Depends: debhelper (>= 9), - dh-python, - openstack-pkg-tools (>= 52~), - python-all, - python-pbr (>= 2.0.0), - python-setuptools, - python-sphinx (>= 1.5.1), - python3-all, - python3-pbr (>= 2.0.0), - python3-setuptools, -Build-Depends-Indep: python-babel (>= 1.8), - python-coverage (>= 4.0), - python-fixtures (>= 3.0.0), - python-hacking (>= 0.12.0), - python-keystoneauth1 (>= 2.18.0), - python-mock (>= 2.0), - python-os-client-config (>= 1.28.0), - python-osc-lib (>= 1.2.0), - python-oslo.i18n (>= 2.1.0), - python-oslo.log (>= 3.11.0), - python-oslo.utils (>= 3.20.0), - python-oslosphinx (>= 4.7.0), - python-prettytable (>= 0.7.1), - python-requests (>= 2.10.0), - python-requests-mock (>= 1.1), - python-six (>= 1.9.0), - python-testrepository (>= 0.0.18), - python-testscenarios (>= 0.4), - python-testtools (>= 1.4.0), - python3-babel (>= 1.8), - python3-coverage (>= 4.0), - python3-fixtures (>= 3.0.0), - python3-hacking (>= 0.12.0), - python3-keystoneauth1 (>= 2.18.0), - python3-mock (>= 2.0), - python3-os-client-config (>= 1.28.0), - python3-osc-lib (>= 1.2.0), - python3-oslo.i18n (>= 2.1.0), - python3-oslo.log (>= 3.11.0), - python3-oslo.utils (>= 3.20.0), - python3-oslosphinx (>= 4.7.0), - python3-prettytable (>= 0.7.1), - python3-requests (>= 2.10.0), - python3-requests-mock (>= 1.1), - python3-six (>= 1.9.0), - python3-testrepository (>= 0.0.18), - python3-testscenarios (>= 0.4), - python3-testtools (>= 1.4.0), - subunit, - testrepository -Standards-Version: 3.9.8 +Build-Depends: + debhelper (>= 10~), + dh-python, + openstack-pkg-tools (>= 52~), + python-all, + python-pbr (>= 2.0.0), + python-setuptools, + python-sphinx (>= 1.6.2), + python3-all, + python3-pbr (>= 2.0.0), + python3-setuptools, + python3-sphinx (>= 1.6.2), +Build-Depends-Indep: + python-babel (>= 2.3.4), + python-coverage (>= 4.0), + python-fixtures (>= 3.0.0), + python-hacking (>= 0.12.0), + python-keystoneauth1 (>= 3.2.0), + python-mock (>= 2.0.0), + python-os-client-config (>= 1.28.0), + python-osc-lib (>= 1.7.0), + python-oslo.i18n (>= 3.15.3), + python-oslo.log (>= 3.30.0), + python-oslo.utils (>= 3.31.0), + python-oslosphinx (>= 4.7.0), + python-prettytable (>= 0.7.1), + python-requests (>= 2.14.2), + python-requests-mock (>= 1.1.0), + python-six (>= 1.9.0), + python-testrepository (>= 0.0.18), + python-testscenarios (>= 0.4), + python-testtools (>= 1.4.0), + python3-babel (>= 2.3.4), + python3-coverage (>= 4.0), + python3-fixtures (>= 3.0.0), + python3-hacking (>= 0.12.0), + python3-keystoneauth1 (>= 3.2.0), + python3-mock (>= 2.0.0), + python3-os-client-config (>= 1.28.0), + python3-osc-lib (>= 1.7.0), + python3-oslo.i18n (>= 3.15.3), + python3-oslo.log (>= 3.30.0), + python3-oslo.utils (>= 3.31.0), + python3-oslosphinx (>= 4.7.0), + python3-prettytable (>= 0.7.1), + python3-requests (>= 2.14.2), + python3-requests-mock (>= 1.1.0), + python3-six (>= 1.9.0), + python3-testrepository (>= 0.0.18), + python3-testscenarios (>= 0.4), + python3-testtools (>= 1.4.0), + subunit, + testrepository, +Standards-Version: 4.1.2 Vcs-Browser: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-glareclient Vcs-Git: git://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-glareclient Homepage: http://www.openstack.org/ @@ -60,20 +63,22 @@ Package: python-glareclient Architecture: all -Depends: python-babel (>= 1.8), - python-keystoneauth1 (>= 2.18.0), - python-osc-lib (>= 1.2.0), - python-oslo.i18n (>= 2.1.0), - python-oslo.log (>= 3.11.0), - python-oslo.utils (>= 3.20.0), - python-pbr (>= 2.0.0), - python-prettytable (>= 0.7.1), - python-requests (>= 2.10.0), - python-six (>= 1.9.0), - ${misc:Depends}, - ${python:Depends}, - ${sphinxdoc:Depends} -Suggests: python-glareclient-doc +Depends: + python-babel (>= 2.3.4), + python-keystoneauth1 (>= 3.2.0), + python-osc-lib (>= 1.7.0), + python-oslo.i18n (>= 3.15.3), + python-oslo.log (>= 3.30.0), + python-oslo.utils (>= 3.31.0), + python-pbr (>= 2.0.0), + python-prettytable (>= 0.7.1), + python-requests (>= 2.14.2), + python-six (>= 1.9.0), + ${misc:Depends}, + ${python:Depends}, + ${sphinxdoc:Depends}, +Suggests: + python-glareclient-doc, Description: Client library for Openstack glare server - Python 2.x The glare project provides services for accessing a unified catalog of structured meta-information as well as related binary data (these @@ -84,22 +89,13 @@ . This package provides the Python 2.x module. -Package: python3-glareclient +Package: python-glareclient-doc +Section: doc Architecture: all -Depends: python3-babel (>= 1.8), - python3-keystoneauth1 (>= 2.18.0), - python3-osc-lib (>= 1.2.0), - python3-oslo.i18n (>= 2.1.0), - python3-oslo.log (>= 3.11.0), - python3-oslo.utils (>= 3.20.0), - python3-pbr (>= 2.0.0), - python3-prettytable (>= 0.7.1), - python3-requests (>= 2.10.0), - python3-six (>= 1.9.0), - ${misc:Depends}, - ${python3:Depends} -Suggests: python-glareclient-doc -Description: Client library for Openstack glare server - Python 3.x +Depends: + ${misc:Depends}, + ${sphinxdoc:Depends}, +Description: Client library for Openstack glare server - doc The glare project provides services for accessing a unified catalog of structured meta-information as well as related binary data (these structures are also called 'artifacts'). @@ -107,14 +103,26 @@ This is a client for glare which uses the OpenStack Glare API. There's a Python API (the "glareclient" module), and a command-line script ("glare"). . - This package provides the Python 3.x module. + This package provides the documentation and man page. -Package: python-glareclient-doc -Section: doc +Package: python3-glareclient Architecture: all -Depends: ${misc:Depends}, - ${sphinxdoc:Depends}, -Description: Client library for Openstack glare server - doc +Depends: + python3-babel (>= 2.3.4), + python3-keystoneauth1 (>= 3.2.0), + python3-osc-lib (>= 1.7.0), + python3-oslo.i18n (>= 3.15.3), + python3-oslo.log (>= 3.30.0), + python3-oslo.utils (>= 3.31.0), + python3-pbr (>= 2.0.0), + python3-prettytable (>= 0.7.1), + python3-requests (>= 2.14.2), + python3-six (>= 1.9.0), + ${misc:Depends}, + ${python3:Depends}, +Suggests: + python-glareclient-doc, +Description: Client library for Openstack glare server - Python 3.x The glare project provides services for accessing a unified catalog of structured meta-information as well as related binary data (these structures are also called 'artifacts'). @@ -122,4 +130,4 @@ This is a client for glare which uses the OpenStack Glare API. There's a Python API (the "glareclient" module), and a command-line script ("glare"). . - This package provides the documentation and man page. + This package provides the Python 3.x module. diff -Nru python-glareclient-0.4.1/debian/patches/skip-test.patch python-glareclient-0.5.2/debian/patches/skip-test.patch --- python-glareclient-0.4.1/debian/patches/skip-test.patch 2017-08-23 15:46:55.000000000 +0000 +++ python-glareclient-0.5.2/debian/patches/skip-test.patch 2018-02-20 20:55:54.000000000 +0000 @@ -9,7 +9,7 @@ --- a/glareclient/tests/unit/v1/test_artifacts.py +++ b/glareclient/tests/unit/v1/test_artifacts.py -@@ -41,6 +41,7 @@ +@@ -45,6 +45,7 @@ json={'version': '0.1.2', 'name': 'name'}) self.c._check_type_name.assert_called_once_with('ok') @@ -17,9 +17,9 @@ def test_update(self): remove_props = ['remove1', 'remove2'] body = self.c.update('test-id', type_name='test_name', -@@ -118,6 +119,7 @@ +@@ -165,6 +166,7 @@ '/artifacts/checked_name/test-id/blob-prop', - data='data', headers={'Content-Type': 'application/test'}) + data=data, headers={'Content-Type': 'application/test'}) + @testtools.skip("Skipped by Ubuntu") def test_get_type_list(self): diff -Nru python-glareclient-0.4.1/glareclient/common/http.py python-glareclient-0.5.2/glareclient/common/http.py --- python-glareclient-0.4.1/glareclient/common/http.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/common/http.py 2018-01-18 12:17:09.000000000 +0000 @@ -15,7 +15,6 @@ import copy import hashlib -import os import socket from keystoneauth1 import adapter @@ -28,30 +27,13 @@ from glareclient.common import exceptions as exc from glareclient.common import keycloak_auth +from glareclient.common import utils LOG = logging.getLogger(__name__) USER_AGENT = 'python-glareclient' CHUNKSIZE = 1024 * 64 # 64kB -def get_system_ca_file(): - """Return path to system default CA file.""" - # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, - # Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca - ca_path = ['/etc/ssl/certs/ca-certificates.crt', - '/etc/pki/tls/certs/ca-bundle.crt', - '/etc/ssl/ca-bundle.pem', - '/etc/ssl/cert.pem', - '/System/Library/OpenSSL/certs/cacert.pem', - requests.certs.where()] - for ca in ca_path: - LOG.debug("Looking for ca file %s", ca) - if os.path.exists(ca): - LOG.debug("Using ca file %s", ca) - return ca - LOG.warning("System ca file could not be found.") - - def _handle_response(resp): content_type = resp.headers.get('Content-Type') if not content_type: @@ -113,7 +95,8 @@ if kwargs.get('insecure'): self.verify_cert = False else: - self.verify_cert = kwargs.get('cacert', get_system_ca_file()) + self.verify_cert = kwargs.get( + 'cacert', utils.get_system_ca_file()) def _safe_header(self, name, value): if name in ['X-Auth-Token', 'X-Subject-Token']: @@ -332,14 +315,14 @@ parameters.update(kwargs) return SessionClient(**parameters) elif endpoint: - realm_name = kwargs.pop('keycloak_realm_name', None) if keycloak_auth_url: kwargs['auth_token'] = keycloak_auth.authenticate( auth_url=keycloak_auth_url, client_id=kwargs.pop('openid_client_id', None), username=kwargs.pop('keycloak_username', None), password=kwargs.pop('keycloak_password', None), - realm_name=realm_name + realm_name=kwargs.pop('keycloak_realm_name', None), + **kwargs ) else: kwargs['auth_token'] = auth_token diff -Nru python-glareclient-0.4.1/glareclient/common/keycloak_auth.py python-glareclient-0.5.2/glareclient/common/keycloak_auth.py --- python-glareclient-0.4.1/glareclient/common/keycloak_auth.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/common/keycloak_auth.py 2018-01-18 12:17:09.000000000 +0000 @@ -15,6 +15,9 @@ import logging import pprint import requests +from six.moves import urllib + +from glareclient.common import utils LOG = logging.getLogger(__name__) @@ -29,8 +32,8 @@ :param username: User name (Optional, if None then access_token must be provided). :param password: Password (Optional). + :param cacert: SSL certificate file (Optional). :param insecure: If True, SSL certificate is not verified (Optional). - """ auth_url = kwargs.get('auth_url') client_id = kwargs.get('client_id') @@ -38,6 +41,7 @@ username = kwargs.get('username') password = kwargs.get('password') insecure = kwargs.get('insecure', False) + cacert = kwargs.get('cacert', utils.get_system_ca_file()) if not auth_url: raise ValueError('Base authentication url is not provided.') @@ -59,6 +63,10 @@ (auth_url, realm_name) ) + verify = None + if urllib.parse.urlparse(access_token_endpoint).scheme == "https": + verify = False if insecure else cacert if cacert else True + body = { 'grant_type': 'password', 'username': username, @@ -70,7 +78,7 @@ resp = requests.post( access_token_endpoint, data=body, - verify=not insecure + verify=verify ) try: diff -Nru python-glareclient-0.4.1/glareclient/common/utils.py python-glareclient-0.5.2/glareclient/common/utils.py --- python-glareclient-0.4.1/glareclient/common/utils.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/common/utils.py 2018-01-18 12:17:09.000000000 +0000 @@ -25,12 +25,16 @@ else: msvcrt = None +from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import importutils import requests from glareclient import exc +LOG = logging.getLogger(__name__) + + SENSITIVE_HEADERS = ('X-Auth-Token', ) @@ -173,3 +177,21 @@ type_name=parsed_args.type_name)['id'] except exc.BadRequest as e: exit(msg=e.details) + + +def get_system_ca_file(): + """Return path to system default CA file.""" + # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, + # Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca + ca_path = ['/etc/ssl/certs/ca-certificates.crt', + '/etc/pki/tls/certs/ca-bundle.crt', + '/etc/ssl/ca-bundle.pem', + '/etc/ssl/cert.pem', + '/System/Library/OpenSSL/certs/cacert.pem', + requests.certs.where()] + for ca in ca_path: + LOG.debug("Looking for ca file %s", ca) + if os.path.exists(ca): + LOG.debug("Using ca file %s", ca) + return ca + LOG.warning("System ca file could not be found.") diff -Nru python-glareclient-0.4.1/glareclient/osc/v1/artifacts.py python-glareclient-0.5.2/glareclient/osc/v1/artifacts.py --- python-glareclient-0.4.1/glareclient/osc/v1/artifacts.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/osc/v1/artifacts.py 2018-01-18 12:17:09.000000000 +0000 @@ -75,7 +75,7 @@ help='Filtering artifact list by a user-defined property.', ) parser.add_argument( - '--sort', '-s', + '--sort', '-S', default='name:asc', metavar='[:]', help='Comma-separated list of sort keys and directions in the ' diff -Nru python-glareclient-0.4.1/glareclient/osc/v1/blobs.py python-glareclient-0.5.2/glareclient/osc/v1/blobs.py --- python-glareclient-0.4.1/glareclient/osc/v1/blobs.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/osc/v1/blobs.py 2018-01-18 12:17:09.000000000 +0000 @@ -275,3 +275,52 @@ else: data_to_display.update(data[parsed_args.blob_property]) return self.dict2columns(data_to_display) + + +class RemoveLocation(command.ShowOne): + """Remove external location""" + + def get_parser(self, prog_name): + parser = super(RemoveLocation, self).get_parser(prog_name) + parser.add_argument( + 'type_name', + metavar='', + action=TypeMapperAction, + help='Name of artifact type.', + ), + parser.add_argument( + 'name', + metavar='', + help='Name or id of the artifact to download.', + ), + parser.add_argument( + '--artifact-version', '-V', + metavar='', + default='latest', + help='Version of the artifact.', + ), + parser.add_argument( + '--id', '-i', + action='store_true', + help='The specified id of the artifact.', + ), + parser.add_argument( + '--blob-property', '-p', + metavar='', + help='Name of the blob field.' + ) + return parser + + def take_action(self, parsed_args): + LOG.debug('take_action({0})'.format(parsed_args)) + client = self.app.client_manager.artifact + af_id = utils.get_artifact_id(client, parsed_args) + + if not parsed_args.blob_property: + parsed_args.blob_property = _default_blob_property( + parsed_args.type_name) + + client.artifacts.remove_external_location( + af_id, + parsed_args.blob_property, + type_name=parsed_args.type_name) diff -Nru python-glareclient-0.4.1/glareclient/shell.py python-glareclient-0.5.2/glareclient/shell.py --- python-glareclient-0.4.1/glareclient/shell.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/shell.py 2018-01-18 12:17:09.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright 2015 - StackStorm, Inc. +# Copyright 2017 - Nokia Networks # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -225,6 +225,35 @@ dest='keycloak_password', default=utils.env('KEYCLOAK_PASSWORD'), help='Keycloak user password (Env: KEYCLOAK_PASSWORD)') + parser.add_argument( + '--cert', + action='store', + dest='cert_file', + default=utils.env('OS_GLARE_CERT'), + help='Client Certificate (Env: OS_GLARE_CERT)' + ) + parser.add_argument( + '--key', + action='store', + dest='key_file', + default=utils.env('OS_GLARE_KEY'), + help='Client Key (Env: OS_GLARE_KEY)' + ) + parser.add_argument( + '--cacert', + action='store', + dest='cacert', + default=utils.env('OS_GLARE_CACERT'), + help='Authentication CA Certificate (Env: OS_GLARE_CACERT)' + ) + parser.add_argument( + '--insecure', + action='store_true', + dest='insecure', + default=utils.env('GLARECLIENT_INSECURE', default=False), + help='Disables SSL/TLS certificate verification ' + '(Env: GLARELCLIENT_INSECURE)' + ) return parser @@ -232,25 +261,15 @@ self._clear_shell_commands() self._set_shell_commands(self._get_commands()) - do_help = ('help' in argv) or ('-h' in argv) or not argv + # bash-completion and help messages should not require client creation + need_client = not ( + ('bash-completion' in argv) or + ('help' in argv) or + ('-h' in argv) or + ('--help' in argv) or + not argv) - # Set default for auth_url if not supplied. The default is not - # set at the parser to support use cases where auth is not enabled. - # An example use case would be a developer's environment. - - # bash-completion should not require authentification. - if do_help or ('bash-completion' in argv): - self.options.auth_url = None - - self.client = client.Client( - endpoint=self.options.glare_url, - auth_token=self.options.auth_token, - keycloak_auth_url=self.options.keycloak_auth_url, - openid_client_id=self.options.openid_client_id, - keycloak_realm_name=self.options.keycloak_realm_name, - keycloak_username=self.options.keycloak_username, - keycloak_password=self.options.keycloak_password, - ) + self.client = self._create_client() if need_client else None # Adding client_manager variable to make glare client work with # unified OpenStack client. @@ -262,6 +281,21 @@ self.client_manager = ClientManager() + def _create_client(self): + return client.Client( + endpoint=self.options.glare_url, + auth_token=self.options.auth_token, + keycloak_auth_url=self.options.keycloak_auth_url, + openid_client_id=self.options.openid_client_id, + keycloak_realm_name=self.options.keycloak_realm_name, + keycloak_username=self.options.keycloak_username, + keycloak_password=self.options.keycloak_password, + cert_file=self.options.cert_file, + key_file=self.options.key_file, + cacert=self.options.cacert, + insecure=self.options.insecure + ) + def _set_shell_commands(self, cmds_dict): for k, v in cmds_dict.items(): self.command_manager.add_command(k, v) @@ -293,7 +327,8 @@ 'schema': glareclient.osc.v1.artifacts.TypeSchema, 'upload': glareclient.osc.v1.blobs.UploadBlob, 'download': glareclient.osc.v1.blobs.DownloadBlob, - 'location': glareclient.osc.v1.blobs.AddLocation + 'location': glareclient.osc.v1.blobs.AddLocation, + 'remove-location': glareclient.osc.v1.blobs.RemoveLocation } diff -Nru python-glareclient-0.4.1/glareclient/tests/unit/osc/v1/test_blob.py python-glareclient-0.5.2/glareclient/tests/unit/osc/v1/test_blob.py --- python-glareclient-0.4.1/glareclient/tests/unit/osc/v1/test_blob.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/tests/unit/osc/v1/test_blob.py 2018-01-18 12:17:09.000000000 +0000 @@ -221,3 +221,31 @@ columns, data = self.cmd.take_action(parsed_args) self.app.client_manager.artifact.artifacts.get = fakes.mock_get self.assertEqual(self.COLUMNS, columns) + + +class TestRemoveLocation(TestBlobs): + def setUp(self): + super(TestRemoveLocation, self).setUp() + self.blob_mock.call.return_value = \ + api_art.Controller(self.http, type_name='images') + + # Command to test + self.cmd = osc_blob.RemoveLocation(self.app, None) + + def test_remove_location(self): + arglist = ['images', + 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba', '--id'] + verify = [('type_name', 'images'), + ('name', 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba'), + ('id', True)] + parsed_args = self.check_parser(self.cmd, arglist, verify) + self.assertIsNone(self.cmd.take_action(parsed_args)) + + def test_remove_dict_location(self): + arglist = ['images', '--blob-property', 'nested_templates/blob', + 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba', '--id'] + verify = [('type_name', 'images'), + ('name', 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba'), + ('id', True)] + parsed_args = self.check_parser(self.cmd, arglist, verify) + self.assertIsNone(self.cmd.take_action(parsed_args)) diff -Nru python-glareclient-0.4.1/glareclient/tests/unit/test_common_http.py python-glareclient-0.5.2/glareclient/tests/unit/test_common_http.py --- python-glareclient-0.4.1/glareclient/tests/unit/test_common_http.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/tests/unit/test_common_http.py 2018-01-18 12:17:09.000000000 +0000 @@ -19,6 +19,7 @@ from glareclient.common import exceptions as exc from glareclient.common import http +from glareclient.common import utils from glareclient.tests.unit import fakes @@ -420,7 +421,7 @@ with mock.patch('os.path.exists') as mock_os: mock_os.return_value = chosen - ca = http.get_system_ca_file() + ca = utils.get_system_ca_file() self.assertEqual(chosen, ca) mock_os.assert_called_once_with(chosen) @@ -433,7 +434,7 @@ client = http.HTTPClient('https://foo', cacert="NOWHERE") self.assertEqual("NOWHERE", client.verify_cert) - with mock.patch('glareclient.common.http.get_system_ca_file') as gsf: + with mock.patch('glareclient.common.utils.get_system_ca_file') as gsf: gsf.return_value = "SOMEWHERE" client = http.HTTPClient('https://foo') self.assertEqual("SOMEWHERE", client.verify_cert) diff -Nru python-glareclient-0.4.1/glareclient/tests/unit/test_shell.py python-glareclient-0.5.2/glareclient/tests/unit/test_shell.py --- python-glareclient-0.4.1/glareclient/tests/unit/test_shell.py 1970-01-01 00:00:00.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/tests/unit/test_shell.py 2018-01-18 12:17:09.000000000 +0000 @@ -0,0 +1,59 @@ +# Copyright 2015 Huawei Technologies Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock +import os +import sys + +import six +import testtools + +from glareclient import shell + + +class TestShell(testtools.TestCase): + + def shell(self, argstr): + orig = (sys.stdout, sys.stderr) + clean_env = {} + _old_env, os.environ = os.environ, clean_env.copy() + + try: + sys.stdout = six.moves.cStringIO() + sys.stderr = six.moves.cStringIO() + _shell = shell.GlareShell() + _shell.run(argstr.split()) + except SystemExit: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.assertEqual(0, exc_value.code) + finally: + stdout = sys.stdout.getvalue() + stderr = sys.stderr.getvalue() + sys.stdout.close() + sys.stderr.close() + sys.stdout, sys.stderr = orig + os.environ = _old_env + + return stdout, stderr + + def test_help(self): + """Test that client is not created for help and bash complete""" + for command in ('-h', + '--help', + 'help', + 'help workbook-list', + 'bash-completion'): + with mock.patch('glareclient.client.Client') as client_mock: + self.shell(command) + self.assertFalse(client_mock.called) diff -Nru python-glareclient-0.4.1/glareclient/tests/unit/v1/test_artifacts.py python-glareclient-0.5.2/glareclient/tests/unit/v1/test_artifacts.py --- python-glareclient-0.4.1/glareclient/tests/unit/v1/test_artifacts.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/tests/unit/v1/test_artifacts.py 2018-01-18 12:17:09.000000000 +0000 @@ -13,6 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. +import io +import os +import tempfile + import mock from oslo_serialization import jsonutils import testtools @@ -66,7 +70,7 @@ '/artifacts/checked_name/test-id') self.c._check_type_name.assert_called_once_with('test_name') - def test_list(self): + def test_list_legacy(self): self.mock_http_client.get.side_effect = [ (None, {'checked_name': [10, 11, 12], "next": "next1"}), (None, {'checked_name': [13, 14, 15], "next": "next2"}), @@ -84,6 +88,24 @@ ] self.assertEqual(expected_calls, self.mock_http_client.mock_calls) + def test_list(self): + self.mock_http_client.get.side_effect = [ + (None, {'artifacts': [10, 11, 12], "next": "next1"}), + (None, {'artifacts': [13, 14, 15], "next": "next2"}), + (None, {'artifacts': [16, 17, 18], "next": "next3"}), + (None, {'artifacts': [19, 20, 21]}), + ] + data = list(self.c.list(type_name='test-type', limit=10, page_size=3)) + expected = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + self.assertEqual(expected, data) + expected_calls = [ + mock.call.get('/artifacts/checked_name?&limit=3'), + mock.call.get('next1'), + mock.call.get('next2'), + mock.call.get('next3'), + ] + self.assertEqual(expected_calls, self.mock_http_client.mock_calls) + def test_activate(self): self.c.update = mock.Mock() self.assertEqual(self.c.update.return_value, @@ -110,13 +132,38 @@ self.mock_http_client.delete.assert_called_once_with( '/artifacts/checked_name/test-id') - def test_upload_blob(self): + def test_upload_blob_str(self): self.c.upload_blob('test-id', 'blob-prop', 'data', type_name='test-type', content_type='application/test') self.mock_http_client.put.assert_called_once_with( '/artifacts/checked_name/test-id/blob-prop', - data='data', headers={'Content-Type': 'application/test'}) + data='data', headers={'Content-Length': '4', + 'Content-Type': 'application/test'}) + + def test_upload_blob_file(self): + tfd, path = tempfile.mkstemp() + try: + os.write(tfd, b'data') + tfile = open(path, "rb") + self.c.upload_blob('test-id', 'blob-prop', tfile, + type_name='test-type', + content_type='application/test') + self.mock_http_client.put.assert_called_once_with( + '/artifacts/checked_name/test-id/blob-prop', + data=tfile, headers={'Content-Length': '4', + 'Content-Type': 'application/test'}) + finally: + os.remove(path) + + def test_upload_blob_stream(self): + data = io.BytesIO(b'data') + self.c.upload_blob('test-id', 'blob-prop', data, + type_name='test-type', + content_type='application/test') + self.mock_http_client.put.assert_called_once_with( + '/artifacts/checked_name/test-id/blob-prop', + data=data, headers={'Content-Type': 'application/test'}) def test_get_type_list(self): schemas = {'schemas': {'a': {'version': 1}, 'b': {'version': 2}}} @@ -151,6 +198,16 @@ 'application/vnd+openstack.glare-custom-location+json'}) self.assertIsNone(resp) + def test_remove_external_location(self): + art_id = '3a4560a1-e585-443e-9b39-553b46ec92a8' + resp = self.c.remove_external_location( + art_id, 'image', + type_name='images') + self.c.http_client.delete.assert_called_once_with( + '/artifacts/checked_name/' + '3a4560a1-e585-443e-9b39-553b46ec92a8/image') + self.assertIsNone(resp) + def test_add_tag(self): art_id = '07a679d8-d0a8-45ff-8d6e-2f32f2097b7c' d = {'tags': ['a', 'b', 'c']} diff -Nru python-glareclient-0.4.1/glareclient/v1/artifacts.py python-glareclient-0.5.2/glareclient/v1/artifacts.py --- python-glareclient-0.4.1/glareclient/v1/artifacts.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/glareclient/v1/artifacts.py 2018-01-18 12:17:09.000000000 +0000 @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import os + from oslo_serialization import jsonutils from oslo_utils import encodeutils import six @@ -116,7 +118,7 @@ type_name = self._check_type_name(type_name) url = '/artifacts/%s?version=%s&name=%s' % (type_name, version, name) resp, body = self.http_client.get(url) - arts = body[type_name] + arts = body.get('artifacts', body.get(type_name)) if not arts: msg = ('Artifact with name=%s and version=%s not found.' % (name, version)) @@ -136,7 +138,7 @@ ' Please provide the concrete id from the list:\n%s' % (name, version, output)) raise exc.BadRequest(msg) - return body[type_name][0] + return arts[0] def list(self, type_name=None, **kwargs): """Retrieve a listing of artifacts objects. @@ -159,7 +161,11 @@ "limit=%s" % limit) resp, body = self.http_client.get(next_url) - for artifact in body[type_name]: + + # For backward compatibility we also look for the list of + # artifacts under the type_name section. + # In current versions it should be located in 'artifacts'. + for artifact in body.get('artifacts', body.get(type_name)): yield artifact if limit: @@ -244,8 +250,22 @@ :param blob_property: blob property name """ content_type = content_type or 'application/octet-stream' - type_name = self._check_type_name(type_name) hdrs = {'Content-Type': content_type} + type_name = self._check_type_name(type_name) + + content_length = None + if isinstance(data, six.string_types): + content_length = len(data) + else: + try: + content_length = os.path.getsize(data.name) + except Exception: + # if for some reason we can't get the file size, then we just + # ignore it. + pass + if content_length is not None: + hdrs['Content-Length'] = str(content_length) + url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property) self.http_client.put(url, headers=hdrs, data=data) @@ -267,6 +287,18 @@ raise exc.HTTPBadRequest("json is malformed.") self.http_client.put(url, headers=hdrs, data=data) + def remove_external_location(self, artifact_id, blob_property, + type_name=None): + """Remove external location. + + :param artifact_id: ID of the artifact with external location + to be removed + :param blob_property: blob property name + """ + type_name = self._check_type_name(type_name) + url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property) + self.http_client.delete(url) + def download_blob(self, artifact_id, blob_property, type_name=None, do_checksum=True): """Get blob data. diff -Nru python-glareclient-0.4.1/PKG-INFO python-glareclient-0.5.2/PKG-INFO --- python-glareclient-0.4.1/PKG-INFO 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/PKG-INFO 2018-01-18 12:20:05.000000000 +0000 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: python-glareclient -Version: 0.4.1 +Version: 0.5.2 Summary: Glare Artifact Repository Home-page: http://docs.openstack.org/developer/python-glareclient Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: Python bindings to the Glare Artifact Repository ================================================ diff -Nru python-glareclient-0.4.1/python_glareclient.egg-info/entry_points.txt python-glareclient-0.5.2/python_glareclient.egg-info/entry_points.txt --- python-glareclient-0.4.1/python_glareclient.egg-info/entry_points.txt 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/python_glareclient.egg-info/entry_points.txt 2018-01-18 12:20:04.000000000 +0000 @@ -12,6 +12,7 @@ artifact_location = glareclient.osc.v1.blobs:AddLocation artifact_publish = glareclient.osc.v1.artifacts:PublishArtifact artifact_reactivate = glareclient.osc.v1.artifacts:ReactivateArtifact +artifact_remove-location = glareclient.osc.v1.blobs:RemoveLocation artifact_remove_tag = glareclient.osc.v1.artifacts:RemoveTag artifact_schema = glareclient.osc.v1.artifacts:TypeSchema artifact_show = glareclient.osc.v1.artifacts:ShowArtifact diff -Nru python-glareclient-0.4.1/python_glareclient.egg-info/pbr.json python-glareclient-0.5.2/python_glareclient.egg-info/pbr.json --- python-glareclient-0.4.1/python_glareclient.egg-info/pbr.json 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/python_glareclient.egg-info/pbr.json 2018-01-18 12:20:04.000000000 +0000 @@ -1 +1 @@ -{"git_version": "3644d2d", "is_release": true} \ No newline at end of file +{"git_version": "6da299f", "is_release": true} \ No newline at end of file diff -Nru python-glareclient-0.4.1/python_glareclient.egg-info/PKG-INFO python-glareclient-0.5.2/python_glareclient.egg-info/PKG-INFO --- python-glareclient-0.4.1/python_glareclient.egg-info/PKG-INFO 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/python_glareclient.egg-info/PKG-INFO 2018-01-18 12:20:04.000000000 +0000 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: python-glareclient -Version: 0.4.1 +Version: 0.5.2 Summary: Glare Artifact Repository Home-page: http://docs.openstack.org/developer/python-glareclient Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: Python bindings to the Glare Artifact Repository ================================================ diff -Nru python-glareclient-0.4.1/python_glareclient.egg-info/requires.txt python-glareclient-0.5.2/python_glareclient.egg-info/requires.txt --- python-glareclient-0.4.1/python_glareclient.egg-info/requires.txt 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/python_glareclient.egg-info/requires.txt 2018-01-18 12:20:04.000000000 +0000 @@ -1,10 +1,10 @@ -pbr>=1.8 -Babel>=2.3.4 +pbr!=2.1.0,>=2.0.0 +Babel!=2.4.0,>=2.3.4 PrettyTable<0.8,>=0.7.1 -keystoneauth1>=2.18.0 -requests!=2.12.2,!=2.13.0,>=2.10.0 +keystoneauth1>=3.2.0 +requests>=2.14.2 six>=1.9.0 -oslo.utils>=3.18.0 -oslo.i18n>=2.1.0 -oslo.log>=3.11.0 -osc-lib>=1.2.0 +oslo.utils>=3.31.0 +oslo.i18n>=3.15.3 +oslo.log>=3.30.0 +osc-lib>=1.7.0 diff -Nru python-glareclient-0.4.1/python_glareclient.egg-info/SOURCES.txt python-glareclient-0.5.2/python_glareclient.egg-info/SOURCES.txt --- python-glareclient-0.4.1/python_glareclient.egg-info/SOURCES.txt 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/python_glareclient.egg-info/SOURCES.txt 2018-01-18 12:20:05.000000000 +0000 @@ -37,6 +37,7 @@ glareclient/tests/unit/fakes.py glareclient/tests/unit/test_common_http.py glareclient/tests/unit/test_progressbar.py +glareclient/tests/unit/test_shell.py glareclient/tests/unit/test_utils.py glareclient/tests/unit/osc/__init__.py glareclient/tests/unit/osc/test_plugin.py @@ -73,5 +74,4 @@ releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder tools/glare.bash_completion -tools/tox_install.sh tools/with_venv.sh \ No newline at end of file diff -Nru python-glareclient-0.4.1/releasenotes/source/conf.py python-glareclient-0.5.2/releasenotes/source/conf.py --- python-glareclient-0.4.1/releasenotes/source/conf.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/releasenotes/source/conf.py 2018-01-18 12:17:09.000000000 +0000 @@ -58,17 +58,11 @@ project = u'glareclient Release Notes' copyright = u'2016, Glare Developers' -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -import pbr.version +# Release notes are version independent. # The full version, including alpha/beta/rc tags. -glare_version = pbr.version.VersionInfo('glareclient') -release = glare_version.version_string_with_vcs() +release = '' # The short X.Y version. -version = glare_version.canonical_version_string() +version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -Nru python-glareclient-0.4.1/requirements.txt python-glareclient-0.5.2/requirements.txt --- python-glareclient-0.4.1/requirements.txt 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/requirements.txt 2018-01-18 12:17:09.000000000 +0000 @@ -1,13 +1,13 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.8 # Apache-2.0 -Babel>=2.3.4 # BSD +pbr!=2.1.0,>=2.0.0 # Apache-2.0 +Babel!=2.4.0,>=2.3.4 # BSD PrettyTable<0.8,>=0.7.1 # BSD -keystoneauth1>=2.18.0 # Apache-2.0 -requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0 +keystoneauth1>=3.2.0 # Apache-2.0 +requests>=2.14.2 # Apache-2.0 six>=1.9.0 # MIT -oslo.utils>=3.18.0 # Apache-2.0 -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.log>=3.11.0 # Apache-2.0 -osc-lib>=1.2.0 # Apache-2.0 +oslo.utils>=3.31.0 # Apache-2.0 +oslo.i18n>=3.15.3 # Apache-2.0 +oslo.log>=3.30.0 # Apache-2.0 +osc-lib>=1.7.0 # Apache-2.0 diff -Nru python-glareclient-0.4.1/setup.cfg python-glareclient-0.5.2/setup.cfg --- python-glareclient-0.4.1/setup.cfg 2017-06-27 22:56:27.000000000 +0000 +++ python-glareclient-0.5.2/setup.cfg 2018-01-18 12:20:05.000000000 +0000 @@ -47,6 +47,7 @@ artifact_publish = glareclient.osc.v1.artifacts:PublishArtifact artifact_upload = glareclient.osc.v1.blobs:UploadBlob artifact_location = glareclient.osc.v1.blobs:AddLocation + artifact_remove-location = glareclient.osc.v1.blobs:RemoveLocation artifact_download = glareclient.osc.v1.blobs:DownloadBlob artifact_type-list = glareclient.osc.v1.artifacts:TypeList artifact_schema = glareclient.osc.v1.artifacts:TypeSchema diff -Nru python-glareclient-0.4.1/setup.py python-glareclient-0.5.2/setup.py --- python-glareclient-0.4.1/setup.py 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/setup.py 2018-01-18 12:17:09.000000000 +0000 @@ -25,5 +25,5 @@ pass setuptools.setup( - setup_requires=['pbr>=1.8'], + setup_requires=['pbr>=2.0.0'], pbr=True) diff -Nru python-glareclient-0.4.1/test-requirements.txt python-glareclient-0.5.2/test-requirements.txt --- python-glareclient-0.4.1/test-requirements.txt 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/test-requirements.txt 2018-01-18 12:17:09.000000000 +0000 @@ -1,17 +1,17 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking>=0.12.0,!=0.13.0,<0.14 # Apache-2.0 +hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -coverage>=4.0 # Apache-2.0 -mock>=2.0 # BSD -ordereddict # MIT -os-client-config>=1.22.0 # Apache-2.0 +coverage!=4.4,>=4.0 # Apache-2.0 +mock>=2.0.0 # BSD +ordereddict>=1.1 # MIT +os-client-config>=1.28.0 # Apache-2.0 oslosphinx>=4.7.0 # Apache-2.0 -reno>=1.8.0 # Apache-2.0 -sphinx>=1.5.1 # BSD +reno>=2.5.0 # Apache-2.0 +sphinx>=1.6.2 # BSD testrepository>=0.0.18 # Apache-2.0/BSD testtools>=1.4.0 # MIT testscenarios>=0.4 # Apache-2.0/BSD fixtures>=3.0.0 # Apache-2.0/BSD -requests-mock>=1.1 # Apache-2.0 +requests-mock>=1.1.0 # Apache-2.0 diff -Nru python-glareclient-0.4.1/tools/tox_install.sh python-glareclient-0.5.2/tools/tox_install.sh --- python-glareclient-0.4.1/tools/tox_install.sh 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/tools/tox_install.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should replace the version pin in -# the constraints file before applying it for from-source installation. - -ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner -BRANCH_NAME=master -CLIENT_NAME=python-glareclient -requirements_installed=$(echo "import openstack_requirements" | python 2>/dev/null ; echo $?) - -set -e - -CONSTRAINTS_FILE=$1 -shift - -install_cmd="pip install" -if [ $CONSTRAINTS_FILE != "unconstrained" ]; then - - mydir=$(mktemp -dt "$CLIENT_NAME-tox_install-XXXXXXX") - localfile=$mydir/upper-constraints.txt - if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE - fi - curl $CONSTRAINTS_FILE -k -o $localfile - install_cmd="$install_cmd -c$localfile" - - if [ $requirements_installed -eq 0 ]; then - echo "ALREADY INSTALLED" > /tmp/tox_install.txt - echo "Requirements already installed; using existing package" - elif [ -x "$ZUUL_CLONER" ]; then - export ZUUL_BRANCH=${ZUUL_BRANCH-$BRANCH} - echo "ZUUL CLONER" > /tmp/tox_install.txt - pushd $mydir - $ZUUL_CLONER --cache-dir \ - /opt/git \ - --branch $BRANCH_NAME \ - git://git.openstack.org \ - openstack/requirements - cd openstack/requirements - $install_cmd -e . - popd - else - echo "PIP HARDCODE" > /tmp/tox_install.txt - if [ -z "$REQUIREMENTS_PIP_LOCATION" ]; then - REQUIREMENTS_PIP_LOCATION="git+https://git.openstack.org/openstack/requirements@$BRANCH_NAME#egg=requirements" - fi - $install_cmd -U -e ${REQUIREMENTS_PIP_LOCATION} - fi - - edit-constraints $localfile -- $CLIENT_NAME "-e file://$PWD#egg=$CLIENT_NAME" -fi - -$install_cmd -U $* -exit $? diff -Nru python-glareclient-0.4.1/tox.ini python-glareclient-0.5.2/tox.ini --- python-glareclient-0.4.1/tox.ini 2017-06-27 22:54:56.000000000 +0000 +++ python-glareclient-0.5.2/tox.ini 2018-01-18 12:17:09.000000000 +0000 @@ -5,15 +5,16 @@ [testenv] usedevelop = True -install_command = - {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} +install_command = pip install {opts} {packages} setenv = VIRTUAL_ENV={envdir} OS_STDOUT_NOCAPTURE=False OS_STDERR_NOCAPTURE=False PYTHONHASHSEED=0 PYTHONDONTWRITEBYTECODE = 1 -deps = -r{toxinidir}/requirements.txt +deps = + -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} + -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = python setup.py testr --testr-args='{posargs}'