From 804365db24c23a604dc5fa75b5da1fc47ee89269 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 Mar 2016 11:37:09 +0200 Subject: [PATCH] Improve config, tests and docs Add better support to env variables. --- bigchaindb/commands/bigchain.py | 2 +- bigchaindb/config_utils.py | 42 +++++++++++++++++++++++--------- docs/source/bigchaindb-cli.md | 24 ++++++++++++------ tests/test_commands.py | 2 +- tests/utils/test_config_utils.py | 16 ++++++------ 5 files changed, 58 insertions(+), 28 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 40f0cfa5..fbcc3f31 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -26,7 +26,7 @@ def run_show_config(args): # TODO Proposal: remove the "hidden" configuration. Only show config. If # the system needs to be configured, then display information on how to # configure the system. - bigchaindb.config_utils.file_config(args.config) + bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) pprint(bigchaindb.config) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index 7ab81250..b1e729d2 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -155,20 +155,38 @@ def update_types(config): reference = bigchaindb.config + def _coerce(current, value): + # Coerce a value to the `current` type. + try: + # First we try to apply current to the value, since it + # might be a function + return current(value) + except TypeError: + # Then we check if current is a list AND if the value + # is a string. + if isinstance(current, list) and isinstance(value, str): + # If so, we use the colon as the separator + return value.split(':') + + try: + # If we are here, we should try to apply the type + # of `current` to the value + return type(current)(value) + except TypeError: + # Worst case scenario we return the value itself. + return value + def _update_type(value, path): - ref = reference + current = reference for elem in path: - ref = ref[elem] - - try: - return ref(value) - except TypeError: try: - return type(ref)(value) - except TypeError: + current = current[elem] + except KeyError: return value + return _coerce(current, value) + return map_leafs(_update_type, config) @@ -207,6 +225,7 @@ def autoconfigure(filename=None, config=None, force=False): been initialized.""" if not force and bigchaindb.config.get('CONFIGURED'): + logger.info('System already configured, skipping autoconfiguration') return newconfig = env_config(bigchaindb.config) @@ -215,9 +234,10 @@ def autoconfigure(filename=None, config=None, force=False): newconfig = update(newconfig, config) try: - newconfig = update(newconfig, file_config()) - except FileNotFoundError: - logger.warning('Cannot find your config file.') + # import pdb; pdb.set_trace() + newconfig = update(newconfig, file_config(filename=filename)) + except FileNotFoundError as e: + logger.warning('Cannot find config file `%s`.' % e.filename) dict_config(newconfig) return newconfig diff --git a/docs/source/bigchaindb-cli.md b/docs/source/bigchaindb-cli.md index 53ef986c..dce80671 100644 --- a/docs/source/bigchaindb-cli.md +++ b/docs/source/bigchaindb-cli.md @@ -29,7 +29,6 @@ For more information check the help with `bigchaindb -h`. # Precedence in reading configuration values Note that there is a precedence in reading configuration values: - - (**not yet**) command line; - local config file; - environment vars; - default config file (contained in ``bigchaindb.__init__``). @@ -46,29 +45,37 @@ This means that if the default configuration contains an entry that is: while your local file `local.json` contains: ``` {... - "database": {"host": "whatever"} + "database": {"host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com"} ...} ``` and you run this command: ``` -$ BIGCHAINDB_DATABASE_HOST=foobar BIGCHAINDB_DATABASE_PORT=42000 bigchaindb -c local.json show-config +$ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ + BIGCHAINDB_DATABASE_PORT=4242 \ + BIGCHAINDB_KEYRING=pubkey0:pubkey1 \ + bigchaindb -c local.json show-config ``` you will get: ``` +Cannot find config file `/home/vrde/.bigchaindb`. INFO:bigchaindb.config_utils:Configuration loaded from `local.json` {'CONFIGURED': True, 'api_endpoint': 'http://localhost:8008/api/v1', 'consensus_plugin': 'default', - 'database': {'host': 'localhost', 'name': 'bigchain', 'port': 28015}, - 'keypair': {'private': 'Hbqvh...', - 'public': '2Bi5NU...'}, - 'keyring': [], + 'database': {'host': 'ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com', + 'name': 'bigchain', + 'port': 4242}, + 'keypair': {'private': None, 'public': None}, + 'keyring': ['pubkey0', 'pubkey1'], 'statsd': {'host': 'localhost', 'port': 8125, 'rate': 0.01}} - ``` +Note that the type of `keyring` is a list. If you want to pass a list as an +environ variable you need to use colon (`:`) as separator. + + # List of env variables ``` @@ -77,6 +84,7 @@ INFO:bigchaindb.config_utils:Configuration loaded from `local.json` - BIGCHAINDB_DATABASE_NAME - BIGCHAINDB_KEYPAIR_PUBLIC - BIGCHAINDB_KEYPAIR_PRIVATE +- BIGCHAINDB_KEYRING - BIGCHAINDB_STATSD_HOST - BIGCHAINDB_STATSD_PORT - BIGCHAINDB_STATSD_RATE diff --git a/tests/test_commands.py b/tests/test_commands.py index 1a6db1b1..e1fbe14a 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -14,7 +14,7 @@ def mock_run_configure(monkeypatch): @pytest.fixture def mock_file_config(monkeypatch): from bigchaindb import config_utils - monkeypatch.setattr(config_utils, 'file_config', lambda *args: None) + monkeypatch.setattr(config_utils, 'file_config', lambda *args, **kwargs: {}) @pytest.fixture diff --git a/tests/utils/test_config_utils.py b/tests/utils/test_config_utils.py index c6224c2a..9defc601 100644 --- a/tests/utils/test_config_utils.py +++ b/tests/utils/test_config_utils.py @@ -106,28 +106,30 @@ def test_env_config(monkeypatch): def test_autoconfigure_read_both_from_file_and_env(monkeypatch): - monkeypatch.setattr('bigchaindb.config_utils.file_config', lambda: {}) - monkeypatch.setattr('os.environ', {'BIGCHAINDB_DATABASE_HOST': 'test-host', - 'BIGCHAINDB_DATABASE_PORT': '4242'}) + file_config = { + 'database': {'host': 'test-host'} + } + monkeypatch.setattr('bigchaindb.config_utils.file_config', lambda *args, **kwargs: file_config) + monkeypatch.setattr('os.environ', {'BIGCHAINDB_DATABASE_NAME': 'test-dbname', + 'BIGCHAINDB_DATABASE_PORT': '4242', + 'BIGCHAINDB_KEYRING': 'pubkey_0:pubkey_1:pubkey_2'}) import bigchaindb from bigchaindb import config_utils config_utils.autoconfigure() - assert bigchaindb.config['database']['host'] == 'test-host' - assert bigchaindb.config['database']['port'] == 4242 assert bigchaindb.config == { 'CONFIGURED': True, 'database': { 'host': 'test-host', 'port': 4242, - 'name': 'bigchain', + 'name': 'test-dbname', }, 'keypair': { 'public': None, 'private': None, }, - 'keyring': [], + 'keyring': ['pubkey_0', 'pubkey_1', 'pubkey_2'], 'statsd': { 'host': 'localhost', 'port': 8125,