diff --git a/cli/main.py b/cli/main.py index fdff9fe1d..d2e0483a4 100755 --- a/cli/main.py +++ b/cli/main.py @@ -6,6 +6,7 @@ import random import shutil import subprocess import sys +from urllib.parse import urlparse import click from constant_sorrow import constants @@ -19,8 +20,9 @@ from nucypher.characters.lawful import Ursula from nucypher.config.characters import UrsulaConfiguration from nucypher.config.constants import DEFAULT_CONFIG_FILE_LOCATION, BASE_DIR from nucypher.config.node import DEFAULT_CONFIG_ROOT, NodeConfiguration +from nucypher.config.utils import validate_configuration_file from nucypher.network.middleware import RestMiddleware -from nucypher.utilities.sandbox.blockchain import TesterBlockchain +from nucypher.utilities.sandbox.blockchain import TesterBlockchain, token_airdrop from nucypher.utilities.sandbox.ursula import UrsulaProcessProtocol __version__ = '0.1.0-alpha.0' @@ -666,7 +668,7 @@ def status(config, provider, contracts, network): @cli.command() -@click.option('--config-file', type=click.Path(), default=DEFAULT_CONFIG_FILE_LOCATION) +@click.option('--config-file', type=click.Path()) @click.option('--federated-only', is_flag=True, default=False) @click.option('--dev', is_flag=True, default=False) @click.option('--rest-host', type=str, default='localhost') @@ -689,45 +691,61 @@ def run_ursula(rest_port, The following procedure is required to "spin-up" an Ursula node. 1. Collect all known known from storages - 2. Start the asyncio event loop - 3. Initialize Ursula object - 5. Enter the learning loop - 6. Run TLS deployment - 7. Start the staking daemon + 2. Initialize Ursula object + 3. Enter the learning loop + 4. Run TLS deployment + 5. Start the staking daemon - Configurable values are first read from the .ini configuration file, + Configurable values are first read from the configuration file, but can be overridden (mostly for testing purposes) with inline cli options. """ - if dev is True: - temp = True + temp = True if dev else False - ursula_config = UrsulaConfiguration(temp=True, - federated_only=federated_only, - rest_host=rest_host, - rest_port=rest_port, - db_name=db_name, - checksum_address=checksum_address, - save_metadata=True, - known_metadata_dir=metadata_dir - ) + if config_file: + ursula_config = UrsulaConfiguration.from_config_file(filepath=config_file) + else: + ursula_config = UrsulaConfiguration(temp=temp, + rest_host=rest_host, + rest_port=rest_port, + db_name=db_name, + is_me=True, + federated_only=federated_only, + checksum_address=checksum_address, + network_middleware=RestMiddleware(), + save_metadata=True, + known_metadata_dir=metadata_dir) - ursula_config.initialize_configuration() - ursula_config.load_known_nodes() + if dev: + ursula_config.initialize_configuration() + ursula_config.load_known_nodes() + + ursula_config.check_config_tree() ursula = ursula_config.produce() if teacher_uri: - host, port = teacher_uri.split(':') - teacher = Ursula.from_rest_url(host=host, port=port, network_middleware=RestMiddleware()) - ursula.remember_node(teacher) - ursula.write_node_metadata() + if 'http' not in teacher_uri: + teacher_uri = 'https://'+teacher_uri + url = urlparse(url=teacher_uri) + host, port = url.hostname, url.port - ursula.start_learning_loop() # 5. Enter learning loop - ursula.get_deployer().run() # 6. Run TLS Deployer + teacher = Ursula(rest_host=host, + rest_port=port, + is_me=False, + federated_only=federated_only, + known_nodes=(ursula, )) + + # Know each other + # ursula.remember_node(teacher) + + # ursula.write_node_metadata() + + ursula.start_learning_loop() # Enter learning loop + ursula.get_deployer().run() # Run TLS Deployer if not federated_only: - ursula.stake() # 7. start staking daemon + ursula.stake() # Start staking daemon if __name__ == "__main__": diff --git a/nucypher/blockchain/eth/chains.py b/nucypher/blockchain/eth/chains.py index ad22aceab..b36ab8029 100644 --- a/nucypher/blockchain/eth/chains.py +++ b/nucypher/blockchain/eth/chains.py @@ -40,7 +40,7 @@ class Blockchain: @classmethod def from_config(cls, config: BlockchainConfiguration) -> 'Blockchain': - pass + pass # TODO: BlockchainConfiguration? @classmethod def from_config_file(cls, filepath: str): diff --git a/nucypher/config/characters.py b/nucypher/config/characters.py index d8159b6b9..af4974531 100644 --- a/nucypher/config/characters.py +++ b/nucypher/config/characters.py @@ -74,11 +74,11 @@ class UrsulaConfiguration(NodeConfiguration): self.registry_filepath = registry_filepath @classmethod - def from_config_file(cls, filepath=None) -> 'UrsulaConfiguration': + def from_config_file(cls, filepath=None, **overrides) -> 'UrsulaConfiguration': from nucypher.config.parsers import parse_ursula_config filepath = filepath if filepath is None else DEFAULT_CONFIG_FILE_LOCATION payload = parse_ursula_config(filepath=filepath) - instance = cls(**payload) + instance = cls(**{**payload, **overrides}) return instance @property diff --git a/nucypher/config/node.py b/nucypher/config/node.py index dabed6739..e5cac7110 100644 --- a/nucypher/config/node.py +++ b/nucypher/config/node.py @@ -45,7 +45,7 @@ class NodeConfiguration: self.config_root = config_root self.config_file_location = config_file_location - # Dynamically generate paths baed on configuration root directory + # Dynamically generate paths based on configuration root directory self.keyring_dir = os.path.join(self.config_root, 'keyring') self.known_nodes_dir = os.path.join(self.config_root, 'known_nodes') self.known_certificates_dir = os.path.join(self.config_root, 'certificates') @@ -73,8 +73,8 @@ class NodeConfiguration: for line in islice(template_file, 12, None): new_file.writelines(line.lstrip(';')) # TODO Copy Default Sections, Perhaps interactively - def _check_config_tree(self, configuration_dir: str = None) -> bool: - path = configuration_dir if configuration_dir else DEFAULT_CONFIG_ROOT + def check_config_tree(self, configuration_dir: str = None) -> bool: + path = configuration_dir if configuration_dir else self.config_root if not os.path.exists(path): raise self.ConfigurationError( 'No Nucypher configuration directory found at {}.'.format(configuration_dir)) @@ -110,17 +110,16 @@ class NodeConfiguration: # Create Config Root # - if not self.temp: - if os.path.isdir(self.config_root): - message = "There are existing configuration files at {}".format(self.config_root) - raise self.ConfigurationError(message) + if os.path.isdir(self.config_root): + message = "There are existing configuration files at {}".format(self.config_root) + raise self.ConfigurationError(message) - try: - os.mkdir(self.config_root, mode=0o755) - except FileExistsError: - raise - except FileNotFoundError: - raise + try: + os.mkdir(self.config_root, mode=0o755) + except FileExistsError: + raise + except FileNotFoundError: + raise # # Create Config Subdirectories @@ -131,7 +130,7 @@ class NodeConfiguration: os.mkdir(self.known_certificates_dir, mode=0o755) # known_certs os.mkdir(self.known_metadata_dir, mode=0o755) # known_metadata - self._check_config_tree(configuration_dir=self.config_root) + self.check_config_tree(configuration_dir=self.config_root) return self.config_root