mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge pull request #186 from bigchaindb/feat/179/cli-export-import-public-keys
Added CLI command to export public key
This commit is contained in:
commit
dadde325b8
@ -1,5 +1,7 @@
|
||||
"""Command line interface for the `bigchain` command."""
|
||||
|
||||
"""Implementation of the `bigchaindb` command,
|
||||
which is one of the commands in the BigchainDB
|
||||
command-line interface.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
@ -38,7 +40,7 @@ def run_configure(args, skip_if_exists=False):
|
||||
"""Run a script to configure the current node.
|
||||
|
||||
Args:
|
||||
skip_if_exists (bool): skip the function if a conf file already exists
|
||||
skip_if_exists (bool): skip the function if a config file already exists
|
||||
"""
|
||||
config_path = args.config or bigchaindb.config_utils.CONFIG_DEFAULT_PATH
|
||||
config_file_exists = os.path.exists(config_path)
|
||||
@ -48,7 +50,7 @@ def run_configure(args, skip_if_exists=False):
|
||||
|
||||
if config_file_exists and not args.yes:
|
||||
want = input('Config file `{}` exists, do you want to override it? '
|
||||
'(cannot be undone) [y/n]: '.format(config_path))
|
||||
'(cannot be undone) [y/N]: '.format(config_path))
|
||||
if want != 'y':
|
||||
return
|
||||
|
||||
@ -56,25 +58,49 @@ def run_configure(args, skip_if_exists=False):
|
||||
conf = copy.deepcopy(bigchaindb._config)
|
||||
|
||||
print('Generating keypair')
|
||||
conf['keypair']['private'], conf['keypair']['public'] = crypto.generate_key_pair()
|
||||
conf['keypair']['private'], conf['keypair']['public'] = \
|
||||
crypto.generate_key_pair()
|
||||
|
||||
if not args.yes:
|
||||
for key in ('bind', ):
|
||||
val = conf['server'][key]
|
||||
conf['server'][key] = input('API Server {}? (default `{}`): '.format(key, val)) or val
|
||||
conf['server'][key] = \
|
||||
input('API Server {}? (default `{}`): '.format(key, val)) \
|
||||
or val
|
||||
|
||||
for key in ('host', 'port', 'name'):
|
||||
val = conf['database'][key]
|
||||
conf['database'][key] = input('Database {}? (default `{}`): '.format(key, val)) or val
|
||||
conf['database'][key] = \
|
||||
input('Database {}? (default `{}`): '.format(key, val)) \
|
||||
or val
|
||||
|
||||
for key in ('host', 'port', 'rate'):
|
||||
val = conf['statsd'][key]
|
||||
conf['statsd'][key] = input('Statsd {}? (default `{}`): '.format(key, val)) or val
|
||||
conf['statsd'][key] = \
|
||||
input('Statsd {}? (default `{}`): '.format(key, val)) \
|
||||
or val
|
||||
|
||||
bigchaindb.config_utils.write_config(conf, config_path)
|
||||
print('Configuration written to {}'.format(config_path))
|
||||
print('Ready to go!')
|
||||
|
||||
|
||||
def run_export_my_pubkey(args):
|
||||
"""Export this node's public key to standard output
|
||||
"""
|
||||
logger.debug('bigchaindb args = {}'.format(args))
|
||||
bigchaindb.config_utils.autoconfigure(filename=args.config, force=True)
|
||||
pubkey = bigchaindb.config['keypair']['public']
|
||||
if pubkey is not None:
|
||||
print(pubkey)
|
||||
else:
|
||||
sys.exit("This node's public key wasn't set anywhere "
|
||||
"so it can't be exported")
|
||||
# raises SystemExit exception
|
||||
# message is sent to stderr
|
||||
# exits with exit code 1 (signals tha an error happened)
|
||||
|
||||
|
||||
def run_init(args):
|
||||
"""Initialize the database"""
|
||||
bigchaindb.config_utils.autoconfigure(filename=args.config, force=True)
|
||||
@ -103,16 +129,18 @@ def run_start(args):
|
||||
except DatabaseAlreadyExists:
|
||||
pass
|
||||
except KeypairNotFoundException:
|
||||
sys.exit('Cannot start BigchainDB, no keypair found. Did you run `bigchaindb configure`?')
|
||||
sys.exit("Can't start BigchainDB, no keypair found. "
|
||||
'Did you run `bigchaindb configure`?')
|
||||
|
||||
processes = Processes()
|
||||
logger.info('Start bigchaindb main process')
|
||||
logger.info('Starting BigchainDB main process')
|
||||
processes.start()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Control your bigchain node.',
|
||||
parents=[base_parser])
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Control your BigchainDB node.',
|
||||
parents=[base_parser])
|
||||
|
||||
# all the commands are contained in the subparsers object,
|
||||
# the command selected by the user will be stored in `args.command`
|
||||
@ -121,22 +149,28 @@ def main():
|
||||
subparsers = parser.add_subparsers(title='Commands',
|
||||
dest='command')
|
||||
|
||||
# parser for writing a config file
|
||||
subparsers.add_parser('configure',
|
||||
help='Prepare the config file and create the node keypair')
|
||||
help='Prepare the config file '
|
||||
'and create the node keypair')
|
||||
|
||||
# parser for database level commands
|
||||
# parsers for showing/exporting config values
|
||||
subparsers.add_parser('show-config',
|
||||
help='Show the current configuration')
|
||||
|
||||
subparsers.add_parser('export-my-pubkey',
|
||||
help="Export this node's public key")
|
||||
|
||||
# parser for database-level commands
|
||||
subparsers.add_parser('init',
|
||||
help='Init the database')
|
||||
|
||||
subparsers.add_parser('drop',
|
||||
help='Drop the database')
|
||||
|
||||
# TODO how about just config, or info?
|
||||
subparsers.add_parser('show-config',
|
||||
help='Show the current configuration')
|
||||
|
||||
# parser for starting BigchainDB
|
||||
subparsers.add_parser('start',
|
||||
help='Start bigchain')
|
||||
help='Start BigchainDB')
|
||||
|
||||
start(parser, globals())
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
'''Command line interface for the `bigchain-benchmark` command.'''
|
||||
"""Command line interface for the `bigchaindb-benchmark` command."""
|
||||
|
||||
import logging
|
||||
import argparse
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Utility functions and basic common arguments for ``argparse.ArgumentParser``."""
|
||||
"""Utility functions and basic common arguments
|
||||
for ``argparse.ArgumentParser``.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import multiprocessing as mp
|
||||
@ -7,7 +9,8 @@ import multiprocessing as mp
|
||||
def start(parser, scope):
|
||||
"""Utility function to execute a subcommand.
|
||||
|
||||
The function will look up in the ``scope`` if there is a function called ``run_<parser.args.command>``
|
||||
The function will look up in the ``scope``
|
||||
if there is a function called ``run_<parser.args.command>``
|
||||
and will run it using ``parser.args`` as first positional argument.
|
||||
|
||||
Args:
|
||||
@ -15,7 +18,8 @@ def start(parser, scope):
|
||||
scope (dict): map containing (eventually) the functions to be called.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: if ``scope`` doesn't contain a function called ``run_<parser.args.command>``.
|
||||
NotImplementedError: if ``scope`` doesn't contain a function called
|
||||
``run_<parser.args.command>``.
|
||||
"""
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -29,7 +33,8 @@ def start(parser, scope):
|
||||
|
||||
# if no command has been found, raise a `NotImplementedError`
|
||||
if not func:
|
||||
raise NotImplementedError('Command `{}` not yet implemented'.format(args.command))
|
||||
raise NotImplementedError('Command `{}` not yet implemented'.
|
||||
format(args.command))
|
||||
|
||||
args.multiprocess = getattr(args, 'multiprocess', False)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""Utils to configure Bigchain.
|
||||
"""Utils to configure BigchainDB.
|
||||
|
||||
By calling `file_config`, the global configuration (stored in
|
||||
`bigchain.config`) will be updated with the values contained in the
|
||||
configuration file.
|
||||
`$HOME/.bigchaindb`) will be updated with the values contained
|
||||
in the configuration file.
|
||||
|
||||
Note that there is a precedence in reading configuration values:
|
||||
- local config file;
|
||||
@ -54,7 +54,20 @@ def map_leafs(func, mapping):
|
||||
# Thanks Alex <3
|
||||
# http://stackoverflow.com/a/3233356/597097
|
||||
def update(d, u):
|
||||
"""Recursively update a mapping."""
|
||||
"""Recursively update a mapping (i.e. a dict, list, set, or tuple).
|
||||
|
||||
Conceptually, d and u are two sets trees (with nodes and edges).
|
||||
This function goes through all the nodes of u. For each node in u,
|
||||
if d doesn't have that node yet, then this function adds the node from u,
|
||||
otherwise this function overwrites the node already in d with u's node.
|
||||
|
||||
Args:
|
||||
d (mapping): The mapping to overwrite and add to.
|
||||
u (mapping): The mapping to read for changes.
|
||||
|
||||
Returns:
|
||||
mapping: An updated version of d (updated by u).
|
||||
"""
|
||||
for k, v in u.items():
|
||||
if isinstance(v, collections.Mapping):
|
||||
r = update(d.get(k, {}), v)
|
||||
@ -65,19 +78,21 @@ def update(d, u):
|
||||
|
||||
|
||||
def file_config(filename=None):
|
||||
"""Returns the values found in a configuration file.
|
||||
"""Returns the config values found in a configuration file.
|
||||
|
||||
Args:
|
||||
filename (str): the JSON file with the configuration. Defaults to ``None``.
|
||||
If ``None``, the HOME of the current user and the string ``.bigchaindb`` will be used.
|
||||
filename (str): the JSON file with the configuration values.
|
||||
If ``None``, CONFIG_DEFAULT_PATH will be used.
|
||||
|
||||
Note:
|
||||
The function merges the values in ``filename`` with the **default configuration**,
|
||||
so any update made to ``bigchaindb.config`` will be lost.
|
||||
Returns:
|
||||
dict: The config values in the specified config file (or the
|
||||
file at CONFIG_DEFAULT_PATH, if filename == None)
|
||||
"""
|
||||
logger.debug('On entry into file_config(), filename = {}'.format(filename))
|
||||
if not filename:
|
||||
filename = CONFIG_DEFAULT_PATH
|
||||
|
||||
logger.debug('file_config() will try to open `{}`'.format(filename))
|
||||
with open(filename) as f:
|
||||
config = json.load(f)
|
||||
|
||||
@ -145,17 +160,21 @@ def update_types(config, reference, list_sep=':'):
|
||||
return map_leafs(_update_type, config)
|
||||
|
||||
|
||||
def dict_config(config):
|
||||
"""Merge the provided configuration with the default one.
|
||||
def set_config(config):
|
||||
"""Set bigchaindb.config equal to the default config dict,
|
||||
then update that with whatever is in the provided config dict,
|
||||
and then set bigchaindb.config['CONFIGURED'] = True
|
||||
|
||||
Args:
|
||||
newconfig (dict): a dictionary with the configuration to load.
|
||||
config (dict): the config dict to read for changes
|
||||
to the default config
|
||||
|
||||
Note:
|
||||
The function merges ``newconfig`` with the **default configuration**, so any
|
||||
update made to ``bigchaindb.config`` will be lost.
|
||||
Any previous changes made to ``bigchaindb.config`` will be lost.
|
||||
"""
|
||||
# Deep copy the default config into bigchaindb.config
|
||||
bigchaindb.config = copy.deepcopy(bigchaindb._config)
|
||||
# Update the default config with whatever is in the passed config
|
||||
update(bigchaindb.config, update_types(config, bigchaindb.config))
|
||||
bigchaindb.config['CONFIGURED'] = True
|
||||
|
||||
@ -193,8 +212,7 @@ def autoconfigure(filename=None, config=None, force=False):
|
||||
if config:
|
||||
newconfig = update(newconfig, config)
|
||||
|
||||
dict_config(newconfig)
|
||||
return newconfig
|
||||
set_config(newconfig) # sets bigchaindb.config
|
||||
|
||||
|
||||
def load_consensus_plugin(name=None):
|
||||
|
@ -1,27 +1,46 @@
|
||||
# The BigchainDB Command Line Interfaces (CLIs)
|
||||
# The BigchainDB Command Line Interface (CLI)
|
||||
|
||||
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
|
||||
```
|
||||
There are some command-line commands for working with BigchainDB: `bigchaindb` and `bigchaindb-benchmark`. This section provides an overview of those commands.
|
||||
|
||||
When you run `bigchaindb configure`, it creates a default configuration file in `$HOME/.bigchaindb`. You can check that configuration using:
|
||||
```text
|
||||
$ bigchaindb show-config
|
||||
```
|
||||
## bigchaindb
|
||||
|
||||
To find out what else you can do with the `bigchain` command, use:
|
||||
```text
|
||||
$ bigchaindb -h
|
||||
```
|
||||
### bigchaindb --help
|
||||
|
||||
There's another command named `bigchaindb-benchmark`. It's used to run benchmarking tests. You can learn more about it using:
|
||||
One can get basic help with the `bigchaindb` command using `bigchaindb --help` or `bigchaindb -h`.
|
||||
|
||||
### bigchaindb configure
|
||||
|
||||
This command generates a public/private keypair for the node, and writes a BigchainDB configuration file to the node's file system. It's documented in the section [Configuring a BigchainDB Node](configuration.html).
|
||||
|
||||
If you want to force-generate a new configuration file regardless of whether one already exists (i.e. skipping the yes/no prompt), then use `bigchaindb -y configure`.
|
||||
|
||||
### bigchaindb show-config
|
||||
|
||||
This command shows the values of the configuration settings, which can come from a variety of sources. See [the section on configuring BigchainDB](configuration.html) for more details and examples.
|
||||
|
||||
### bigchaindb export-my-pubkey
|
||||
|
||||
This command writes the node's public key (i.e. one of its configuration values) to standard output (stdout).
|
||||
|
||||
### bigchaindb init
|
||||
|
||||
This command creates a RethinkDB database, two RethinkDB database tables (backlog and bigchain), various RethinkDB database indexes, and the genesis block.
|
||||
|
||||
Note: The `bigchaindb start` command (see below) always starts by trying a `bigchaindb init` first. If it sees that the RethinkDB database already exists, then it doesn't re-initialize the database. One doesn't have to do `bigchaindb init` before `bigchaindb start`. `bigchaindb init` is useful if you only want to initialize (but not start).
|
||||
|
||||
### bigchaindb drop
|
||||
|
||||
This command drops (erases) the RethinkDB database. You will be prompted to make sure. If you want to force-drop the database (i.e. skipping the yes/no prompt), then use `bigchaindb -y drop`
|
||||
|
||||
### bigchaindb start
|
||||
|
||||
This command starts BigchainDB. It always begins by trying a `bigchaindb init` first. See the note in the documentation for `bigchaindb init`.
|
||||
|
||||
|
||||
## bigchaindb-benchmark
|
||||
|
||||
The `bigchaindb-benchmark` command is used to run benchmarking tests. You can learn more about it using:
|
||||
```text
|
||||
$ 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`.
|
||||
|
||||
|
@ -95,16 +95,17 @@ $ rethinkdb
|
||||
Then open a different terminal and run:
|
||||
```text
|
||||
$ bigchaindb -y configure
|
||||
$ bigchaindb init
|
||||
```
|
||||
|
||||
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.
|
||||
That creates a configuration file in `$HOME/.bigchaindb` (documented in [the section on configuration](configuration.html)). More documentation about the `bigchaindb` command is in the section on [the BigchainDB Command Line Interface (CLI)](bigchaindb-cli.html).
|
||||
|
||||
You can start BigchainDB Server using:
|
||||
```text
|
||||
$ bigchaindb start
|
||||
```
|
||||
|
||||
If it's the first time you've run `bigchaindb start`, then it creates the database (a RethinkDB database), the tables, the indexes, and the genesis block. It then starts BigchainDB. If you're run `bigchaindb start` or `bigchaindb init` before (and you haven't dropped the database), then `bigchaindb start` just starts BigchainDB.
|
||||
|
||||
|
||||
## Run BigchainDB with Docker
|
||||
|
||||
|
@ -45,7 +45,7 @@ def ignore_local_config_file(monkeypatch):
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
def restore_config(request, node_config):
|
||||
from bigchaindb import config_utils
|
||||
config_utils.dict_config(node_config)
|
||||
config_utils.set_config(node_config)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
|
@ -17,7 +17,7 @@ from bigchaindb.db import get_conn
|
||||
@pytest.fixture(autouse=True)
|
||||
def restore_config(request, node_config):
|
||||
from bigchaindb import config_utils
|
||||
config_utils.dict_config(node_config)
|
||||
config_utils.set_config(node_config)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
|
@ -82,7 +82,7 @@ def test_bigchain_run_start_assume_yes_create_default_config(monkeypatch, mock_p
|
||||
value['return'] = newconfig
|
||||
|
||||
monkeypatch.setattr(config_utils, 'write_config', mock_write_config)
|
||||
monkeypatch.setattr(config_utils, 'file_config', lambda x: config_utils.dict_config(expected_config))
|
||||
monkeypatch.setattr(config_utils, 'file_config', lambda x: config_utils.set_config(expected_config))
|
||||
monkeypatch.setattr('os.path.exists', lambda path: False)
|
||||
|
||||
args = Namespace(config=None, yes=True)
|
||||
@ -108,6 +108,42 @@ def test_bigchain_show_config(capsys):
|
||||
assert output_config == config
|
||||
|
||||
|
||||
def test_bigchain_export_my_pubkey_when_pubkey_set(capsys, monkeypatch):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchain import run_export_my_pubkey
|
||||
|
||||
args = Namespace(config='dummy')
|
||||
# so in run_export_my_pubkey(args) below,
|
||||
# filename=args.config='dummy' is passed to autoconfigure().
|
||||
# We just assume autoconfigure() works and sets
|
||||
# config['keypair']['public'] correctly (tested elsewhere).
|
||||
# We force-set config['keypair']['public'] using monkeypatch.
|
||||
monkeypatch.setitem(config['keypair'], 'public', 'Charlie_Bucket')
|
||||
_, _ = capsys.readouterr() # has the effect of clearing capsys
|
||||
run_export_my_pubkey(args)
|
||||
out, err = capsys.readouterr()
|
||||
assert out == config['keypair']['public'] + '\n'
|
||||
assert out == 'Charlie_Bucket\n'
|
||||
|
||||
|
||||
def test_bigchain_export_my_pubkey_when_pubkey_not_set(monkeypatch):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchain import run_export_my_pubkey
|
||||
|
||||
args = Namespace(config='dummy')
|
||||
monkeypatch.setitem(config['keypair'], 'public', None)
|
||||
# assert that run_export_my_pubkey(args) raises SystemExit:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_export_my_pubkey(args)
|
||||
# exc_info is an object of class ExceptionInfo
|
||||
# https://pytest.org/latest/builtin.html#_pytest._code.ExceptionInfo
|
||||
assert exc_info.type == SystemExit
|
||||
# exc_info.value is an object of class SystemExit
|
||||
# https://docs.python.org/3/library/exceptions.html#SystemExit
|
||||
assert exc_info.value.code == \
|
||||
"This node's public key wasn't set anywhere so it can't be exported"
|
||||
|
||||
|
||||
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)
|
||||
@ -159,4 +195,3 @@ def test_run_configure_when_config_does_exist(monkeypatch,
|
||||
args = Namespace(config='foo', yes=None)
|
||||
run_configure(args)
|
||||
assert value == {}
|
||||
|
||||
|
@ -18,7 +18,7 @@ def test_bigchain_instance_is_initialized_when_conf_provided():
|
||||
from bigchaindb import config_utils
|
||||
assert 'CONFIGURED' not in bigchaindb.config
|
||||
|
||||
config_utils.dict_config({'keypair': {'public': 'a', 'private': 'b'}})
|
||||
config_utils.set_config({'keypair': {'public': 'a', 'private': 'b'}})
|
||||
|
||||
assert bigchaindb.config['CONFIGURED'] is True
|
||||
b = bigchaindb.Bigchain()
|
||||
|
@ -5,7 +5,7 @@ from ..db import conftest
|
||||
@pytest.fixture(autouse=True)
|
||||
def restore_config(request, node_config):
|
||||
from bigchaindb import config_utils
|
||||
config_utils.dict_config(node_config)
|
||||
config_utils.set_config(node_config)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
|
Loading…
x
Reference in New Issue
Block a user