From e4d3915533a4de730975474fbdc131a1f54219dd Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 24 Mar 2016 01:41:00 +0100 Subject: [PATCH 01/25] Add type conversion and docs --- bigchaindb/__init__.py | 43 +++------ bigchaindb/commands/bigchain.py | 2 +- bigchaindb/config_utils.py | 149 +++++++++++++++++++++++++++---- docs/source/bigchaindb-cli.md | 65 +++++++++++++- tests/test_commands.py | 1 + tests/utils/test_config_utils.py | 76 +++++++++++++++- 6 files changed, 283 insertions(+), 53 deletions(-) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index 9283913f..4ed6d0bd 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -1,47 +1,24 @@ -import os import copy - -def e(key, default=None, conv=None): - '''Get the environment variable `key`, fallback to `default` - if nothing is found. - - Keyword arguments: - key -- the key to look for in the environment - default -- the default value if nothing is found (default: None) - conv -- a callable used to convert the value (default: use the type of the - default value) - ''' - - val = os.environ.get(key, default) - - if conv or default is not None: - conv = conv or type(default) - return conv(val) - - return val - - config = { 'database': { - 'host': e('BIGCHAIN_DATABASE_HOST', default='localhost'), - 'port': e('BIGCHAIN_DATABASE_PORT', default=28015), - 'name': e('BIGCHAIN_DATABASE_NAME', default='bigchain') + 'host': 'localhost', + 'port': 28015, + 'name': 'bigchain', }, 'keypair': { - 'public': e('BIGCHAIN_KEYPAIR_PUBLIC'), - 'private': e('BIGCHAIN_KEYPAIR_PRIVATE') + 'public': None, + 'private': None, }, - 'keyring': [ - ], + 'keyring': [], 'statsd': { - 'host': e('BIGCHAIN_STATSD_HOST', default='localhost'), - 'port': e('BIGCHAIN_STATSD_PORT', default=8125), - 'rate': e('BIGCHAIN_STATSD_SAMPLERATE', default=0.01) + 'host': 'localhost', + 'port': 8125, + 'rate': 0.01, }, 'api_endpoint': 'http://localhost:8008/api/v1', - 'consensus_plugin': e('BIGCHAIN_CONSENSUS_PLUGIN', default='default') + 'consensus_plugin': 'default', } # We need to maintain a backup copy of the original config dict in case diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 35b2de2f..40f0cfa5 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -88,7 +88,7 @@ def run_drop(args): def run_start(args): """Start the processes to run the node""" - run_configure(args, skip_if_exists=True) + # run_configure(args, skip_if_exists=True) bigchaindb.config_utils.file_config(args.config) try: db.init() diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index 645780eb..7ab81250 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -5,10 +5,46 @@ By calling `file_config`, the global configuration (stored in configuration file. Note that there is a precedence in reading configuration values: - - [not yet] command line; + - (**not yet**) command line; - local config file; - environment vars; - - default config file (contained in `bigchain.__init__`). + - default config file (contained in ``bigchaindb.__init__``). + +This means that if the default configuration contains an entry that is: + +``` +{... + "database": {"host": "localhost", + "port": 28015} +...} +``` + +while your local file `local.json` contains: +``` +{... + "database": {"host": "whatever"} +...} +``` + +and you run this command: +``` +$ BIGCHAINDB_DATABASE_HOST=foobar BIGCHAINDB_DATABASE_PORT=42000 bigchaindb -c local.json show-config +``` + +You will get: +``` +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': [], + 'statsd': {'host': 'localhost', 'port': 8125, 'rate': 0.01}} + +``` + """ import os @@ -23,11 +59,40 @@ import bigchaindb from bigchaindb.consensus import AbstractConsensusRules logger = logging.getLogger(__name__) + CONFIG_DEFAULT_PATH = os.environ.setdefault( 'BIGCHAINDB_CONFIG_PATH', os.path.join(os.path.expanduser('~'), '.bigchaindb'), ) +CONFIG_PREFIX = 'BIGCHAINDB' +CONFIG_SEP = '_' + + +def map_leafs(func, mapping): + """Map a function to the leafs of a mapping.""" + + def _inner(mapping, path=None): + if path is None: + path = [] + + for key, val in mapping.items(): + if isinstance(val, collections.Mapping): + _inner(val, path + [key]) + else: + mapping[key] = func(val, path=path+[key]) + + return mapping + + return _inner(copy.deepcopy(mapping)) + + +def get_casted_value(original, to_convert): + try: + return original(to_convert) + except TypeError: + return type(original)(to_convert) + # Thanks Alex <3 # http://stackoverflow.com/a/3233356/597097 @@ -43,7 +108,7 @@ def update(d, u): def file_config(filename=None): - """Read a configuration file and merge it with the default configuration. + """Returns the values found in a configuration file. Args: filename (str): the JSON file with the configuration. Defaults to ``None``. @@ -57,13 +122,57 @@ def file_config(filename=None): filename = CONFIG_DEFAULT_PATH with open(filename) as f: - newconfig = json.load(f) + config = json.load(f) - dict_config(newconfig) logger.info('Configuration loaded from `{}`'.format(filename)) + return config -def dict_config(newconfig): + +def env_config(config): + """Return a new configuration with the values found in the environment. + + The function recursively iterates over the config, checking if there is + a matching env variable. If an env variable is found, the func updates + the configuration with that value. + + The name of the env variable is built combining a prefix (``BIGCHAINDB``) + with the path to the value. If the ``config`` in input is: + ``{'database': {'host': 'localhost'}}`` + this function will try to read the env variable ``BIGCHAINDB_DATABASE_HOST``. + """ + + def load_from_env(value, path): + var_name = CONFIG_SEP.join([CONFIG_PREFIX] + list(map(lambda s: s.upper(), path))) + return os.environ.get(var_name, value) + + return map_leafs(load_from_env, config) + + +def update_types(config): + """Return a new configuration where all the values types + are aligned with the ones in the default configuration""" + + reference = bigchaindb.config + + def _update_type(value, path): + ref = reference + + for elem in path: + ref = ref[elem] + + try: + return ref(value) + except TypeError: + try: + return type(ref)(value) + except TypeError: + return value + + return map_leafs(_update_type, config) + + +def dict_config(config): """Merge the provided configuration with the default one. Args: @@ -74,11 +183,11 @@ def dict_config(newconfig): update made to ``bigchaindb.config`` will be lost. """ bigchaindb.config = copy.deepcopy(bigchaindb._config) - update(bigchaindb.config, newconfig) + update(bigchaindb.config, update_types(config)) bigchaindb.config['CONFIGURED'] = True -def write_config(newconfig, filename=None): +def write_config(config, filename=None): """Write the provided configuration to a specific location. Args: @@ -90,18 +199,28 @@ def write_config(newconfig, filename=None): filename = CONFIG_DEFAULT_PATH with open(filename, 'w') as f: - json.dump(newconfig, f) + json.dump(config, f) -def autoconfigure(): - """Run ``file_config`` if the module has not been initialized. - """ - if bigchaindb.config.get('CONFIGURED'): +def autoconfigure(filename=None, config=None, force=False): + """Run ``file_config`` and ``env_config`` if the module has not + been initialized.""" + + if not force and bigchaindb.config.get('CONFIGURED'): return + + newconfig = env_config(bigchaindb.config) + + if config: + newconfig = update(newconfig, config) + try: - file_config() + newconfig = update(newconfig, file_config()) except FileNotFoundError: - logger.warning('Cannot find your config file. Run `bigchaindb configure` to create one') + logger.warning('Cannot find your config file.') + + dict_config(newconfig) + return newconfig def load_consensus_plugin(name=None): diff --git a/docs/source/bigchaindb-cli.md b/docs/source/bigchaindb-cli.md index 108e5846..53ef986c 100644 --- a/docs/source/bigchaindb-cli.md +++ b/docs/source/bigchaindb-cli.md @@ -2,10 +2,11 @@ BigchainDB has some Command Line Interfaces (CLIs). One of them is the `bigchaindb` command which we already saw when we first started BigchainDB using: ```text +$ bigchaindb configure $ bigchaindb start ``` -The fist time you run `bigchaindb start`, it creates a default configuration file in `$HOME/.bigchaindb`. You can check that configuration using: +When you run `bigchaindb configure`, it creates a default configuration file in `$HOME/.bigchaindb`. You can check that configuration using: ```text $ bigchaindb show-config ``` @@ -20,3 +21,65 @@ There's another command named `bigchaindb-benchmark`. It's used to run benchmark $ bigchaindb-benchmark -h $ bigchaindb-benchmark load -h ``` + +Note that you can always start `bigchaindb` using a different config file using the `-c` option. +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__``). + +This means that if the default configuration contains an entry that is: + +``` +{... + "database": {"host": "localhost", + "port": 28015} +...} +``` + +while your local file `local.json` contains: +``` +{... + "database": {"host": "whatever"} +...} +``` + +and you run this command: +``` +$ BIGCHAINDB_DATABASE_HOST=foobar BIGCHAINDB_DATABASE_PORT=42000 bigchaindb -c local.json show-config +``` + +you will get: +``` +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': [], + 'statsd': {'host': 'localhost', 'port': 8125, 'rate': 0.01}} + +``` + +# List of env variables + +``` +- BIGCHAINDB_DATABASE_HOST +- BIGCHAINDB_DATABASE_PORT +- BIGCHAINDB_DATABASE_NAME +- BIGCHAINDB_KEYPAIR_PUBLIC +- BIGCHAINDB_KEYPAIR_PRIVATE +- BIGCHAINDB_STATSD_HOST +- BIGCHAINDB_STATSD_PORT +- BIGCHAINDB_STATSD_RATE +- BIGCHAINDB_API_ENDPOINT +- BIGCHAINDB_CONSENSUS_PLUGIN +``` diff --git a/tests/test_commands.py b/tests/test_commands.py index 6e731c13..1a6db1b1 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -72,6 +72,7 @@ def test_bigchain_run_start(mock_run_configure, mock_file_config, run_start(args) +@pytest.mark.skipif(reason="BigchainDB doesn't support the automatic creation of a config file anymore") def test_bigchain_run_start_assume_yes_create_default_config(monkeypatch, mock_processes_start, mock_generate_key_pair, mock_db_init_with_existing_db): import bigchaindb diff --git a/tests/utils/test_config_utils.py b/tests/utils/test_config_utils.py index fa63158d..c6224c2a 100644 --- a/tests/utils/test_config_utils.py +++ b/tests/utils/test_config_utils.py @@ -60,9 +60,79 @@ def test_load_consensus_plugin_raises_with_invalid_subclass(monkeypatch): from bigchaindb import config_utils monkeypatch.setattr(config_utils, 'iter_entry_points', - lambda *args: [ type('entry_point', - (object), - {'load': lambda: object}) ]) + lambda *args: [type('entry_point', (object), {'load': lambda: object})]) with pytest.raises(TypeError): config_utils.load_consensus_plugin() + + +def test_map_leafs_iterator(): + from bigchaindb import config_utils + + mapping = { + 'a': {'b': {'c': 1}, + 'd': {'z': 44}}, + 'b': {'d': 2}, + 'c': 3 + } + + result = config_utils.map_leafs(lambda x, path: x * 2, mapping) + assert result == { + 'a': {'b': {'c': 2}, + 'd': {'z': 88}}, + 'b': {'d': 4}, + 'c': 6 + } + + result = config_utils.map_leafs(lambda x, path: path, mapping) + assert result == { + 'a': {'b': {'c': ['a', 'b', 'c']}, + 'd': {'z': ['a', 'd', 'z']}}, + 'b': {'d': ['b', 'd']}, + 'c': ['c'] + } + + +def test_env_config(monkeypatch): + monkeypatch.setattr('os.environ', {'BIGCHAINDB_DATABASE_HOST': 'test-host', + 'BIGCHAINDB_DATABASE_PORT': 'test-port'}) + + from bigchaindb import config_utils + + result = config_utils.env_config({'database': {'host': None, 'port': None}}) + expected = {'database': {'host': 'test-host', 'port': 'test-port'}} + + assert result == expected + + +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'}) + + 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', + }, + 'keypair': { + 'public': None, + 'private': None, + }, + 'keyring': [], + 'statsd': { + 'host': 'localhost', + 'port': 8125, + 'rate': 0.01, + }, + 'api_endpoint': 'http://localhost:8008/api/v1', + 'consensus_plugin': 'default', + } From 804365db24c23a604dc5fa75b5da1fc47ee89269 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 Mar 2016 11:37:09 +0200 Subject: [PATCH 02/25] 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, From 75a4bf65dd37ca807556165dc5cde31d0c870efd Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 Mar 2016 11:44:33 +0200 Subject: [PATCH 03/25] Remove reference to command line params --- bigchaindb/config_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index b1e729d2..e4e23144 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -5,7 +5,6 @@ By calling `file_config`, the global configuration (stored in configuration file. 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__``). From 5864c34115e4110c1784bc83a013a0b61cebd7d9 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 Mar 2016 11:50:48 +0200 Subject: [PATCH 04/25] Remove redundant documentation --- bigchaindb/config_utils.py | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index e4e23144..f165334a 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -8,44 +8,9 @@ Note that there is a precedence in reading configuration values: - local config file; - environment vars; - default config file (contained in ``bigchaindb.__init__``). - -This means that if the default configuration contains an entry that is: - -``` -{... - "database": {"host": "localhost", - "port": 28015} -...} -``` - -while your local file `local.json` contains: -``` -{... - "database": {"host": "whatever"} -...} -``` - -and you run this command: -``` -$ BIGCHAINDB_DATABASE_HOST=foobar BIGCHAINDB_DATABASE_PORT=42000 bigchaindb -c local.json show-config -``` - -You will get: -``` -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': [], - 'statsd': {'host': 'localhost', 'port': 8125, 'rate': 0.01}} - -``` - """ + import os import copy import json From aec3b3db6c48346c15fe48d3d3a16fa8cdef8295 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 16:14:43 +0200 Subject: [PATCH 05/25] Hide private key when showing configuration --- bigchaindb/commands/bigchain.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index fbcc3f31..6e2bf1d3 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -27,6 +27,7 @@ def run_show_config(args): # the system needs to be configured, then display information on how to # configure the system. bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) + bigchaindb.config['keypair']['private'] = 'x' * 45 pprint(bigchaindb.config) From 4b32e8e01a627a75f0d6f5cc0de41e325065b2f6 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 16:15:17 +0200 Subject: [PATCH 06/25] Use autoconfigure on every command --- bigchaindb/commands/bigchain.py | 6 +++--- bigchaindb/config_utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 6e2bf1d3..fddcce52 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -70,7 +70,7 @@ def run_configure(args, skip_if_exists=False): def run_init(args): """Initialize the database""" - bigchaindb.config_utils.file_config(args.config) + bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) # TODO Provide mechanism to: # 1. prompt the user to inquire whether they wish to drop the db # 2. force the init, (e.g., via -f flag) @@ -83,14 +83,14 @@ def run_init(args): def run_drop(args): """Drop the database""" - bigchaindb.config_utils.file_config(args.config) + bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) db.drop(assume_yes=args.yes) def run_start(args): """Start the processes to run the node""" # run_configure(args, skip_if_exists=True) - bigchaindb.config_utils.file_config(args.config) + bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) try: db.init() except DatabaseAlreadyExists: diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index f165334a..19caef90 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -189,7 +189,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') + logger.debug('System already configured, skipping autoconfiguration') return newconfig = env_config(bigchaindb.config) From c5cefd6ad5c818ca6fbf23c5b60c6e6242a93e57 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 16:15:38 +0200 Subject: [PATCH 07/25] Remove useless import --- bigchaindb/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bigchaindb/core.py b/bigchaindb/core.py index f76dd2d6..48838adb 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -1,6 +1,5 @@ import rethinkdb as r import random -import json import rapidjson From a56aa992fa6dc1501e5ac702ca2eeff33e31cb94 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 16:36:12 +0200 Subject: [PATCH 08/25] Do not hide empty privkeys --- bigchaindb/commands/bigchain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index fddcce52..70554ad3 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -27,7 +27,8 @@ def run_show_config(args): # the system needs to be configured, then display information on how to # configure the system. bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) - bigchaindb.config['keypair']['private'] = 'x' * 45 + private_key = bigchaindb.config['keypair']['private'] + bigchaindb.config['keypair']['private'] = 'x' * 45 if private_key else None pprint(bigchaindb.config) From 3c31a8684ffa2b878f1708abc253c1ee87d0366f Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 16:50:34 +0200 Subject: [PATCH 09/25] Remove `CONFIGURED` key from show-config --- bigchaindb/commands/bigchain.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 70554ad3..e7cb933f 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -27,9 +27,11 @@ def run_show_config(args): # the system needs to be configured, then display information on how to # configure the system. bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) - private_key = bigchaindb.config['keypair']['private'] - bigchaindb.config['keypair']['private'] = 'x' * 45 if private_key else None - pprint(bigchaindb.config) + config = copy.deepcopy(bigchaindb.config) + del config['CONFIGURED'] + private_key = config['keypair']['private'] + config['keypair']['private'] = 'x' * 45 if private_key else None + pprint(config) def run_configure(args, skip_if_exists=False): From 959320cdb9603edeae6552a5e33b1971ac8f1df3 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 6 Apr 2016 17:39:44 +0200 Subject: [PATCH 10/25] Remove `CONFIGURED` from tests as well :sweat: --- tests/test_commands.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_commands.py b/tests/test_commands.py index e1fbe14a..895efc07 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -107,6 +107,8 @@ def test_bigchain_show_config(capsys, mock_file_config): _, _ = capsys.readouterr() run_show_config(args) output_config, _ = capsys.readouterr() + config['keypair']['private'] = 'x' * 45 + del config['CONFIGURED'] pprint(config) expected_outout_config, _ = capsys.readouterr() assert output_config == expected_outout_config From 06f45f1dc71fe4387d4e3fc7a8e7c3d6276e38be Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 7 Apr 2016 14:15:29 +0200 Subject: [PATCH 11/25] Change server port to 9984 --- bigchaindb/__init__.py | 12 ++++++++++-- bigchaindb/web/server.py | 3 +++ docs/source/bigchaindb-cli.md | 3 +++ docs/source/http-client-server-api.md | 13 +++++++++---- docs/source/installing-server.md | 10 ++++++++-- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index f1dc0f2f..6a462ab7 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -1,9 +1,17 @@ import copy +# from functools import reduce +# PORT_NUMBER = reduce(lambda x, y: x * y, map(ord, 'BigchainDB')) % 2**16 +# basically, the port number is 9984 + config = { 'server': { - 'bind': '0.0.0.0:5000', + # Note: this section supports all the Gunicorn settings: + # - http://docs.gunicorn.org/en/stable/settings.html + 'bind': '0.0.0.0:9984', + 'workers': None, # if none, the value will be cpu_count * 2 + 1 + 'threads': None, # if none, the value will be cpu_count * 2 + 1 }, 'database': { 'host': 'localhost', @@ -20,7 +28,7 @@ config = { 'port': 8125, 'rate': 0.01, }, - 'api_endpoint': 'http://localhost:8008/api/v1', + 'api_endpoint': 'http://localhost:9984/api/v1', 'consensus_plugin': 'default', } diff --git a/bigchaindb/web/server.py b/bigchaindb/web/server.py index 208f2458..021ceab4 100644 --- a/bigchaindb/web/server.py +++ b/bigchaindb/web/server.py @@ -76,6 +76,9 @@ def create_server(settings): if not settings.get('workers'): settings['workers'] = (multiprocessing.cpu_count() * 2) + 1 + if not settings.get('threads'): + settings['threads'] = (multiprocessing.cpu_count() * 2) + 1 + debug = settings.pop('debug', False) app = create_app(debug) standalone = StandaloneApplication(app, settings) diff --git a/docs/source/bigchaindb-cli.md b/docs/source/bigchaindb-cli.md index dce80671..a1b9e778 100644 --- a/docs/source/bigchaindb-cli.md +++ b/docs/source/bigchaindb-cli.md @@ -90,4 +90,7 @@ environ variable you need to use colon (`:`) as separator. - BIGCHAINDB_STATSD_RATE - BIGCHAINDB_API_ENDPOINT - BIGCHAINDB_CONSENSUS_PLUGIN +- BIGCHAINDB_SERVER_BIND +- BIGCHAINDB_SERVER_WORKERS +- BIGCHAINDB_SERVER_THREADS ``` diff --git a/docs/source/http-client-server-api.md b/docs/source/http-client-server-api.md index 1520b046..da045fa3 100644 --- a/docs/source/http-client-server-api.md +++ b/docs/source/http-client-server-api.md @@ -2,10 +2,15 @@ When you start Bigchaindb using `bigchaindb start`, an HTTP API is exposed at: -[http://localhost:5000/api/v1/](http://localhost:5000/api/v1/) +- [http://localhost:9984/api/v1/](http://localhost:9984/api/v1/) -Right now, that API can only be accessed from localhost (i.e. not remotely). In the future, we'll enable remote access and explain how that works. See [Issue #149](https://github.com/bigchaindb/bigchaindb/issues/149) on GitHub. -The HTTP API currently exposes two endpoints, one to get information about a specific transaction id, and one to push a transaction to the BigchainDB cluster. Those endpoints are documented at: +Please note that by default the server binds to `0.0.0.0:9984`, hence the API +is exposed to the world. + +The HTTP API currently exposes two endpoints, one to get information about a +specific transaction id, and one to push a transaction to the BigchainDB +cluster. Those endpoints are documented at: + +- [http://docs.bigchaindb.apiary.io/](http://docs.bigchaindb.apiary.io/) -[http://docs.bigchaindb.apiary.io/](http://docs.bigchaindb.apiary.io/) diff --git a/docs/source/installing-server.md b/docs/source/installing-server.md index c168f62d..4047f817 100644 --- a/docs/source/installing-server.md +++ b/docs/source/installing-server.md @@ -94,10 +94,16 @@ $ rethinkdb Then open a different terminal and run: ```text -$ bigchaindb start +$ bigchaindb init ``` -During its first run, BigchainDB Server takes care of configuring a single node environment. +During its first run, the command takes care of configuring a single node environment. + + +After configuring the node, you can start it with: +```text +$ bigchaindb start +``` ## Run BigchainDB with Docker From 0692fe04d0175162409e7f440d3994cb6c1b393f Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 7 Apr 2016 14:16:01 +0200 Subject: [PATCH 12/25] Print config using json --- bigchaindb/commands/bigchain.py | 5 +-- docs/source/bigchaindb-cli.md | 65 ++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 1832b99f..0b82986a 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -5,6 +5,7 @@ import os import logging import argparse import copy +import json import bigchaindb import bigchaindb.config_utils @@ -21,8 +22,6 @@ logger = logging.getLogger(__name__) def run_show_config(args): """Show the current configuration""" - from pprint import pprint - # 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. @@ -31,7 +30,7 @@ def run_show_config(args): del config['CONFIGURED'] private_key = config['keypair']['private'] config['keypair']['private'] = 'x' * 45 if private_key else None - pprint(config) + print(json.dumps(config, indent=4, sort_keys=True)) def run_configure(args, skip_if_exists=False): diff --git a/docs/source/bigchaindb-cli.md b/docs/source/bigchaindb-cli.md index a1b9e778..ddb04e1c 100644 --- a/docs/source/bigchaindb-cli.md +++ b/docs/source/bigchaindb-cli.md @@ -35,18 +35,25 @@ Note that there is a precedence in reading configuration values: This means that if the default configuration contains an entry that is: -``` -{... - "database": {"host": "localhost", - "port": 28015} -...} +```json +{ + + "database": { + "host": "localhost", + "port": 28015 + } + +} ``` while your local file `local.json` contains: -``` -{... - "database": {"host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com"} -...} +```json +{ + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com" + } +} + ``` and you run this command: @@ -58,18 +65,34 @@ $ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ ``` 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': '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}} +```json +{ + "api_endpoint": "http://localhost:8008/api/v1", + "consensus_plugin": "default", + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com", + "name": "bigchain", + "port": 4242 + }, + "keypair": { + "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "public": "nJq6EmdUkvFjQRB5hFvDmvZtv1deb3W3RgmiAq6dyygC" + }, + "keyring": [ + "pubkey0", + "pubkey1" + ], + "server": { + "bind": "0.0.0.0:9984", + "threads": null, + "workers": null + }, + "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 From ae641d6a9611877992ae526b71c433c46db233df Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 7 Apr 2016 14:31:34 +0200 Subject: [PATCH 13/25] Fix tests --- tests/test_commands.py | 5 ++--- tests/utils/test_config_utils.py | 7 ++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index 895efc07..1ad96d45 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,3 +1,4 @@ +import json from argparse import Namespace from pprint import pprint import copy @@ -109,9 +110,7 @@ def test_bigchain_show_config(capsys, mock_file_config): output_config, _ = capsys.readouterr() config['keypair']['private'] = 'x' * 45 del config['CONFIGURED'] - pprint(config) - expected_outout_config, _ = capsys.readouterr() - assert output_config == expected_outout_config + assert output_config.strip() == json.dumps(config, indent=4, sort_keys=True) def test_bigchain_run_init_when_db_exists(mock_file_config, mock_db_init_with_existing_db): diff --git a/tests/utils/test_config_utils.py b/tests/utils/test_config_utils.py index 9defc601..eafcef08 100644 --- a/tests/utils/test_config_utils.py +++ b/tests/utils/test_config_utils.py @@ -120,6 +120,11 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch): assert bigchaindb.config == { 'CONFIGURED': True, + 'server': { + 'bind': '0.0.0.0:9984', + 'workers': None, + 'threads': None, + }, 'database': { 'host': 'test-host', 'port': 4242, @@ -135,6 +140,6 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch): 'port': 8125, 'rate': 0.01, }, - 'api_endpoint': 'http://localhost:8008/api/v1', + 'api_endpoint': 'http://localhost:9984/api/v1', 'consensus_plugin': 'default', } From c9cd8421513798fbfbb567101096cb8511463f89 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 7 Apr 2016 17:54:36 +0200 Subject: [PATCH 14/25] Avoid loading the config located in the home of the current user --- bigchaindb/commands/bigchain.py | 2 +- tests/conftest.py | 12 ++++++++++++ tests/test_commands.py | 16 ++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 0b82986a..c460ae15 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -58,7 +58,7 @@ def run_configure(args, skip_if_exists=False): conf['keypair']['private'], conf['keypair']['public'] = crypto.generate_key_pair() if not args.yes: - for key in ('host', 'port'): + for key in ('bind', ): val = conf['server'][key] conf['server'][key] = input('API Server {}? (default `{}`): '.format(key, val)) or val diff --git a/tests/conftest.py b/tests/conftest.py index 3781b2b6..f73fc63c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,6 +29,18 @@ USER_PRIVATE_KEY = 'GmRZxQdQv7tooMijXytQkexKuFN6mJocciJarAmMwTX2' USER_PUBLIC_KEY = 'r3cEu8GNoz8rYpNJ61k7GqfR8VEvdUbtyHce8u1kaYwh' +# We need this function to avoid loading an existing +# conf file located in the home of the user running +# the tests. If it's too aggressive we can change it +# later. +@pytest.fixture(scope='function', autouse=True) +def ignore_local_config_file(monkeypatch): + def mock_file_config(filename=None): + raise FileNotFoundError() + + monkeypatch.setattr('bigchaindb.config_utils.file_config', mock_file_config) + + @pytest.fixture def restore_config(request, node_config): from bigchaindb import config_utils diff --git a/tests/test_commands.py b/tests/test_commands.py index 1ad96d45..64918cd4 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -12,12 +12,6 @@ def mock_run_configure(monkeypatch): monkeypatch.setattr(bigchain, 'run_configure', lambda *args, **kwargs: None) -@pytest.fixture -def mock_file_config(monkeypatch): - from bigchaindb import config_utils - monkeypatch.setattr(config_utils, 'file_config', lambda *args, **kwargs: {}) - - @pytest.fixture def mock_write_config(monkeypatch): from bigchaindb import config_utils @@ -66,8 +60,7 @@ def mock_bigchaindb_backup_config(monkeypatch): monkeypatch.setattr('bigchaindb._config', config) -def test_bigchain_run_start(mock_run_configure, mock_file_config, - mock_processes_start, mock_db_init_with_existing_db): +def test_bigchain_run_start(mock_run_configure, mock_processes_start, mock_db_init_with_existing_db): from bigchaindb.commands.bigchain import run_start args = Namespace(config=None, yes=True) run_start(args) @@ -101,25 +94,24 @@ def test_bigchain_run_start_assume_yes_create_default_config(monkeypatch, mock_p # TODO Please beware, that if debugging, the "-s" switch for pytest will # interfere with capsys. # See related issue: https://github.com/pytest-dev/pytest/issues/128 -def test_bigchain_show_config(capsys, mock_file_config): +def test_bigchain_show_config(capsys): from bigchaindb import config from bigchaindb.commands.bigchain import run_show_config args = Namespace(config=None) _, _ = capsys.readouterr() run_show_config(args) output_config, _ = capsys.readouterr() - config['keypair']['private'] = 'x' * 45 del config['CONFIGURED'] assert output_config.strip() == json.dumps(config, indent=4, sort_keys=True) -def test_bigchain_run_init_when_db_exists(mock_file_config, mock_db_init_with_existing_db): +def test_bigchain_run_init_when_db_exists(mock_db_init_with_existing_db): from bigchaindb.commands.bigchain import run_init args = Namespace(config=None) run_init(args) -def test_drop_existing_db(mock_file_config, mock_rethink_db_drop): +def test_drop_existing_db(mock_rethink_db_drop): from bigchaindb.commands.bigchain import run_drop args = Namespace(config=None, yes=True) run_drop(args) From 1ddfa2becbbbfc5c0578f569c98d88df246db44e Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 7 Apr 2016 18:06:04 +0200 Subject: [PATCH 15/25] Add explicit tests for update_types --- bigchaindb/config_utils.py | 8 +++----- tests/utils/test_config_utils.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index 19caef90..df63e7c2 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -113,12 +113,10 @@ def env_config(config): return map_leafs(load_from_env, config) -def update_types(config): +def update_types(config, reference, list_sep=':'): """Return a new configuration where all the values types are aligned with the ones in the default configuration""" - reference = bigchaindb.config - def _coerce(current, value): # Coerce a value to the `current` type. try: @@ -130,7 +128,7 @@ def update_types(config): # is a string. if isinstance(current, list) and isinstance(value, str): # If so, we use the colon as the separator - return value.split(':') + return value.split(list_sep) try: # If we are here, we should try to apply the type @@ -165,7 +163,7 @@ def dict_config(config): update made to ``bigchaindb.config`` will be lost. """ bigchaindb.config = copy.deepcopy(bigchaindb._config) - update(bigchaindb.config, update_types(config)) + update(bigchaindb.config, update_types(config, bigchaindb.config)) bigchaindb.config['CONFIGURED'] = True diff --git a/tests/utils/test_config_utils.py b/tests/utils/test_config_utils.py index eafcef08..cec7743f 100644 --- a/tests/utils/test_config_utils.py +++ b/tests/utils/test_config_utils.py @@ -93,6 +93,27 @@ def test_map_leafs_iterator(): } +def test_update_types(): + from bigchaindb import config_utils + + raw = { + 'a_string': 'test', + 'an_int': '42', + 'a_float': '3.14', + 'a_list': 'a:b:c', + } + + reference = { + 'a_string': 'test', + 'an_int': 42, + 'a_float': 3.14, + 'a_list': ['a', 'b', 'c'], + } + + result = config_utils.update_types(raw, reference) + assert result == reference + + def test_env_config(monkeypatch): monkeypatch.setattr('os.environ', {'BIGCHAINDB_DATABASE_HOST': 'test-host', 'BIGCHAINDB_DATABASE_PORT': 'test-port'}) @@ -143,3 +164,4 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch): 'api_endpoint': 'http://localhost:9984/api/v1', 'consensus_plugin': 'default', } + From 32e08b7c63edab652d8b2a3e94ce8446b4de268e Mon Sep 17 00:00:00 2001 From: vrde Date: Fri, 8 Apr 2016 10:14:14 +0200 Subject: [PATCH 16/25] Remove useless func --- bigchaindb/config_utils.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index df63e7c2..0ce41360 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -51,13 +51,6 @@ def map_leafs(func, mapping): return _inner(copy.deepcopy(mapping)) -def get_casted_value(original, to_convert): - try: - return original(to_convert) - except TypeError: - return type(original)(to_convert) - - # Thanks Alex <3 # http://stackoverflow.com/a/3233356/597097 def update(d, u): From d2b44890f26646ab61c1a0567a827323d0ae6b6f Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Fri, 8 Apr 2016 14:04:17 +0200 Subject: [PATCH 17/25] changed bigchaindb-benchmark to use the new configuration loader --- bigchaindb/commands/bigchain_benchmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigchaindb/commands/bigchain_benchmark.py b/bigchaindb/commands/bigchain_benchmark.py index 96ba0a5b..2bac4c08 100644 --- a/bigchaindb/commands/bigchain_benchmark.py +++ b/bigchaindb/commands/bigchain_benchmark.py @@ -34,7 +34,7 @@ def _run_load(tx_left, stats): def run_load(args): - bigchaindb.config_utils.file_config(args.config) + bigchaindb.config_utils.autoconfigure(filename=args.config, force=True) logger.info('Starting %s processes', args.multiprocess) stats = logstats.Logstats() logstats.thread.start(stats) From f90254c3c92b4a454d1dab1ac2e51965413dba33 Mon Sep 17 00:00:00 2001 From: vrde Date: Fri, 8 Apr 2016 15:14:14 +0200 Subject: [PATCH 18/25] Update documentation --- docs/source/bigchaindb-cli.md | 92 ------------- docs/source/configuration.md | 247 ++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 92 deletions(-) create mode 100644 docs/source/configuration.md diff --git a/docs/source/bigchaindb-cli.md b/docs/source/bigchaindb-cli.md index ddb04e1c..4186426e 100644 --- a/docs/source/bigchaindb-cli.md +++ b/docs/source/bigchaindb-cli.md @@ -25,95 +25,3 @@ $ bigchaindb-benchmark load -h Note that you can always start `bigchaindb` using a different config file using the `-c` option. For more information check the help with `bigchaindb -h`. - -# Precedence in reading configuration values - -Note that there is a precedence in reading configuration values: - - local config file; - - environment vars; - - default config file (contained in ``bigchaindb.__init__``). - -This means that if the default configuration contains an entry that is: - -```json -{ - - "database": { - "host": "localhost", - "port": 28015 - } - -} -``` - -while your local file `local.json` contains: -```json -{ - "database": { - "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com" - } -} - -``` - -and you run this command: -``` -$ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ - BIGCHAINDB_DATABASE_PORT=4242 \ - BIGCHAINDB_KEYRING=pubkey0:pubkey1 \ - bigchaindb -c local.json show-config -``` - -you will get: -```json -{ - "api_endpoint": "http://localhost:8008/api/v1", - "consensus_plugin": "default", - "database": { - "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com", - "name": "bigchain", - "port": 4242 - }, - "keypair": { - "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "public": "nJq6EmdUkvFjQRB5hFvDmvZtv1deb3W3RgmiAq6dyygC" - }, - "keyring": [ - "pubkey0", - "pubkey1" - ], - "server": { - "bind": "0.0.0.0:9984", - "threads": null, - "workers": null - }, - "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 - -``` -- BIGCHAINDB_DATABASE_HOST -- BIGCHAINDB_DATABASE_PORT -- BIGCHAINDB_DATABASE_NAME -- BIGCHAINDB_KEYPAIR_PUBLIC -- BIGCHAINDB_KEYPAIR_PRIVATE -- BIGCHAINDB_KEYRING -- BIGCHAINDB_STATSD_HOST -- BIGCHAINDB_STATSD_PORT -- BIGCHAINDB_STATSD_RATE -- BIGCHAINDB_API_ENDPOINT -- BIGCHAINDB_CONSENSUS_PLUGIN -- BIGCHAINDB_SERVER_BIND -- BIGCHAINDB_SERVER_WORKERS -- BIGCHAINDB_SERVER_THREADS -``` diff --git a/docs/source/configuration.md b/docs/source/configuration.md new file mode 100644 index 00000000..6a906b96 --- /dev/null +++ b/docs/source/configuration.md @@ -0,0 +1,247 @@ +# Configuring a BigchainDB Node + +The standard way to configure a BigchainDB node is to run the command `configure`: + +```text +$ bigchaindb configure +``` + +This command will generate a new keypair and will guide you through the +configuration of the system. By default keypair and settings will be saved in the +`$HOME/.bigchaindb` file. + + +## Using a different path for the configuration + +By default the configuration is stored in `$HOME/.bigchaindb`, if you want to +specify a different path for your configuration you can use the `-c` parameter. +This works for every subcommand under the `bigchaindb` executable. + +For example, if you want to **generate** a new configuration file under a +specific path, you can run: + +``` +$ bigchaindb -c local.json configure +$ bigchaindb -c test.json configure +``` + +This will create two new files called `local.json` and `test.json` in your +current working directory. + +From now on, you can refer to those configuration files using the `-c` +parameter, for example: + +``` +$ bigchaindb -c local.json show-config +``` + +Will show the configuration for `local.json`. + +If you want to **start** BigchainDB with the `test.json` configuration, you can +try: + +``` +$ bigchaindb -c test.json start +``` + + +## Using environ variables to configure the node + +Sometimes it's more convenient to use environment variables to configure the +system, for example when using Docker or Heroku. Another use case is to have a +*volatile*, throw away configuration you need to test something quickly. In +those cases you can configure the system using environment variables. + +Every configuration key can be mapped to an environment variable. The +environment variables available are: +``` +- BIGCHAINDB_DATABASE_HOST +- BIGCHAINDB_DATABASE_PORT +- BIGCHAINDB_DATABASE_NAME +- BIGCHAINDB_KEYPAIR_PUBLIC +- BIGCHAINDB_KEYPAIR_PRIVATE +- BIGCHAINDB_KEYRING +- BIGCHAINDB_STATSD_HOST +- BIGCHAINDB_STATSD_PORT +- BIGCHAINDB_STATSD_RATE +- BIGCHAINDB_API_ENDPOINT +- BIGCHAINDB_CONSENSUS_PLUGIN +- BIGCHAINDB_SERVER_BIND +- BIGCHAINDB_SERVER_WORKERS +- BIGCHAINDB_SERVER_THREADS +``` + +As an example, let's assume we **don't** have any configuration file stored in +the default location `$HOME/.bigchaindb`. + +As you can see, `show-config` displays the default configuration (and a +warning): +``` +$ bigchaindb show-config +WARNING:bigchaindb.config_utils:Cannot find config file `/home/vrde/.bigchaindb`. +{ + "api_endpoint": "http://localhost:9984/api/v1", + "consensus_plugin": "default", + "database": { + "host": "localhost", + "name": "bigchain", + "port": 28015 + }, + "keypair": { + "private": null, + "public": null + }, + "keyring": [], + "server": { + "bind": "0.0.0.0:9984", + "threads": null, + "workers": null + }, + "statsd": { + "host": "localhost", + "port": 8125, + "rate": 0.01 + } +} +``` + +If we try to run the node, the command will fail: + +``` +$ bigchaindb start +WARNING:bigchaindb.config_utils:Cannot find config file `/home/vrde/.bigchaindb`. +INFO:bigchaindb.db.utils:Create: +INFO:bigchaindb.db.utils: - database `bigchain` +INFO:bigchaindb.db.utils: - tables +INFO:bigchaindb.db.utils: - indexes +INFO:bigchaindb.db.utils: - genesis block +Traceback (most recent call last): + File "/home/vrde/.local/share/virtualenvs/bigchain/bin/bigchaindb", line 9, in + load_entry_point('BigchainDB', 'console_scripts', 'bigchaindb')() + File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/bigchain.py", line 137, in main + start(parser, globals()) + File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/utils.py", line 41, in start + func(args) + File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/bigchain.py", line 101, in run_start + db.init() + File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/db/utils.py", line 62, in init + b = bigchaindb.Bigchain() + File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/core.py", line 58, in __init__ + raise exceptions.KeypairNotFoundException() +bigchaindb.exceptions.KeypairNotFoundException +``` + +This is failing as expected: a BigchainDB node needs at least a key pair to work. +We can pass the key pair using environment variables: +``` +$ BIGCHAINDB_KEYPAIR_PUBLIC=26y9EuyGP44JXxqcvF8GbCJGqkiqFXddZzxVjLU3rWbHp \ + BIGCHAINDB_KEYPAIR_PRIVATE=9PkLfHbzXnSSNnb1sSBL73C2MydzKLs5fAHoA4Q7otrG \ + bigchaindb start +``` + +We can also run `show-config` to see how the configuration looks like: +``` +$ BIGCHAINDB_KEYPAIR_PUBLIC=26y9EuyGP44JXxqcvF8GbCJGqkiqFXddZzxVjLU3rWbHp \ + BIGCHAINDB_KEYPAIR_PRIVATE=9PkLfHbzXnSSNnb1sSBL73C2MydzKLs5fAHoA4Q7otrG \ + bigchaindb show-config + +WARNING:bigchaindb.config_utils:Cannot find config file `/home/vrde/.bigchaindb`. +{ + "api_endpoint": "http://localhost:9984/api/v1", + "consensus_plugin": "default", + "database": { + "host": "localhost", + "name": "bigchain", + "port": 28015 + }, + "keypair": { + "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "public": "26y9EuyGP44JXxqcvF8GbCJGqkiqFXddZzxVjLU3rWbHp" + }, + "keyring": [], + "server": { + "bind": "0.0.0.0:9984", + "threads": null, + "workers": null + }, + "statsd": { + "host": "localhost", + "port": 8125, + "rate": 0.01 + } +} +``` + + +# Precedence in reading configuration values + +Note that there is a precedence in reading configuration values: + - local config file; + - environment vars; + - default config file (contained in ``bigchaindb.__init__``). + +This means that if the default configuration contains an entry that is: + +```json +{ + + "database": { + "host": "localhost", + "port": 28015 + } + +} +``` + +while your local file `local.json` contains: +```json +{ + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com" + } +} + +``` + +and you run this command: +``` +$ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ + BIGCHAINDB_DATABASE_PORT=4242 \ + BIGCHAINDB_KEYRING=pubkey0:pubkey1 \ + bigchaindb -c local.json show-config +``` + +you will get: +```json +{ + "api_endpoint": "http://localhost:8008/api/v1", + "consensus_plugin": "default", + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com", + "name": "bigchain", + "port": 4242 + }, + "keypair": { + "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "public": "nJq6EmdUkvFjQRB5hFvDmvZtv1deb3W3RgmiAq6dyygC" + }, + "keyring": [ + "pubkey0", + "pubkey1" + ], + "server": { + "bind": "0.0.0.0:9984", + "threads": null, + "workers": null + }, + "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. + From 82155764975e6d62401b3cc4b8f95468ab525aa3 Mon Sep 17 00:00:00 2001 From: vrde Date: Fri, 8 Apr 2016 15:56:10 +0200 Subject: [PATCH 19/25] Remove exception stacktrace when starting without keypair --- bigchaindb/commands/bigchain.py | 6 +++++- bigchaindb/db/utils.py | 4 +++- docs/source/configuration.md | 20 +------------------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index c460ae15..912e5ed7 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -10,7 +10,7 @@ import json import bigchaindb import bigchaindb.config_utils from bigchaindb import db -from bigchaindb.exceptions import DatabaseAlreadyExists +from bigchaindb.exceptions import DatabaseAlreadyExists, KeypairNotFoundException from bigchaindb.commands.utils import base_parser, start from bigchaindb.processes import Processes from bigchaindb import crypto @@ -101,6 +101,10 @@ def run_start(args): db.init() except DatabaseAlreadyExists: pass + except KeypairNotFoundException: + print('Cannot start BigchainDB, no keypair found. Did you run `bigchaindb configure`?') + exit(1) + processes = Processes() logger.info('Start bigchaindb main process') processes.start() diff --git a/bigchaindb/db/utils.py b/bigchaindb/db/utils.py index d5551833..b0a44d6a 100644 --- a/bigchaindb/db/utils.py +++ b/bigchaindb/db/utils.py @@ -19,6 +19,9 @@ def get_conn(): def init(): + # Try to access the keypair, throws an exception if it does not exist + b = bigchaindb.Bigchain() + conn = get_conn() dbname = bigchaindb.config['database']['name'] @@ -59,7 +62,6 @@ def init(): r.db(dbname).table('bigchain').index_wait().run(conn) logger.info(' - genesis block') - b = bigchaindb.Bigchain() b.create_genesis_block() logger.info('Done, have fun!') diff --git a/docs/source/configuration.md b/docs/source/configuration.md index 6a906b96..efb71cc4 100644 --- a/docs/source/configuration.md +++ b/docs/source/configuration.md @@ -110,25 +110,7 @@ If we try to run the node, the command will fail: ``` $ bigchaindb start WARNING:bigchaindb.config_utils:Cannot find config file `/home/vrde/.bigchaindb`. -INFO:bigchaindb.db.utils:Create: -INFO:bigchaindb.db.utils: - database `bigchain` -INFO:bigchaindb.db.utils: - tables -INFO:bigchaindb.db.utils: - indexes -INFO:bigchaindb.db.utils: - genesis block -Traceback (most recent call last): - File "/home/vrde/.local/share/virtualenvs/bigchain/bin/bigchaindb", line 9, in - load_entry_point('BigchainDB', 'console_scripts', 'bigchaindb')() - File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/bigchain.py", line 137, in main - start(parser, globals()) - File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/utils.py", line 41, in start - func(args) - File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/commands/bigchain.py", line 101, in run_start - db.init() - File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/db/utils.py", line 62, in init - b = bigchaindb.Bigchain() - File "/home/vrde/ascribe/repos/bigchaindb/bigchaindb/core.py", line 58, in __init__ - raise exceptions.KeypairNotFoundException() -bigchaindb.exceptions.KeypairNotFoundException +Cannot start BigchainDB, no keypair found. Did you run `bigchaindb configure`? ``` This is failing as expected: a BigchainDB node needs at least a key pair to work. From 9e7c55a08331629bea8c3acf6a9c009df19bbaea Mon Sep 17 00:00:00 2001 From: Sylvain Bellemare Date: Mon, 11 Apr 2016 09:43:17 +0200 Subject: [PATCH 20/25] Add docs for config when using docker (#169) --- docs/source/installing-server.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/source/installing-server.md b/docs/source/installing-server.md index 4047f817..6b39c5a2 100644 --- a/docs/source/installing-server.md +++ b/docs/source/installing-server.md @@ -128,8 +128,22 @@ then do a one-time configuration step to create the config file; it will be stored on your host machine under ` ~/.bigchaindb_docker/config`: ```text $ docker-compose run --rm bigchaindb bigchaindb configure +Starting bigchaindb_rethinkdb-data_1 +Generating keypair +API Server bind? (default `0.0.0.0:9984`): +Database host? (default `localhost`): rethinkdb +Database port? (default `28015`): +Database name? (default `bigchain`): +Statsd host? (default `localhost`): statsd +Statsd port? (default `8125`): +Statsd rate? (default `0.01`): +Ready to go! ``` +As shown above, make sure that you set the database and statsd hosts to their +corresponding service names (`rethinkdb`, `statsd`), defined in`docker-compose.yml` +and `docker-compose-monitor.yml`. + You can then start it up (in the background, as a daemon) using: ```text $ docker-compose up -d From a59797c491fb6461ecd39bda8edf459cc03e7fd4 Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 11 Apr 2016 11:26:58 +0200 Subject: [PATCH 21/25] Add more docs to config --- docs/source/configuration.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/source/configuration.md b/docs/source/configuration.md index efb71cc4..64369384 100644 --- a/docs/source/configuration.md +++ b/docs/source/configuration.md @@ -54,22 +54,23 @@ those cases you can configure the system using environment variables. Every configuration key can be mapped to an environment variable. The environment variables available are: -``` -- BIGCHAINDB_DATABASE_HOST -- BIGCHAINDB_DATABASE_PORT -- BIGCHAINDB_DATABASE_NAME -- BIGCHAINDB_KEYPAIR_PUBLIC -- BIGCHAINDB_KEYPAIR_PRIVATE -- BIGCHAINDB_KEYRING -- BIGCHAINDB_STATSD_HOST -- BIGCHAINDB_STATSD_PORT -- BIGCHAINDB_STATSD_RATE -- BIGCHAINDB_API_ENDPOINT -- BIGCHAINDB_CONSENSUS_PLUGIN -- BIGCHAINDB_SERVER_BIND -- BIGCHAINDB_SERVER_WORKERS -- BIGCHAINDB_SERVER_THREADS -``` + +- `BIGCHAINDB_DATABASE_HOST` defines the database hostname to connect to. +- `BIGCHAINDB_DATABASE_PORT` defines the database port to connect to. +- `BIGCHAINDB_DATABASE_NAME` defines the database name to use. +- `BIGCHAINDB_KEYPAIR_PUBLIC` defines the public key of the BigchainDB node. +- `BIGCHAINDB_KEYPAIR_PRIVATE` defines the private key of the BigchainDB noce. +- `BIGCHAINDB_KEYRING` is a colon-separated list of public keys +- `BIGCHAINDB_STATSD_HOST` defines the host of the statsd server for [monitoring](monitoring.html). +- `BIGCHAINDB_STATSD_PORT` defines the port of the statsd server for monitoring. +- `BIGCHAINDB_STATSD_RATE` is a float between `0` and `1` that defines the fraction of transaction operations sampled. +- `BIGCHAINDB_API_ENDPOINT` defines the API endpoint to use. +- `BIGCHAINDB_CONSENSUS_PLUGIN` defines the name of the [consensus plugin](consensus.html) to use. +- `BIGCHAINDB_SERVER_BIND` defines where to bind the server socket, the format is `addr:port`. +- `BIGCHAINDB_SERVER_WORKERS defines the [number of workers](http://docs.gunicorn.org/en/stable/settings.html#workers) + to start for the server API. +- `BIGCHAINDB_SERVER_THREADS defines the [number of threads](http://docs.gunicorn.org/en/stable/settings.html#threads) + to start for the server API. As an example, let's assume we **don't** have any configuration file stored in the default location `$HOME/.bigchaindb`. From ab8113a91cb9040a10d73fd6789ac5268646cb5a Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 11 Apr 2016 11:29:42 +0200 Subject: [PATCH 22/25] Use `sys.exit` instead of `exit` --- bigchaindb/commands/bigchain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 912e5ed7..15092db5 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -2,6 +2,7 @@ import os +import sys import logging import argparse import copy @@ -102,8 +103,7 @@ def run_start(args): except DatabaseAlreadyExists: pass except KeypairNotFoundException: - print('Cannot start BigchainDB, no keypair found. Did you run `bigchaindb configure`?') - exit(1) + sys.exit('Cannot start BigchainDB, no keypair found. Did you run `bigchaindb configure`?') processes = Processes() logger.info('Start bigchaindb main process') From bdc2cf21c47d48aff14734ff0c8a7f6c39a2e0c0 Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 11 Apr 2016 11:31:33 +0200 Subject: [PATCH 23/25] Add missing backtick --- docs/source/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/configuration.md b/docs/source/configuration.md index 64369384..b9c3c724 100644 --- a/docs/source/configuration.md +++ b/docs/source/configuration.md @@ -67,9 +67,9 @@ environment variables available are: - `BIGCHAINDB_API_ENDPOINT` defines the API endpoint to use. - `BIGCHAINDB_CONSENSUS_PLUGIN` defines the name of the [consensus plugin](consensus.html) to use. - `BIGCHAINDB_SERVER_BIND` defines where to bind the server socket, the format is `addr:port`. -- `BIGCHAINDB_SERVER_WORKERS defines the [number of workers](http://docs.gunicorn.org/en/stable/settings.html#workers) +- `BIGCHAINDB_SERVER_WORKERS` defines the [number of workers](http://docs.gunicorn.org/en/stable/settings.html#workers) to start for the server API. -- `BIGCHAINDB_SERVER_THREADS defines the [number of threads](http://docs.gunicorn.org/en/stable/settings.html#threads) +- `BIGCHAINDB_SERVER_THREADS` defines the [number of threads](http://docs.gunicorn.org/en/stable/settings.html#threads) to start for the server API. As an example, let's assume we **don't** have any configuration file stored in From ff2e36a44e1bdf657ac6cb22ef666012522e33d7 Mon Sep 17 00:00:00 2001 From: troymc Date: Mon, 11 Apr 2016 14:51:26 +0200 Subject: [PATCH 24/25] Edits to configuration.md and related docs --- docs/source/configuration.md | 202 +++++++++++----------- docs/source/index.rst | 1 + docs/source/installing-server.md | 11 +- docs/source/python-server-api-examples.md | 2 + 4 files changed, 110 insertions(+), 106 deletions(-) diff --git a/docs/source/configuration.md b/docs/source/configuration.md index b9c3c724..b5d538e1 100644 --- a/docs/source/configuration.md +++ b/docs/source/configuration.md @@ -1,20 +1,21 @@ # Configuring a BigchainDB Node -The standard way to configure a BigchainDB node is to run the command `configure`: +The BigchainDB configuration settings for a particular node are stored on that node in a configuration file at `$HOME/.bigchaindb`. That file doesn't exist by default. (It's not created when installing BigchainDB.) One could create it using a text editor, but it's easiest to use the `bigchaindb configure` command: ```text $ bigchaindb configure ``` -This command will generate a new keypair and will guide you through the -configuration of the system. By default keypair and settings will be saved in the -`$HOME/.bigchaindb` file. +It will ask some questions and generate a new keypair (i.e. a private key and corresponding public key for the node). See below for some additional explanation of the settings and their meanings. To accept a suggested default value, press Enter or Return. If you want to accept all the default values, use the `-y` option when running the command, that is: +```text +$ bigchaindb -y configure +``` -## Using a different path for the configuration +## Using a Different Path for the Configuration File -By default the configuration is stored in `$HOME/.bigchaindb`, if you want to -specify a different path for your configuration you can use the `-c` parameter. +By default, the configuration settings are stored in `$HOME/.bigchaindb`. If you want to +specify a different path for your configuration file, you can use the `-c` parameter. This works for every subcommand under the `bigchaindb` executable. For example, if you want to **generate** a new configuration file under a @@ -25,57 +26,126 @@ $ bigchaindb -c local.json configure $ bigchaindb -c test.json configure ``` -This will create two new files called `local.json` and `test.json` in your +This will create two new files named `local.json` and `test.json` in your current working directory. From now on, you can refer to those configuration files using the `-c` -parameter, for example: +parameter; for example: ``` $ bigchaindb -c local.json show-config ``` -Will show the configuration for `local.json`. +will show the configuration for `local.json`. -If you want to **start** BigchainDB with the `test.json` configuration, you can -try: +If you want to **start** BigchainDB with the `test.json` configuration file, you can use: ``` $ bigchaindb -c test.json start ``` -## Using environ variables to configure the node +## Using Environment Variables to Configure the Node Sometimes it's more convenient to use environment variables to configure the -system, for example when using Docker or Heroku. Another use case is to have a -*volatile*, throw away configuration you need to test something quickly. In -those cases you can configure the system using environment variables. +system, for example when using Docker or Heroku. In +that case you can configure the system using environment variables. -Every configuration key can be mapped to an environment variable. The +Every configuration parameter can be mapped to an environment variable. The environment variables available are: -- `BIGCHAINDB_DATABASE_HOST` defines the database hostname to connect to. -- `BIGCHAINDB_DATABASE_PORT` defines the database port to connect to. -- `BIGCHAINDB_DATABASE_NAME` defines the database name to use. +- `BIGCHAINDB_DATABASE_HOST` defines the RethinkDB database hostname to connect to. +- `BIGCHAINDB_DATABASE_PORT` defines the RethinkDB database port to connect to. +- `BIGCHAINDB_DATABASE_NAME` defines the RethinkDB database name to use. - `BIGCHAINDB_KEYPAIR_PUBLIC` defines the public key of the BigchainDB node. -- `BIGCHAINDB_KEYPAIR_PRIVATE` defines the private key of the BigchainDB noce. -- `BIGCHAINDB_KEYRING` is a colon-separated list of public keys -- `BIGCHAINDB_STATSD_HOST` defines the host of the statsd server for [monitoring](monitoring.html). +- `BIGCHAINDB_KEYPAIR_PRIVATE` defines the private key of the BigchainDB node. +- `BIGCHAINDB_KEYRING` is a colon-separated list of the public keys of all _other_ nodes in the cluster. +- `BIGCHAINDB_STATSD_HOST` defines the hostname of the statsd server for [monitoring](monitoring.html). - `BIGCHAINDB_STATSD_PORT` defines the port of the statsd server for monitoring. - `BIGCHAINDB_STATSD_RATE` is a float between `0` and `1` that defines the fraction of transaction operations sampled. -- `BIGCHAINDB_API_ENDPOINT` defines the API endpoint to use. +- `BIGCHAINDB_API_ENDPOINT` defines the API endpoint to use (e.g. `http://localhost:9984/api/v1`). - `BIGCHAINDB_CONSENSUS_PLUGIN` defines the name of the [consensus plugin](consensus.html) to use. -- `BIGCHAINDB_SERVER_BIND` defines where to bind the server socket, the format is `addr:port`. +- `BIGCHAINDB_SERVER_BIND` defines where to bind the server socket, the format is `addr:port` (e.g. `0.0.0.0:9984`). - `BIGCHAINDB_SERVER_WORKERS` defines the [number of workers](http://docs.gunicorn.org/en/stable/settings.html#workers) to start for the server API. - `BIGCHAINDB_SERVER_THREADS` defines the [number of threads](http://docs.gunicorn.org/en/stable/settings.html#threads) to start for the server API. -As an example, let's assume we **don't** have any configuration file stored in -the default location `$HOME/.bigchaindb`. -As you can see, `show-config` displays the default configuration (and a +## Order of Precedence in Determining Configuration Values + +All configuration values start with their default values (defined in `bigchaindb.__init__`), but a default value can be overriden by an environment variable, and a value set by an environment variable can be overriden by a value in a local configuration file (`$HOME/.bigchaindb` or the location specified by the `-c` command-line option). + +In summary, there is an order of precedence in reading configuration values: +1. local configuration file +2. environment variables +3. default configuration file (defined in ``bigchaindb.__init__``) + +This means that if the default configuration contains: + +```json +{ + "database": { + "host": "localhost", + "port": 28015 + } +} +``` + +while the local file `local.json` contains: +```json +{ + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com" + } +} + +``` + +and you run this command: +``` +$ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ + BIGCHAINDB_DATABASE_PORT=4242 \ + BIGCHAINDB_KEYRING=pubkey0:pubkey1 \ + bigchaindb -c local.json show-config +``` + +you will get the following values for all the configuration settings: +```json +{ + "api_endpoint": "http://localhost:8008/api/v1", + "consensus_plugin": "default", + "database": { + "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com", + "name": "bigchain", + "port": 4242 + }, + "keypair": { + "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "public": "nJq6EmdUkvFjQRB5hFvDmvZtv1deb3W3RgmiAq6dyygC" + }, + "keyring": [ + "pubkey0", + "pubkey1" + ], + "server": { + "bind": "0.0.0.0:9984", + "threads": null, + "workers": null + }, + "statsd": { + "host": "localhost", + "port": 8125, + "rate": 0.01 + } +} +``` + + +## Another Example + +As another example, let's assume we **don't** have any configuration file stored in +`$HOME/.bigchaindb`. As you can see, `show-config` displays the default configuration (and a warning): ``` $ bigchaindb show-config @@ -122,7 +192,7 @@ $ BIGCHAINDB_KEYPAIR_PUBLIC=26y9EuyGP44JXxqcvF8GbCJGqkiqFXddZzxVjLU3rWbHp \ bigchaindb start ``` -We can also run `show-config` to see how the configuration looks like: +We can also run `show-config` to see how the configuration looks: ``` $ BIGCHAINDB_KEYPAIR_PUBLIC=26y9EuyGP44JXxqcvF8GbCJGqkiqFXddZzxVjLU3rWbHp \ BIGCHAINDB_KEYPAIR_PRIVATE=9PkLfHbzXnSSNnb1sSBL73C2MydzKLs5fAHoA4Q7otrG \ @@ -154,77 +224,3 @@ WARNING:bigchaindb.config_utils:Cannot find config file `/home/vrde/.bigchaindb` } } ``` - - -# Precedence in reading configuration values - -Note that there is a precedence in reading configuration values: - - local config file; - - environment vars; - - default config file (contained in ``bigchaindb.__init__``). - -This means that if the default configuration contains an entry that is: - -```json -{ - - "database": { - "host": "localhost", - "port": 28015 - } - -} -``` - -while your local file `local.json` contains: -```json -{ - "database": { - "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com" - } -} - -``` - -and you run this command: -``` -$ BIGCHAINDB_DATABASE_HOST=anotherhost.com \ - BIGCHAINDB_DATABASE_PORT=4242 \ - BIGCHAINDB_KEYRING=pubkey0:pubkey1 \ - bigchaindb -c local.json show-config -``` - -you will get: -```json -{ - "api_endpoint": "http://localhost:8008/api/v1", - "consensus_plugin": "default", - "database": { - "host": "ec2-xx-xx-xxx-xxx.eu-central-1.compute.amazonaws.com", - "name": "bigchain", - "port": 4242 - }, - "keypair": { - "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "public": "nJq6EmdUkvFjQRB5hFvDmvZtv1deb3W3RgmiAq6dyygC" - }, - "keyring": [ - "pubkey0", - "pubkey1" - ], - "server": { - "bind": "0.0.0.0:9984", - "threads": null, - "workers": null - }, - "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. - diff --git a/docs/source/index.rst b/docs/source/index.rst index 8a75833f..ec10c228 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -15,6 +15,7 @@ Table of Contents introduction installing-server running-unit-tests + configuration python-server-api-examples bigchaindb-cli http-client-server-api diff --git a/docs/source/installing-server.md b/docs/source/installing-server.md index 6b39c5a2..7da2b1c4 100644 --- a/docs/source/installing-server.md +++ b/docs/source/installing-server.md @@ -80,6 +80,11 @@ Install from the source: $ python setup.py install ``` +If you want to update BigchainDB to reflect the latest local source code changes, you can use: +```text +$ pip install -e . +``` + ### How to Install BigchainDB on a VM with Vagrant One of our community members ([@Mec-Is](https://github.com/Mec-iS)) wrote [a page about how to install BigchainDB on a VM with Vagrant](https://gist.github.com/Mec-iS/b84758397f1b21f21700). @@ -94,13 +99,13 @@ $ rethinkdb Then open a different terminal and run: ```text +$ bigchaindb -y configure $ bigchaindb init ``` -During its first run, the command takes care of configuring a single node environment. +That creates a configuration file in `$HOME/.bigchaindb` (documented in [the section on configuration](configuration.html)), initializes the database, creates the tables, creates the indexes, and generates the genesis block. - -After configuring the node, you can start it with: +You can start BigchainDB Server using: ```text $ bigchaindb start ``` diff --git a/docs/source/python-server-api-examples.md b/docs/source/python-server-api-examples.md index 25fc5b19..2b2bfd86 100644 --- a/docs/source/python-server-api-examples.md +++ b/docs/source/python-server-api-examples.md @@ -11,6 +11,8 @@ We create a digital asset, sign it, write it to a BigchainDB Server instance, re First, make sure you have RethinkDB and BigchainDB _installed and running_, i.e. you [installed them](installing-server.html) and you ran: ```text $ rethinkdb +$ bigchaindb configure +$ bigchaindb init $ bigchaindb start ``` From 22923ee9d3046cbf08d447228018246cb2a3002c Mon Sep 17 00:00:00 2001 From: vrde Date: Tue, 12 Apr 2016 16:23:09 +0200 Subject: [PATCH 25/25] Force a config reset before every test --- bigchaindb/config_utils.py | 7 +++---- tests/conftest.py | 1 + tests/test_commands.py | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bigchaindb/config_utils.py b/bigchaindb/config_utils.py index 0ce41360..53eb7954 100644 --- a/bigchaindb/config_utils.py +++ b/bigchaindb/config_utils.py @@ -185,15 +185,14 @@ def autoconfigure(filename=None, config=None, force=False): newconfig = env_config(bigchaindb.config) - if config: - newconfig = update(newconfig, config) - try: - # 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) + if config: + newconfig = update(newconfig, config) + dict_config(newconfig) return newconfig diff --git a/tests/conftest.py b/tests/conftest.py index 40500a9f..44de6316 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -42,6 +42,7 @@ def ignore_local_config_file(monkeypatch): @pytest.fixture +@pytest.fixture(scope='function', autouse=True) def restore_config(request, node_config): from bigchaindb import config_utils config_utils.dict_config(node_config) diff --git a/tests/test_commands.py b/tests/test_commands.py index 64918cd4..c289f279 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -94,15 +94,18 @@ def test_bigchain_run_start_assume_yes_create_default_config(monkeypatch, mock_p # TODO Please beware, that if debugging, the "-s" switch for pytest will # interfere with capsys. # See related issue: https://github.com/pytest-dev/pytest/issues/128 +@pytest.mark.usefixtures('restore_config') def test_bigchain_show_config(capsys): from bigchaindb import config from bigchaindb.commands.bigchain import run_show_config + args = Namespace(config=None) _, _ = capsys.readouterr() run_show_config(args) - output_config, _ = capsys.readouterr() + output_config = json.loads(capsys.readouterr()[0]) del config['CONFIGURED'] - assert output_config.strip() == json.dumps(config, indent=4, sort_keys=True) + config['keypair']['private'] = 'x' * 45 + assert output_config == config def test_bigchain_run_init_when_db_exists(mock_db_init_with_existing_db):