From 7c91dee42575b1203a935e5e81c72cf6ddaeab38 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:00:07 +0200 Subject: [PATCH 01/15] implement support for unix:// address Signed-off-by: Steven Armstrong --- consul/aio.py | 16 +++++++--- consul/base.py | 79 ++++++++++++++++++++++++++++++++-------------- consul/std.py | 18 +++++++++-- consul/tornado.py | 5 +-- consul/twisted.py | 8 ++--- requirements.txt | 1 + tests/test_base.py | 75 ++++++++++++++++++++++++++++++++++++++++--- tests/test_std.py | 2 +- 8 files changed, 161 insertions(+), 43 deletions(-) diff --git a/consul/aio.py b/consul/aio.py index 5e347f53..c35fb84d 100644 --- a/consul/aio.py +++ b/consul/aio.py @@ -3,6 +3,8 @@ import asyncio import warnings +from six.moves import urllib + import aiohttp from consul import base @@ -17,7 +19,13 @@ class HTTPClient(base.HTTPClient): def __init__(self, *args, loop=None, **kwargs): super(HTTPClient, self).__init__(*args, **kwargs) self._loop = loop or asyncio.get_event_loop() - connector = aiohttp.TCPConnector(loop=self._loop, + if 'unix://' in self.base_uri: + pr = urllib.parse.urlparse(self.base_uri) + self.base_uri = 'http://consul' + connector = aiohttp.UnixConnector(loop=self._loop, + path=pr.path) + else: + connector = aiohttp.TCPConnector(loop=self._loop, verify_ssl=self.verify) self._session = aiohttp.ClientSession(connector=connector) @@ -64,9 +72,9 @@ def __init__(self, *args, loop=None, **kwargs): self._loop = loop or asyncio.get_event_loop() super().__init__(*args, **kwargs) - def connect(self, host, port, scheme, verify=True, cert=None): - return HTTPClient(host, port, scheme, loop=self._loop, - verify=verify, cert=None) + def connect(self, base_uri, verify=True, cert=None, auth=None): + return HTTPClient(base_uri, loop=self._loop, + verify=verify, cert=cert, auth=auth) def close(self): """Close all opened http connections""" diff --git a/consul/base.py b/consul/base.py index ee6ab254..893ec6bf 100755 --- a/consul/base.py +++ b/consul/base.py @@ -246,14 +246,11 @@ def cb(response): class HTTPClient(six.with_metaclass(abc.ABCMeta, object)): - def __init__(self, host='127.0.0.1', port=8500, scheme='http', - verify=True, cert=None): - self.host = host - self.port = port - self.scheme = scheme + def __init__(self, base_uri, verify=True, cert=None, auth=None): + self.base_uri = base_uri self.verify = verify - self.base_uri = '%s://%s:%s' % (self.scheme, self.host, self.port) self.cert = cert + self.auth = auth def uri(self, path, params=None): uri = self.base_uri + urllib.parse.quote(path, safe='/:') @@ -288,7 +285,9 @@ def __init__( consistency='default', dc=None, verify=True, - cert=None): + cert=None, + auth=None, + addr=None): """ *token* is an optional `ACL token`_. If supplied it will be used by default for all requests made with this client session. It's still @@ -305,27 +304,19 @@ def __init__( *verify* is whether to verify the SSL certificate for HTTPS requests - *cert* client side certificates for HTTPS requests + *cert* tuple containing client certificate and key for HTTPS requests + + *addr* url to use instead of host, port and scheme. + e.g. unix:///var/run/consul/http.sock, http://localhost:8500/ """ # TODO: Status - if os.getenv('CONSUL_HTTP_ADDR'): - try: - host, port = os.getenv('CONSUL_HTTP_ADDR').split(':') - except ValueError: - raise ConsulException('CONSUL_HTTP_ADDR (%s) invalid, ' - 'does not match :' - % os.getenv('CONSUL_HTTP_ADDR')) - use_ssl = os.getenv('CONSUL_HTTP_SSL') - if use_ssl is not None: - scheme = 'https' if use_ssl == 'true' else 'http' - if os.getenv('CONSUL_HTTP_SSL_VERIFY') is not None: - verify = os.getenv('CONSUL_HTTP_SSL_VERIFY') == 'true' - - self.http = self.connect(host, port, scheme, verify, cert) - self.token = os.getenv('CONSUL_HTTP_TOKEN', token) - self.scheme = scheme + if not addr: + addr = '{0}://{1}:{2}'.format(scheme, host, port) + + self.http = self.connect(addr, verify=verify, cert=cert, auth=auth) + self.token = token self.dc = dc assert consistency in ('default', 'consistent', 'stale'), \ 'consistency must be either default, consistent or state' @@ -344,6 +335,46 @@ def __init__( self.coordinate = Consul.Coordinate(self) self.operator = Consul.Operator(self) + + @classmethod + def from_env(cls, consistency='default', dc=None): + """ + Return a client configured from environment variables. + The environment variables used are the same as those used by the + consul command-line client. Refer to the consul documentation [1] for + a list of existing environment variables. + + Additionally all supported given keyword arguments are passed on the + client constructor. + + [1] https://www.consul.io/docs/commands/index.html#environment-variables + """ + oe = os.environ + kwargs = { + 'consistency': consistency, + 'dc': dc, + 'addr': oe.get('CONSUL_HTTP_ADDR', None), + 'verify': oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', False)), + 'token': oe.get('CONSUL_HTTP_TOKEN', None), + } + verify = oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', None)) + if verify: + if verify == 'false': + verify = False + elif verify == 'true': + verify = True + kwargs['verify'] = verify + + if 'CONSUL_CLIENT_CERT' in oe \ + and 'CONSUL_CLIENT_KEY' in oe: + kwargs['cert'] = (oe['CONSUL_CLIENT_CERT'], oe['CONSUL_CLIENT_KEY']) + + if 'CONSUL_HTTP_AUTH' in oe: + kwargs['auth'] = oe['CONSUL_HTTP_AUTH'].split(':') + + return cls(**kwargs) + + class Event(object): """ The event command provides a mechanism to fire a custom user event to diff --git a/consul/std.py b/consul/std.py index 96a5b9dc..f860562e 100644 --- a/consul/std.py +++ b/consul/std.py @@ -1,5 +1,7 @@ import requests +from six.moves import urllib + from consul import base @@ -9,7 +11,17 @@ class HTTPClient(base.HTTPClient): def __init__(self, *args, **kwargs): super(HTTPClient, self).__init__(*args, **kwargs) - self.session = requests.session() + if 'unix://' in self.base_uri: + pr = urllib.parse.urlparse(self.base_uri) + netloc = urllib.parse.quote_plus(pr.path) + self.base_uri = 'http+unix://{0}'.format(netloc) + try: + import requests_unixsocket + self.session = requests_unixsocket.Session() + except ImportError: + raise ConsulException('To use a unix socket to connect to Consul you need to install the "requests_unixsocket" package.') + else: + self.session = requests.session() def response(self, response): response.encoding = 'utf-8' @@ -40,5 +52,5 @@ def post(self, callback, path, params=None, data=''): class Consul(base.Consul): - def connect(self, host, port, scheme, verify=True, cert=None): - return HTTPClient(host, port, scheme, verify, cert) + def connect(self, base_uri, verify=True, cert=None, auth=None): + return HTTPClient(base_uri, verify=verify, cert=cert, auth=auth) diff --git a/consul/tornado.py b/consul/tornado.py index 50507748..bb4d30f5 100644 --- a/consul/tornado.py +++ b/consul/tornado.py @@ -12,6 +12,7 @@ class HTTPClient(base.HTTPClient): def __init__(self, *args, **kwargs): super(HTTPClient, self).__init__(*args, **kwargs) + # TODO: support for unix:// uris self.client = httpclient.AsyncHTTPClient() def response(self, response): @@ -53,5 +54,5 @@ def post(self, callback, path, params=None, data=''): class Consul(base.Consul): - def connect(self, host, port, scheme, verify=True, cert=None): - return HTTPClient(host, port, scheme, verify=verify, cert=cert) + def connect(self, base_uri, verify=True, cert=None, auth=None): + return HTTPClient(base_uri, verify=verify, cert=cert, auth=auth) diff --git a/consul/twisted.py b/consul/twisted.py index 206105cb..6f50c4c0 100644 --- a/consul/twisted.py +++ b/consul/twisted.py @@ -34,6 +34,7 @@ def getContext(self, hostname, port): class HTTPClient(base.HTTPClient): def __init__(self, contextFactory, *args, **kwargs): super(HTTPClient, self).__init__(*args, **kwargs) + # TODO: support for unix:// uris agent_kwargs = dict( reactor=reactor, pool=HTTPConnectionPool(reactor)) if contextFactory is not None: @@ -125,13 +126,12 @@ def delete(self, callback, path, params=None): class Consul(base.Consul): @staticmethod - def connect(host, - port, - scheme, + def connect(base_uri, verify=True, cert=None, + auth=None, contextFactory=None, **kwargs): return HTTPClient( - contextFactory, host, port, scheme, verify=verify, cert=cert, + contextFactory, base_uri, verify=verify, cert=cert, auth=auth, **kwargs) diff --git a/requirements.txt b/requirements.txt index 2846886d..ce3023dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests>=2.0 +requests-unixsocket>=0.1.5 six>=1.4 diff --git a/tests/test_base.py b/tests/test_base.py index ef76a9fa..5172a508 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,5 +1,7 @@ import collections +from contextlib import contextmanager import json +import os import pytest @@ -14,9 +16,11 @@ class HTTPClient(object): - def __init__(self, host=None, port=None, scheme=None, - verify=True, cert=None): - pass + def __init__(self, base_uri, verify=True, cert=None, auth=None): + self.base_uri = base_uri + self.verify = verify + self.cert = cert + self.auth = auth def get(self, callback, path, params=None): return Request('get', path, params, None) @@ -29,8 +33,69 @@ def delete(self, callback, path, params=None): class Consul(consul.base.Consul): - def connect(self, host, port, scheme, verify=True, cert=None): - return HTTPClient(host, port, scheme, verify=verify, cert=None) + def connect(self, base_uri, verify=True, cert=None, auth=None): + return HTTPClient(base_uri, verify=verify, cert=cert, auth=auth) + + + +class TestEnvironment(object): + + @contextmanager + def environ(self, **env): + original_env = {key: os.getenv(key) for key in env} + os.environ.update(env) + try: + yield + finally: + for key, value in original_env.items(): + if value is None: + del os.environ[key] + else: + os.environ[key] = value + + def test_CONSUL_HTTP_ADDR(self): + CONSUL_HTTP_ADDR = 'http://127.0.0.23:4242' + with self.environ(CONSUL_HTTP_ADDR=CONSUL_HTTP_ADDR): + c = Consul.from_env() + assert c.http.base_uri == CONSUL_HTTP_ADDR + + def test_CONSUL_HTTP_TOKEN(self): + CONSUL_HTTP_TOKEN = '1bdc2cb4-9b02-4b3c-9df5-eb86214e1a6c' + with self.environ(CONSUL_HTTP_TOKEN=CONSUL_HTTP_TOKEN): + c = Consul.from_env() + assert c.token == CONSUL_HTTP_TOKEN + + def test_cert(self): + CONSUL_CLIENT_CERT = '/path/to/client.crt' + CONSUL_CLIENT_KEY = '/path/to/client.key' + with self.environ(CONSUL_CLIENT_CERT=CONSUL_CLIENT_CERT, + CONSUL_CLIENT_KEY=CONSUL_CLIENT_KEY): + c = Consul.from_env() + assert c.http.cert == (CONSUL_CLIENT_CERT, CONSUL_CLIENT_KEY) + + def test_CONSUL_HTTP_AUTH(self): + CONSUL_HTTP_AUTH = 'username:s3cr3t' + with self.environ(CONSUL_HTTP_AUTH=CONSUL_HTTP_AUTH): + c = Consul.from_env() + assert c.http.auth == CONSUL_HTTP_AUTH.split(':') + + def test_CONSUL_HTTP_SSL_VERIFY_True(self): + CONSUL_HTTP_SSL_VERIFY = 'true' + with self.environ(CONSUL_HTTP_SSL_VERIFY=CONSUL_HTTP_SSL_VERIFY): + c = Consul.from_env() + assert c.http.verify == True + + def test_CONSUL_HTTP_SSL_VERIFY_False(self): + CONSUL_HTTP_SSL_VERIFY = 'false' + with self.environ(CONSUL_HTTP_SSL_VERIFY=CONSUL_HTTP_SSL_VERIFY): + c = Consul.from_env() + assert c.http.verify == False + + def test_CONSUL_CACERT(self): + CONSUL_CACERT = '/path/to/ca.crt' + with self.environ(CONSUL_CACERT=CONSUL_CACERT): + c = Consul.from_env() + assert c.http.verify == CONSUL_CACERT def _should_support(c): diff --git a/tests/test_std.py b/tests/test_std.py index 6aef1e72..552723fe 100644 --- a/tests/test_std.py +++ b/tests/test_std.py @@ -15,7 +15,7 @@ class TestHTTPClient(object): def test_uri(self): - http = consul.std.HTTPClient() + http = consul.std.HTTPClient('http://127.0.0.1:8500') assert http.uri('/v1/kv') == 'http://127.0.0.1:8500/v1/kv' assert http.uri('/v1/kv', params={'index': 1}) == \ 'http://127.0.0.1:8500/v1/kv?index=1' From fba532a430264b0287f27854e352e99e5b510a1f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:06:09 +0200 Subject: [PATCH 02/15] add example for from_env() Signed-off-by: Steven Armstrong --- README.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.rst b/README.rst index 6ae8da63..7ff5bcf3 100644 --- a/README.rst +++ b/README.rst @@ -19,6 +19,8 @@ Example import consul c = consul.Consul() + # alternatively create client from envrionment variables + # c = consul.Consul.from_env() # poll a key for updates index = None @@ -29,6 +31,17 @@ Example # in another process c.kv.put('foo', 'bar') +.. code:: python + + import consul + + # Alternatively create a client from the same environment variables that the + # consul command line client uses. e.g. CONSUL_HTTP_ADDR, CONSUL_HTTP_TOKEN + c = consul.Consul.from_env() + + c.agent.self() + + Installation ------------ From 11558b17f19a316107f25ebbe090337d9ced9225 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:07:47 +0200 Subject: [PATCH 03/15] add link to consul env vars Signed-off-by: Steven Armstrong --- README.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 7ff5bcf3..f0fc6d87 100644 --- a/README.rst +++ b/README.rst @@ -19,8 +19,6 @@ Example import consul c = consul.Consul() - # alternatively create client from envrionment variables - # c = consul.Consul.from_env() # poll a key for updates index = None @@ -31,12 +29,15 @@ Example # in another process c.kv.put('foo', 'bar') + +Alternatively you can create a client from the same environment variables that +the consul command line client uses. e.g. CONSUL_HTTP_ADDR, CONSUL_HTTP_TOKEN +See https://www.consul.io/docs/commands/index.html#environment-variables + .. code:: python import consul - # Alternatively create a client from the same environment variables that the - # consul command line client uses. e.g. CONSUL_HTTP_ADDR, CONSUL_HTTP_TOKEN c = consul.Consul.from_env() c.agent.self() From 9965d4af1e49e7347a531c746e93fd499aff9409 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:10:10 +0200 Subject: [PATCH 04/15] properly format link Signed-off-by: Steven Armstrong --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index f0fc6d87..a5b61355 100644 --- a/README.rst +++ b/README.rst @@ -30,9 +30,8 @@ Example c.kv.put('foo', 'bar') -Alternatively you can create a client from the same environment variables that -the consul command line client uses. e.g. CONSUL_HTTP_ADDR, CONSUL_HTTP_TOKEN -See https://www.consul.io/docs/commands/index.html#environment-variables +Alternatively you can create a client from the same `environment variables`_ that +the consul command line client uses. e.g. CONSUL_HTTP_ADDR, CONSUL_HTTP_TOKEN. .. code:: python @@ -59,6 +58,7 @@ Installation image:: https://img.shields.io/coveralls/cablehead/python-consul.svg?style=flat-square :target: https://coveralls.io/r/cablehead/python-consul?branch=master .. _Read the Docs: https://python-consul.readthedocs.io/ +.. _environment variables: https://www.consul.io/docs/commands/index.html#environment-variables Status ------ From 88b1ced42a079184148bf44b4edcca77199e2b42 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:25:31 +0200 Subject: [PATCH 05/15] remove initial legacy env handling of verify Signed-off-by: Steven Armstrong --- consul/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/consul/base.py b/consul/base.py index 893ec6bf..91c7652d 100755 --- a/consul/base.py +++ b/consul/base.py @@ -354,7 +354,6 @@ def from_env(cls, consistency='default', dc=None): 'consistency': consistency, 'dc': dc, 'addr': oe.get('CONSUL_HTTP_ADDR', None), - 'verify': oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', False)), 'token': oe.get('CONSUL_HTTP_TOKEN', None), } verify = oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', None)) From e843148927dc865edd3bce771bc73b970df14a45 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:28:19 +0200 Subject: [PATCH 06/15] qualified name for exception Signed-off-by: Steven Armstrong --- consul/std.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consul/std.py b/consul/std.py index f860562e..d997798b 100644 --- a/consul/std.py +++ b/consul/std.py @@ -19,7 +19,7 @@ def __init__(self, *args, **kwargs): import requests_unixsocket self.session = requests_unixsocket.Session() except ImportError: - raise ConsulException('To use a unix socket to connect to Consul you need to install the "requests_unixsocket" package.') + raise base.ConsulException('To use a unix socket to connect to Consul you need to install the "requests_unixsocket" package.') else: self.session = requests.session() From c1f0bf0ae84b4865f7e4190c5faaba9fc8c91017 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 30 Jun 2018 01:48:20 +0200 Subject: [PATCH 07/15] python 2.6 support Signed-off-by: Steven Armstrong --- tests/test_base.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 5172a508..11f0d30d 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -42,12 +42,14 @@ class TestEnvironment(object): @contextmanager def environ(self, **env): - original_env = {key: os.getenv(key) for key in env} + original_env = {} + for key in env: + original_env[key] = os.getenv(key) os.environ.update(env) try: yield finally: - for key, value in original_env.items(): + for key,value in original_env.items(): if value is None: del os.environ[key] else: From 59f5fc0e3b7b4a95f84c4cdfe62cc273efdba1a8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 2 Jul 2018 13:52:27 +0200 Subject: [PATCH 08/15] fix flake8 tests for python 3.5 Signed-off-by: Steven Armstrong --- consul/aio.py | 2 +- consul/base.py | 12 ++++++------ consul/std.py | 3 ++- tests/test_base.py | 3 +-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/consul/aio.py b/consul/aio.py index c35fb84d..54554ebb 100644 --- a/consul/aio.py +++ b/consul/aio.py @@ -26,7 +26,7 @@ def __init__(self, *args, loop=None, **kwargs): path=pr.path) else: connector = aiohttp.TCPConnector(loop=self._loop, - verify_ssl=self.verify) + verify_ssl=self.verify) self._session = aiohttp.ClientSession(connector=connector) @asyncio.coroutine diff --git a/consul/base.py b/consul/base.py index 91c7652d..fd7c469c 100755 --- a/consul/base.py +++ b/consul/base.py @@ -335,7 +335,6 @@ def __init__( self.coordinate = Consul.Coordinate(self) self.operator = Consul.Operator(self) - @classmethod def from_env(cls, consistency='default', dc=None): """ @@ -347,7 +346,7 @@ def from_env(cls, consistency='default', dc=None): Additionally all supported given keyword arguments are passed on the client constructor. - [1] https://www.consul.io/docs/commands/index.html#environment-variables + [1] https://www.consul.io/docs/commands/index.html#environment-variables # noqa: E501 """ oe = os.environ kwargs = { @@ -356,7 +355,8 @@ def from_env(cls, consistency='default', dc=None): 'addr': oe.get('CONSUL_HTTP_ADDR', None), 'token': oe.get('CONSUL_HTTP_TOKEN', None), } - verify = oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', None)) + verify = oe.get('CONSUL_CACERT', + oe.get('CONSUL_HTTP_SSL_VERIFY', None)) if verify: if verify == 'false': verify = False @@ -365,15 +365,15 @@ def from_env(cls, consistency='default', dc=None): kwargs['verify'] = verify if 'CONSUL_CLIENT_CERT' in oe \ - and 'CONSUL_CLIENT_KEY' in oe: - kwargs['cert'] = (oe['CONSUL_CLIENT_CERT'], oe['CONSUL_CLIENT_KEY']) + and 'CONSUL_CLIENT_KEY' in oe: + kwargs['cert'] = (oe['CONSUL_CLIENT_CERT'], + oe['CONSUL_CLIENT_KEY']) if 'CONSUL_HTTP_AUTH' in oe: kwargs['auth'] = oe['CONSUL_HTTP_AUTH'].split(':') return cls(**kwargs) - class Event(object): """ The event command provides a mechanism to fire a custom user event to diff --git a/consul/std.py b/consul/std.py index d997798b..44c4e9b8 100644 --- a/consul/std.py +++ b/consul/std.py @@ -19,7 +19,8 @@ def __init__(self, *args, **kwargs): import requests_unixsocket self.session = requests_unixsocket.Session() except ImportError: - raise base.ConsulException('To use a unix socket to connect to Consul you need to install the "requests_unixsocket" package.') + raise base.ConsulException('To use a unix socket to connect to' + 'Consul you need to install the "requests_unixsocket" package.') else: self.session = requests.session() diff --git a/tests/test_base.py b/tests/test_base.py index 11f0d30d..14a187a7 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -37,7 +37,6 @@ def connect(self, base_uri, verify=True, cert=None, auth=None): return HTTPClient(base_uri, verify=verify, cert=cert, auth=auth) - class TestEnvironment(object): @contextmanager @@ -49,7 +48,7 @@ def environ(self, **env): try: yield finally: - for key,value in original_env.items(): + for key, value in original_env.items(): if value is None: del os.environ[key] else: From 93831cb2c7ae95fb09a071c584f2d300652da65b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Jul 2018 23:31:34 +0200 Subject: [PATCH 09/15] start refactoring tests for parametrization of consul client Replaced most of the boilerplate code that creates a consul client to run tests with fixtures. Prepare for testing with consul clients that can not work with the consul_port fixture, e.g. when using a unix socket. Signed-off-by: Steven Armstrong --- tests/test_aio.py | 38 +++++------- tests/test_std.py | 134 ++++++++++++++---------------------------- tests/test_tornado.py | 44 ++++++-------- tests/test_twisted.py | 41 ++++++------- 4 files changed, 94 insertions(+), 163 deletions(-) diff --git a/tests/test_aio.py b/tests/test_aio.py index b251231f..374ccc5b 100644 --- a/tests/test_aio.py +++ b/tests/test_aio.py @@ -24,13 +24,17 @@ def fin(): return loop +@pytest.fixture +def c(consul_port, loop): + return consul.aio.Consul(port=consul_port, loop=loop) + + class TestAsyncioConsul(object): - def test_kv(self, loop, consul_port): + def test_kv(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) print(c) index, data = yield from c.kv.get('foo') @@ -44,11 +48,10 @@ def main(): loop.run_until_complete(main()) - def test_consul_ctor(self, loop, consul_port): + def test_consul_ctor(self, loop, c): # same as previous but with global event loop @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port) assert c._loop is loop yield from c.kv.put('foo', struct.pack('i', 1000)) index, data = yield from c.kv.get('foo') @@ -58,10 +61,9 @@ def main(): asyncio.set_event_loop(loop) loop.run_until_complete(main()) - def test_kv_binary(self, loop, consul_port): + def test_kv_binary(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) yield from c.kv.put('foo', struct.pack('i', 1000)) index, data = yield from c.kv.get('foo') assert struct.unpack('i', data['Value']) == (1000,) @@ -69,8 +71,7 @@ def main(): loop.run_until_complete(main()) - def test_kv_missing(self, loop, consul_port): - c = consul.aio.Consul(port=consul_port, loop=loop) + def test_kv_missing(self, loop, c): @asyncio.coroutine def main(): @@ -90,10 +91,9 @@ def put(): loop.run_until_complete(main()) - def test_kv_put_flags(self, loop, consul_port): + def test_kv_put_flags(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) yield from c.kv.put('foo', 'bar') index, data = yield from c.kv.get('foo') assert data['Flags'] == 0 @@ -106,10 +106,9 @@ def main(): loop.run_until_complete(main()) - def test_kv_delete(self, loop, consul_port): + def test_kv_delete(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) yield from c.kv.put('foo1', '1') yield from c.kv.put('foo2', '2') yield from c.kv.put('foo3', '3') @@ -128,8 +127,7 @@ def main(): loop.run_until_complete(main()) - def test_kv_subscribe(self, loop, consul_port): - c = consul.aio.Consul(port=consul_port, loop=loop) + def test_kv_subscribe(self, loop, c): @asyncio.coroutine def get(): @@ -149,10 +147,9 @@ def put(): loop.run_until_complete(get()) - def test_transaction(self, loop, consul_port): + def test_transaction(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) value = base64.b64encode(b"1").decode("utf8") d = {"KV": {"Verb": "set", "Key": "asdf", "Value": value}} r = yield from c.txn.put([d]) @@ -164,10 +161,9 @@ def main(): c.close() loop.run_until_complete(main()) - def test_agent_services(self, loop, consul_port): + def test_agent_services(self, loop, c): @asyncio.coroutine def main(): - c = consul.aio.Consul(port=consul_port, loop=loop) services = yield from c.agent.services() assert services == {} response = yield from c.agent.service.register('foo') @@ -192,8 +188,7 @@ def main(): loop.run_until_complete(main()) - def test_catalog(self, loop, consul_port): - c = consul.aio.Consul(port=consul_port, loop=loop) + def test_catalog(self, loop, c): @asyncio.coroutine def nodes(): @@ -223,8 +218,7 @@ def register(): loop.run_until_complete(nodes()) - def test_session(self, loop, consul_port): - c = consul.aio.Consul(port=consul_port, loop=loop) + def test_session(self, loop, c): @asyncio.coroutine def monitor(): diff --git a/tests/test_std.py b/tests/test_std.py index 552723fe..74884b1e 100644 --- a/tests/test_std.py +++ b/tests/test_std.py @@ -13,6 +13,11 @@ Check = consul.Check +@pytest.fixture +def c(consul_port): + return consul.Consul(port=consul_port) + + class TestHTTPClient(object): def test_uri(self): http = consul.std.HTTPClient('http://127.0.0.1:8500') @@ -22,24 +27,20 @@ def test_uri(self): class TestConsul(object): - def test_kv(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv(self, c): index, data = c.kv.get('foo') assert data is None assert c.kv.put('foo', 'bar') is True index, data = c.kv.get('foo') assert data['Value'] == six.b('bar') - def test_kv_wait(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv_wait(self, c): assert c.kv.put('foo', 'bar') is True index, data = c.kv.get('foo') check, data = c.kv.get('foo', index=index, wait='20ms') assert index == check - def test_kv_encoding(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_kv_encoding(self, c): # test binary c.kv.put('foo', struct.pack('i', 1000)) index, data = c.kv.get('foo') @@ -63,8 +64,7 @@ def test_kv_encoding(self, consul_port): # check unencoded values raises assert pytest.raises(AssertionError, c.kv.put, 'foo', {1: 2}) - def test_kv_put_cas(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv_put_cas(self, c): assert c.kv.put('foo', 'bar', cas=50) is False assert c.kv.put('foo', 'bar', cas=0) is True index, data = c.kv.get('foo') @@ -74,8 +74,7 @@ def test_kv_put_cas(self, consul_port): index, data = c.kv.get('foo') assert data['Value'] == six.b('bar2') - def test_kv_put_flags(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv_put_flags(self, c): c.kv.put('foo', 'bar') index, data = c.kv.get('foo') assert data['Flags'] == 0 @@ -84,8 +83,7 @@ def test_kv_put_flags(self, consul_port): index, data = c.kv.get('foo') assert data['Flags'] == 50 - def test_kv_recurse(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv_recurse(self, c): index, data = c.kv.get('foo/', recurse=True) assert data is None @@ -102,8 +100,7 @@ def test_kv_recurse(self, consul_port): assert [x['Value'] for x in data] == [ None, six.b('1'), six.b('2'), six.b('3')] - def test_kv_delete(self, consul_port): - c = consul.Consul(port=consul_port) + def test_kv_delete(self, c): c.kv.put('foo1', '1') c.kv.put('foo2', '2') c.kv.put('foo3', '3') @@ -117,9 +114,7 @@ def test_kv_delete(self, consul_port): index, data = c.kv.get('foo', recurse=True) assert data is None - def test_kv_delete_cas(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_kv_delete_cas(self, c): c.kv.put('foo', 'bar') index, data = c.kv.get('foo') @@ -130,9 +125,7 @@ def test_kv_delete_cas(self, consul_port): index, data = c.kv.get('foo') assert data is None - def test_kv_acquire_release(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_kv_acquire_release(self, c): pytest.raises( consul.ConsulException, c.kv.put, 'foo', 'bar', acquire='foo') @@ -149,9 +142,7 @@ def test_kv_acquire_release(self, consul_port): c.session.destroy(s1) c.session.destroy(s2) - def test_kv_keys_only(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_kv_keys_only(self, c): assert c.kv.put('bar', '4') is True assert c.kv.put('base/foo', '1') is True assert c.kv.put('base/base/foo', '5') is True @@ -159,8 +150,7 @@ def test_kv_keys_only(self, consul_port): index, data = c.kv.get('base/', keys=True, separator='/') assert data == ['base/base/', 'base/foo'] - def test_transaction(self, consul_port): - c = consul.Consul(port=consul_port) + def test_transaction(self, c): value = base64.b64encode(b"1").decode("utf8") d = {"KV": {"Verb": "set", "Key": "asdf", "Value": value}} r = c.txn.put([d]) @@ -170,17 +160,13 @@ def test_transaction(self, consul_port): r = c.txn.put([d]) assert r["Results"][0]["KV"]["Value"] == value - def test_event(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_event(self, c): assert c.event.fire("fooname", "foobody") index, events = c.event.list() assert [x['Name'] == 'fooname' for x in events] assert [x['Payload'] == 'foobody' for x in events] - def test_event_targeted(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_event_targeted(self, c): assert c.event.fire("fooname", "foobody") index, events = c.event.list(name="othername") assert events == [] @@ -189,8 +175,7 @@ def test_event_targeted(self, consul_port): assert [x['Name'] == 'fooname' for x in events] assert [x['Payload'] == 'foobody' for x in events] - def test_agent_checks(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_checks(self, c): def verify_and_dereg_check(check_id): assert set(c.agent.checks().keys()) == set([check_id]) @@ -219,7 +204,8 @@ def verify_check_status(check_id, status, notes=None): check_id='check_id') is True verify_and_dereg_check('check_id') - http_addr = "http://127.0.0.1:{0}".format(consul_port) + #http_addr = "http://127.0.0.1:{0}".format(c) + http_addr = c.http.base_uri assert c.agent.check.register( 'http_check', Check.http(http_addr, '10ms')) is True time.sleep(1) @@ -256,10 +242,9 @@ def verify_check_status(check_id, status, notes=None): verify_check_status('ttl_check', 'critical') verify_and_dereg_check('ttl_check') - def test_service_dereg_issue_156(self, consul_port): + def test_service_dereg_issue_156(self, c): # https://github.com/cablehead/python-consul/issues/156 service_name = 'app#127.0.0.1#3000' - c = consul.Consul(port=consul_port) c.agent.service.register(service_name) time.sleep(80/1000.0) @@ -275,8 +260,7 @@ def test_service_dereg_issue_156(self, consul_port): index, nodes = c.health.service(service_name) assert [node['Service']['ID'] for node in nodes] == [] - def test_agent_checks_service_id(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_checks_service_id(self, c): c.agent.service.register('foo1') time.sleep(40/1000.0) @@ -305,8 +289,7 @@ def test_agent_checks_service_id(self, consul_port): time.sleep(40/1000.0) - def test_agent_register_check_no_service_id(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_register_check_no_service_id(self, c): index, nodes = c.health.service("foo1") assert nodes == [] @@ -324,8 +307,7 @@ def test_agent_register_check_no_service_id(self, consul_port): time.sleep(40/1000.0) - def test_agent_register_enable_tag_override(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_register_enable_tag_override(self, c): index, nodes = c.health.service("foo1") assert nodes == [] @@ -335,9 +317,7 @@ def test_agent_register_enable_tag_override(self, consul_port): # Cleanup tasks c.agent.check.deregister('foo') - def test_agent_service_maintenance(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_agent_service_maintenance(self, c): c.agent.service.register('foo', check=Check.ttl('100ms')) time.sleep(40/1000.0) @@ -362,9 +342,7 @@ def test_agent_service_maintenance(self, consul_port): time.sleep(40/1000.0) - def test_agent_node_maintenance(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_agent_node_maintenance(self, c): c.agent.maintenance('true', "test") time.sleep(40/1000.0) @@ -380,8 +358,7 @@ def test_agent_node_maintenance(self, consul_port): checks_post = c.agent.checks() assert '_node_maintenance' not in checks_post.keys() - def test_agent_members(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_members(self, c): members = c.agent.members() for x in members: assert x['Status'] == 1 @@ -393,14 +370,12 @@ def test_agent_members(self, consul_port): for x in wan_members: assert 'dc1' in x['Name'] - def test_agent_self(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_self(self, c): assert set(c.agent.self().keys()) == set(['Member', 'Stats', 'Config', 'Coord', 'DebugConfig', 'Meta']) - def test_agent_services(self, consul_port): - c = consul.Consul(port=consul_port) + def test_agent_services(self, c): assert c.agent.service.register('foo') is True assert set(c.agent.services().keys()) == set(['foo']) assert c.agent.service.deregister('foo') is True @@ -413,9 +388,7 @@ def test_agent_services(self, consul_port): if k == 'foo'][0] == '10.10.10.1' assert c.agent.service.deregister('foo') is True - def test_catalog(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_catalog(self, c): # grab the node our server created, so we can ignore it _, nodes = c.catalog.nodes() assert len(nodes) == 1 @@ -486,9 +459,7 @@ def test_catalog(self, consul_port): nodes.remove(current) assert [x['Node'] for x in nodes] == [] - def test_health_service(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_health_service(self, c): # check there are no nodes for the service 'foo' index, nodes = c.health.service('foo') assert nodes == [] @@ -551,9 +522,7 @@ def test_health_service(self, consul_port): index, nodes = c.health.service('foo') assert nodes == [] - def test_health_state(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_health_state(self, c): # The empty string is for the Serf Health Status check, which has an # empty ServiceID index, nodes = c.health.state('any') @@ -614,16 +583,13 @@ def test_health_state(self, consul_port): index, nodes = c.health.state('any') assert [node['ServiceID'] for node in nodes] == [''] - def test_health_node(self, consul_port): - c = consul.Consul(port=consul_port) + def test_health_node(self, c): # grab local node name node = c.agent.self()['Config']['NodeName'] index, checks = c.health.node(node) assert node in [check["Node"] for check in checks] - def test_health_checks(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_health_checks(self, c): c.agent.service.register( 'foobar', service_id='foobar', check=Check.ttl('10s')) @@ -641,9 +607,7 @@ def test_health_checks(self, consul_port): index, checks = c.health.checks('foobar') assert len(checks) == 0 - def test_session(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_session(self, c): # session.create pytest.raises(consul.ConsulException, c.session.create, node='n2') pytest.raises(consul.ConsulException, c.session.create, dc='dc2') @@ -676,9 +640,7 @@ def test_session(self, consul_port): _, sessions = c.session.list() assert sessions == [] - def test_session_delete_ttl_renew(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_session_delete_ttl_renew(self, c): s = c.session.create(behavior='delete', ttl=20) # attempt to renew an unknown session @@ -697,8 +659,7 @@ def test_session_delete_ttl_renew(self, consul_port): index, data = c.kv.get('foo') assert data is None - def test_acl_disabled(self, consul_port): - c = consul.Consul(port=consul_port) + def test_acl_disabled(self, c): pytest.raises(consul.ACLDisabled, c.acl.list) pytest.raises(consul.ACLDisabled, c.acl.info, '1'*36) pytest.raises(consul.ACLDisabled, c.acl.create) @@ -866,9 +827,7 @@ def test_acl_implicit_token_use(self, acl_consul): assert set([x['ID'] for x in acls]) == \ set(['anonymous', master_token]) - def test_status_leader(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_status_leader(self, c): agent_self = c.agent.self() leader = c.status.leader() addr_port = agent_self['Stats']['consul']['leader_addr'] @@ -877,10 +836,7 @@ def test_status_leader(self, consul_port): "Leader value was {0}, expected value " \ "was {1}".format(leader, addr_port) - def test_status_peers(self, consul_port): - - c = consul.Consul(port=consul_port) - + def test_status_peers(self, c): agent_self = c.agent.self() addr_port = agent_self['Stats']['consul']['leader_addr'] @@ -890,9 +846,7 @@ def test_status_peers(self, consul_port): "Expected value '{0}' " \ "in peer list but it was not present".format(addr_port) - def test_query(self, consul_port): - c = consul.Consul(port=consul_port) - + def test_query(self, c): # check that query list is empty queries = c.query.list() assert queries == [] @@ -920,15 +874,13 @@ def test_query(self, consul_port): # delete query assert c.query.delete(query['ID']) - def test_coordinate(self, consul_port): - c = consul.Consul(port=consul_port) + def test_coordinate(self, c): c.coordinate.nodes() c.coordinate.datacenters() assert set(c.coordinate.datacenters()[0].keys()) == \ set(['Datacenter', 'Coordinates', 'AreaID']) - def test_operator(self, consul_port): - c = consul.Consul(port=consul_port) + def test_operator(self, c): config = c.operator.raft_config() assert config["Index"] == 1 leader = False diff --git a/tests/test_tornado.py b/tests/test_tornado.py index f69e5ead..75845ec1 100644 --- a/tests/test_tornado.py +++ b/tests/test_tornado.py @@ -22,6 +22,11 @@ def loop(): return loop +@pytest.fixture +def c(consul_port): + return consul.tornado.Consul(port=consul_port) + + def sleep(loop, s): result = gen.Future() loop.add_timeout( @@ -30,10 +35,9 @@ def sleep(loop, s): class TestConsul(object): - def test_kv(self, loop, consul_port): + def test_kv(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) index, data = yield c.kv.get('foo') assert data is None response = yield c.kv.put('foo', 'bar') @@ -43,18 +47,16 @@ def main(): loop.stop() loop.run_sync(main) - def test_kv_binary(self, loop, consul_port): + def test_kv_binary(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) yield c.kv.put('foo', struct.pack('i', 1000)) index, data = yield c.kv.get('foo') assert struct.unpack('i', data['Value']) == (1000,) loop.stop() loop.run_sync(main) - def test_kv_missing(self, loop, consul_port): - c = consul.tornado.Consul(port=consul_port) + def test_kv_missing(self, loop, c): @gen.coroutine def main(): @@ -72,10 +74,9 @@ def put(): loop.add_timeout(time.time()+(2.0/100), put) loop.run_sync(main) - def test_kv_put_flags(self, loop, consul_port): + def test_kv_put_flags(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) yield c.kv.put('foo', 'bar') index, data = yield c.kv.get('foo') assert data['Flags'] == 0 @@ -87,10 +88,9 @@ def main(): loop.stop() loop.run_sync(main) - def test_kv_delete(self, loop, consul_port): + def test_kv_delete(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) yield c.kv.put('foo1', '1') yield c.kv.put('foo2', '2') yield c.kv.put('foo3', '3') @@ -108,8 +108,7 @@ def main(): loop.stop() loop.run_sync(main) - def test_kv_subscribe(self, loop, consul_port): - c = consul.tornado.Consul(port=consul_port) + def test_kv_subscribe(self, loop, c): @gen.coroutine def get(): @@ -127,10 +126,9 @@ def put(): loop.add_timeout(time.time()+(1.0/100), put) loop.run_sync(get) - def test_kv_encoding(self, loop, consul_port): + def test_kv_encoding(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) # test binary response = yield c.kv.put('foo', struct.pack('i', 1000)) @@ -166,10 +164,9 @@ def main(): loop.stop() loop.run_sync(main) - def test_transaction(self, loop, consul_port): + def test_transaction(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) value = base64.b64encode(b"1").decode("utf8") d = {"KV": {"Verb": "set", "Key": "asdf", "Value": value}} r = yield c.txn.put([d]) @@ -181,10 +178,9 @@ def main(): loop.stop() loop.run_sync(main) - def test_agent_services(self, loop, consul_port): + def test_agent_services(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) services = yield c.agent.services() assert services == {} response = yield c.agent.service.register('foo') @@ -208,8 +204,7 @@ def main(): loop.stop() loop.run_sync(main) - def test_catalog(self, loop, consul_port): - c = consul.tornado.Consul(port=consul_port) + def test_catalog(self, loop, c): @gen.coroutine def nodes(): @@ -237,10 +232,9 @@ def register(): loop.add_timeout(time.time()+(1.0/100), register) loop.run_sync(nodes) - def test_health_service(self, loop, consul_port): + def test_health_service(self, loop, c): @gen.coroutine def main(): - c = consul.tornado.Consul(port=consul_port) # check there are no nodes for the service 'foo' index, nodes = yield c.health.service('foo') @@ -302,8 +296,7 @@ def main(): loop.run_sync(main) - def test_health_service_subscribe(self, loop, consul_port): - c = consul.tornado.Consul(port=consul_port) + def test_health_service_subscribe(self, loop, c): class Config(object): pass @@ -341,8 +334,7 @@ def keepalive(): loop.add_callback(monitor) loop.run_sync(keepalive) - def test_session(self, loop, consul_port): - c = consul.tornado.Consul(port=consul_port) + def test_session(self, loop, c): @gen.coroutine def monitor(): diff --git a/tests/test_twisted.py b/tests/test_twisted.py index 097674c5..36db890a 100644 --- a/tests/test_twisted.py +++ b/tests/test_twisted.py @@ -11,6 +11,11 @@ Check = consul.Check +@pytest.fixture +def c(consul_port): + return consul.twisted.Consul(port=consul_port) + + def sleep(seconds): """ An asynchronous sleep function using twsited. Source: @@ -25,8 +30,7 @@ def sleep(seconds): class TestConsul(object): @pytest.inlineCallbacks - def test_kv(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv(self, c): index, data = yield c.kv.get('foo') assert data is None response = yield c.kv.put('foo', 'bar') @@ -35,15 +39,13 @@ def test_kv(self, consul_port): assert data['Value'] == six.b('bar') @pytest.inlineCallbacks - def test_kv_binary(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv_binary(self, c): yield c.kv.put('foo', struct.pack('i', 1000)) index, data = yield c.kv.get('foo') assert struct.unpack('i', data['Value']) == (1000,) @pytest.inlineCallbacks - def test_kv_missing(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv_missing(self, c): reactor.callLater(2.0 / 100, c.kv.put, 'foo', 'bar') yield c.kv.put('index', 'bump') index, data = yield c.kv.get('foo') @@ -52,8 +54,7 @@ def test_kv_missing(self, consul_port): assert data['Value'] == six.b('bar') @pytest.inlineCallbacks - def test_kv_put_flags(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv_put_flags(self, c): yield c.kv.put('foo', 'bar') index, data = yield c.kv.get('foo') assert data['Flags'] == 0 @@ -64,8 +65,7 @@ def test_kv_put_flags(self, consul_port): assert data['Flags'] == 50 @pytest.inlineCallbacks - def test_kv_delete(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv_delete(self, c): yield c.kv.put('foo1', '1') yield c.kv.put('foo2', '2') yield c.kv.put('foo3', '3') @@ -82,8 +82,7 @@ def test_kv_delete(self, consul_port): assert data is None @pytest.inlineCallbacks - def test_kv_subscribe(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_kv_subscribe(self, c): @defer.inlineCallbacks def put(): @@ -97,8 +96,7 @@ def put(): assert data['Value'] == six.b('bar') @pytest.inlineCallbacks - def test_transaction(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_transaction(self, c): value = base64.b64encode(b"1").decode("utf8") d = {"KV": {"Verb": "set", "Key": "asdf", "Value": value}} r = yield c.txn.put([d]) @@ -109,8 +107,7 @@ def test_transaction(self, consul_port): assert r["Results"][0]["KV"]["Value"] == value @pytest.inlineCallbacks - def test_agent_services(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_agent_services(self, c): services = yield c.agent.services() assert services == {} response = yield c.agent.service.register('foo') @@ -134,8 +131,7 @@ def test_agent_services(self, consul_port): assert services == {} @pytest.inlineCallbacks - def test_catalog(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_catalog(self, c): @defer.inlineCallbacks def register(): @@ -160,8 +156,7 @@ def register(): assert [x['Node'] for x in nodes] == [] @pytest.inlineCallbacks - def test_health_service(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_health_service(self, c): # check there are no nodes for the service 'foo' index, nodes = yield c.health.service('foo') @@ -221,8 +216,7 @@ def test_health_service(self, consul_port): assert nodes == [] @pytest.inlineCallbacks - def test_health_service_subscribe(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_health_service_subscribe(self, c): class Config(object): def __init__(self): @@ -254,8 +248,7 @@ def update(self): yield c.agent.service.deregister('foo:1') @pytest.inlineCallbacks - def test_session(self, consul_port): - c = consul.twisted.Consul(port=consul_port) + def test_session(self, c): index, services = yield c.session.list() assert services == [] From 9ae3b20ef79a8dd44c3864f056fdb06e16365606 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Jul 2018 23:50:42 +0200 Subject: [PATCH 10/15] fix flake8 E712 test failures for boolean comparison Signed-off-by: Steven Armstrong --- tests/test_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 14a187a7..53ddf990 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -84,13 +84,13 @@ def test_CONSUL_HTTP_SSL_VERIFY_True(self): CONSUL_HTTP_SSL_VERIFY = 'true' with self.environ(CONSUL_HTTP_SSL_VERIFY=CONSUL_HTTP_SSL_VERIFY): c = Consul.from_env() - assert c.http.verify == True + assert c.http.verify is True def test_CONSUL_HTTP_SSL_VERIFY_False(self): CONSUL_HTTP_SSL_VERIFY = 'false' with self.environ(CONSUL_HTTP_SSL_VERIFY=CONSUL_HTTP_SSL_VERIFY): c = Consul.from_env() - assert c.http.verify == False + assert c.http.verify is False def test_CONSUL_CACERT(self): CONSUL_CACERT = '/path/to/ca.crt' From b8beff2d6ee63545f2ed1e2f9258ac7145677fb7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Jul 2018 23:51:44 +0200 Subject: [PATCH 11/15] fix flake8 E265: remove commented/unused code Signed-off-by: Steven Armstrong --- tests/test_std.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_std.py b/tests/test_std.py index 74884b1e..c7383fd7 100644 --- a/tests/test_std.py +++ b/tests/test_std.py @@ -204,7 +204,6 @@ def verify_check_status(check_id, status, notes=None): check_id='check_id') is True verify_and_dereg_check('check_id') - #http_addr = "http://127.0.0.1:{0}".format(c) http_addr = c.http.base_uri assert c.agent.check.register( 'http_check', Check.http(http_addr, '10ms')) is True From 9287fe75e2cfe097419178a01b11abb61bb4ea55 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Jul 2018 23:56:26 +0200 Subject: [PATCH 12/15] fix flake8 E128 and E501 Signed-off-by: Steven Armstrong --- consul/std.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/consul/std.py b/consul/std.py index 44c4e9b8..a333c5be 100644 --- a/consul/std.py +++ b/consul/std.py @@ -20,7 +20,8 @@ def __init__(self, *args, **kwargs): self.session = requests_unixsocket.Session() except ImportError: raise base.ConsulException('To use a unix socket to connect to' - 'Consul you need to install the "requests_unixsocket" package.') + ' Consul you need to install the' + ' "requests_unixsocket" package.') else: self.session = requests.session() From 905b59834e142c8cda9779c2d57c88df37ee5c65 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 10 Jul 2018 22:39:08 +0200 Subject: [PATCH 13/15] add tests for CONSUL_HTTP_ADDR with and without scheme and CONSUL_HTTP_SSL Signed-off-by: Steven Armstrong --- tests/test_base.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_base.py b/tests/test_base.py index 53ddf990..32c1d500 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -60,6 +60,19 @@ def test_CONSUL_HTTP_ADDR(self): c = Consul.from_env() assert c.http.base_uri == CONSUL_HTTP_ADDR + def test_CONSUL_HTTP_ADDR_scheme_http(self): + CONSUL_HTTP_ADDR = '127.0.0.23:4242' + with self.environ(CONSUL_HTTP_ADDR=CONSUL_HTTP_ADDR): + c = Consul.from_env() + assert c.http.base_uri == 'http://'+ CONSUL_HTTP_ADDR + + def test_CONSUL_HTTP_ADDR_with_CONSUL_HTTP_SSL(self): + CONSUL_HTTP_ADDR = '127.0.0.23:4242' + with self.environ(CONSUL_HTTP_ADDR=CONSUL_HTTP_ADDR, + CONSUL_HTTP_SSL='true'): + c = Consul.from_env() + assert c.http.base_uri == 'https://'+ CONSUL_HTTP_ADDR + def test_CONSUL_HTTP_TOKEN(self): CONSUL_HTTP_TOKEN = '1bdc2cb4-9b02-4b3c-9df5-eb86214e1a6c' with self.environ(CONSUL_HTTP_TOKEN=CONSUL_HTTP_TOKEN): From 84d73ca8d4dd7db2f2a6e6bee155c719b7b35927 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 10 Jul 2018 22:40:02 +0200 Subject: [PATCH 14/15] ensure CONSUL_HTTP_ADDR starts with a scheme, either http or https if CONSUL_HTTP_SSL is set Signed-off-by: Steven Armstrong --- consul/base.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/consul/base.py b/consul/base.py index fd7c469c..87bfc759 100755 --- a/consul/base.py +++ b/consul/base.py @@ -352,9 +352,26 @@ def from_env(cls, consistency='default', dc=None): kwargs = { 'consistency': consistency, 'dc': dc, - 'addr': oe.get('CONSUL_HTTP_ADDR', None), 'token': oe.get('CONSUL_HTTP_TOKEN', None), } + + addr = oe.get('CONSUL_HTTP_ADDR', None) + if addr: + if not addr.startswith('http'): + # Ensure addr starts with a scheme. + ssl = oe.get('CONSUL_HTTP_SSL', False) + if ssl == 'false': + ssl = False + elif ssl == 'true': + ssl = True + + if ssl: + scheme = 'https' + else: + scheme = 'http' + addr = '%s://%s' % (scheme, addr) + kwargs['addr'] = addr + verify = oe.get('CONSUL_CACERT', oe.get('CONSUL_HTTP_SSL_VERIFY', None)) if verify: From a23c4d82630d0ccdaa84375d5bc64a761f27acf0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 10 Jul 2018 22:44:08 +0200 Subject: [PATCH 15/15] fix flake8 E225 Signed-off-by: Steven Armstrong --- tests/test_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 32c1d500..00ae1a83 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -64,14 +64,14 @@ def test_CONSUL_HTTP_ADDR_scheme_http(self): CONSUL_HTTP_ADDR = '127.0.0.23:4242' with self.environ(CONSUL_HTTP_ADDR=CONSUL_HTTP_ADDR): c = Consul.from_env() - assert c.http.base_uri == 'http://'+ CONSUL_HTTP_ADDR + assert c.http.base_uri == 'http://' + CONSUL_HTTP_ADDR def test_CONSUL_HTTP_ADDR_with_CONSUL_HTTP_SSL(self): CONSUL_HTTP_ADDR = '127.0.0.23:4242' with self.environ(CONSUL_HTTP_ADDR=CONSUL_HTTP_ADDR, CONSUL_HTTP_SSL='true'): c = Consul.from_env() - assert c.http.base_uri == 'https://'+ CONSUL_HTTP_ADDR + assert c.http.base_uri == 'https://' + CONSUL_HTTP_ADDR def test_CONSUL_HTTP_TOKEN(self): CONSUL_HTTP_TOKEN = '1bdc2cb4-9b02-4b3c-9df5-eb86214e1a6c'