def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Sentry Logging if self.log_to_sentry is True: initialize_sentry(dsn=NUCYPHER_SENTRY_ENDPOINT) globalLogPublisher.addObserver(logToSentry) # File Logging if self.log_to_file is True: globalLogPublisher.addObserver(getTextFileObserver()) globalLogPublisher.addObserver(getJsonFileObserver()) # You guessed it self.debug = False # Logging self.quiet = False self.log = Logger(self.__class__.__name__) # Auth self.__keyring_password = NO_PASSWORD # Blockchain self.accounts = NO_BLOCKCHAIN_CONNECTION self.blockchain = NO_BLOCKCHAIN_CONNECTION
def nucypher_cli(click_config, verbose, mock_networking, json_ipc, no_logs, quiet, debug, no_registry, log_level): # Session Emitter for pre and post character control engagement. if json_ipc: emitter = JSONRPCStdoutEmitter( quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout) else: emitter = StdoutEmitter( quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout) click_config.attach_emitter(emitter) if not json_ipc: click_config.emit(message=NUCYPHER_BANNER) if log_level: GlobalConsoleLogger.set_log_level(log_level_name=log_level) globalLogPublisher.addObserver(SimpleObserver()) if debug and quiet: raise click.BadOptionUsage( option_name="quiet", message="--debug and --quiet cannot be used at the same time.") if debug: click_config.log_to_sentry = False click_config.log_to_file = True # File Logging globalLogPublisher.addObserver(SimpleObserver()) # Console Logging globalLogPublisher.removeObserver(logToSentry) # No Sentry GlobalConsoleLogger.set_log_level(log_level_name='debug') elif quiet: # Disable Logging globalLogPublisher.removeObserver(logToSentry) globalLogPublisher.removeObserver(SimpleObserver) globalLogPublisher.removeObserver(getJsonFileObserver()) # Logging if not no_logs: GlobalConsoleLogger.start_if_not_started() # CLI Session Configuration click_config.verbose = verbose click_config.mock_networking = mock_networking click_config.json_ipc = json_ipc click_config.no_logs = no_logs click_config.quiet = quiet click_config.no_registry = no_registry click_config.debug = debug # Only used for testing outputs; # Redirects outputs to in-memory python containers. if mock_networking: click_config.emit(message="WARNING: Mock networking is enabled") click_config.middleware = MockRestMiddleware() else: click_config.middleware = RestMiddleware() # Global Warnings if click_config.verbose: click_config.emit(message="Verbose mode is enabled", color='blue')
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Sentry Logging if self.log_to_sentry is True: initialize_sentry(dsn=NUCYPHER_SENTRY_ENDPOINT) globalLogPublisher.addObserver(logToSentry) # File Logging if self.log_to_file is True: globalLogPublisher.addObserver(getTextFileObserver()) globalLogPublisher.addObserver(getJsonFileObserver()) # You guessed it self.debug = False # Logging self.quiet = False self.log = Logger(self.__class__.__name__)
class NucypherClickConfig: # Output Sinks emitters = list() capture_stdout = False __sentry_endpoint = NUCYPHER_SENTRY_ENDPOINT # Environment Variables config_file = os.environ.get('NUCYPHER_CONFIG_FILE', None) sentry_endpoint = os.environ.get("NUCYPHER_SENTRY_DSN", __sentry_endpoint) log_to_sentry = os.environ.get("NUCYPHER_SENTRY_LOGS", True) log_to_file = os.environ.get("NUCYPHER_FILE_LOGS", True) # Sentry Logging if log_to_sentry is True: initialize_sentry(dsn=__sentry_endpoint) globalLogPublisher.addObserver(logToSentry) # File Logging if log_to_file is True: globalLogPublisher.addObserver(getTextFileObserver()) globalLogPublisher.addObserver(getJsonFileObserver()) def __init__(self): self.log = Logger(self.__class__.__name__) self.__keyring_password = NO_PASSWORD def get_password(self, confirm: bool =False) -> str: keyring_password = os.environ.get("NUCYPHER_KEYRING_PASSWORD", NO_PASSWORD) if keyring_password is NO_PASSWORD: # Collect password, prefer env var prompt = "Enter keyring password" keyring_password = click.prompt(prompt, confirmation_prompt=confirm, hide_input=True) self.__keyring_password = keyring_password return self.__keyring_password @classmethod def emit(cls, *args, **kwargs): for emitter in cls.emitters: emitter(*args, **kwargs)
class NucypherClickConfig: __sentry_endpoint = "https://[email protected]/1310685" # TODO: Use nucypher domain # Environment Variables config_file = os.environ.get('NUCYPHER_CONFIG_FILE', None) sentry_endpoint = os.environ.get("NUCYPHER_SENTRY_DSN", __sentry_endpoint) log_to_sentry = os.environ.get("NUCYPHER_SENTRY_LOGS", True) log_to_file = os.environ.get("NUCYPHER_FILE_LOGS", True) # Sentry Logging if log_to_sentry is True: initialize_sentry(dsn=__sentry_endpoint) globalLogPublisher.addObserver(logToSentry) # File Logging if log_to_file is True: globalLogPublisher.addObserver(getTextFileObserver()) globalLogPublisher.addObserver(getJsonFileObserver()) def __init__(self): self.log = Logger(self.__class__.__name__) self.__keyring_password = NO_PASSWORD def get_password(self, confirm: bool = False) -> str: keyring_password = os.environ.get("NUCYPHER_KEYRING_PASSWORD", NO_PASSWORD) if keyring_password is NO_PASSWORD: # Collect password, prefer env var prompt = "Enter keyring password" keyring_password = click.prompt(prompt, confirmation_prompt=confirm, hide_input=True) self.__keyring_password = keyring_password return self.__keyring_password
class NucypherClickConfig: # Output Sinks emitters = list() capture_stdout = False __sentry_endpoint = NUCYPHER_SENTRY_ENDPOINT # Environment Variables config_file = os.environ.get('NUCYPHER_CONFIG_FILE', None) sentry_endpoint = os.environ.get("NUCYPHER_SENTRY_DSN", __sentry_endpoint) log_to_sentry = os.environ.get("NUCYPHER_SENTRY_LOGS", True) log_to_file = os.environ.get("NUCYPHER_FILE_LOGS", True) # Sentry Logging if log_to_sentry is True: initialize_sentry(dsn=__sentry_endpoint) globalLogPublisher.addObserver(logToSentry) # File Logging if log_to_file is True: globalLogPublisher.addObserver(getTextFileObserver()) globalLogPublisher.addObserver(getJsonFileObserver()) def __init__(self): # Logging self.quiet = False self.log = Logger(self.__class__.__name__) # Auth self.__keyring_password = NO_PASSWORD # Blockchain self.accounts = NO_BLOCKCHAIN_CONNECTION self.blockchain = NO_BLOCKCHAIN_CONNECTION def connect_to_blockchain(self, character_configuration, recompile_contracts: bool = False): try: character_configuration.connect_to_blockchain( recompile_contracts=recompile_contracts) character_configuration.connect_to_contracts() except EthereumContractRegistry.NoRegistry: message = "Cannot configure blockchain character: No contract registry found; " \ "Did you mean to pass --federated-only?" raise EthereumContractRegistry.NoRegistry(message) else: self.blockchain = character_configuration.blockchain self.accounts = self.blockchain.interface.w3.eth.accounts def _get_password(self, confirm: bool = False) -> str: keyring_password = os.environ.get("NUCYPHER_KEYRING_PASSWORD", NO_PASSWORD) if keyring_password is NO_PASSWORD: # Collect password, prefer env var prompt = "Enter keyring password" keyring_password = click.prompt(prompt, confirmation_prompt=confirm, hide_input=True) self.__keyring_password = keyring_password return self.__keyring_password def unlock_keyring(self, character_configuration: NodeConfiguration): try: # Unlock Keyring if not self.quiet: self.emit('Decrypting keyring...', fg='blue') character_configuration.keyring.unlock( password=self._get_password()) # Takes ~3 seconds, ~1GB Ram except CryptoError: raise character_configuration.keyring.AuthenticationFailed @classmethod def emit(cls, *args, **kwargs): for emitter in cls.emitters: emitter(*args, **kwargs)
def ursula( click_config, action, debug, dev, quiet, dry_run, force, lonely, network, teacher_uri, min_stake, rest_host, rest_port, db_filepath, checksum_address, federated_only, poa, config_root, config_file, metadata_dir, # TODO: Start nodes from an additional existing metadata dir provider_uri, no_registry, registry_filepath) -> None: """ Manage and run an "Ursula" PRE node. \b Actions ------------------------------------------------- \b run Run an "Ursula" node. init Create a new Ursula node configuration. view View the Ursula node's configuration. forget Forget all known nodes. save-metadata Manually write node metadata to disk without running destroy Delete Ursula node configuration. """ # # Boring Setup Stuff # if not quiet: click.secho(URSULA_BANNER) log = Logger('ursula.cli') if debug and quiet: raise click.BadOptionUsage( option_name="quiet", message="--debug and --quiet cannot be used at the same time.") if debug: click_config.log_to_sentry = False click_config.log_to_file = True globalLogPublisher.removeObserver(logToSentry) # Sentry GlobalConsoleLogger.set_log_level("debug") elif quiet: globalLogPublisher.removeObserver(logToSentry) globalLogPublisher.removeObserver(SimpleObserver) globalLogPublisher.removeObserver(getJsonFileObserver()) # # Pre-Launch Warnings # if not quiet: if dev: click.secho("WARNING: Running in development mode", fg='yellow') if force: click.secho("WARNING: Force is enabled", fg='yellow') # # Unauthenticated Configurations # if action == "init": """Create a brand-new persistent Ursula""" if dev and not quiet: click.secho("WARNING: Using temporary storage area", fg='yellow') if not config_root: # Flag config_root = click_config.config_file # Envvar if not rest_host: rest_host = click.prompt( "Enter Ursula's public-facing IPv4 address") ursula_config = UrsulaConfiguration.generate( password=click_config.get_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, domains={network} if network else None, federated_only=federated_only, checksum_public_address=checksum_address, no_registry=federated_only or no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, poa=poa) if not quiet: click.secho("Generated keyring {}".format( ursula_config.keyring_dir), fg='green') click.secho("Saved configuration file {}".format( ursula_config.config_file_location), fg='green') # Give the use a suggestion as to what to do next... how_to_run_message = "\nTo run an Ursula node from the default configuration filepath run: \n\n'{}'\n" suggested_command = 'nucypher ursula run' if config_root is not None: config_file_location = os.path.join( config_root, config_file or UrsulaConfiguration.CONFIG_FILENAME) suggested_command += ' --config-file {}'.format( config_file_location) click.secho(how_to_run_message.format(suggested_command), fg='green') return # FIN else: click.secho("OK") elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroy_system_configuration(config_class=UrsulaConfiguration, config_file=config_file, network=network, config_root=config_root, force=force, log=log) if not quiet: click.secho("Destroyed {}".format(config_root)) return # Development Configuration if dev: ursula_config = UrsulaConfiguration( dev_mode=True, domains={TEMPORARY_DOMAIN}, poa=poa, registry_filepath=registry_filepath, provider_uri=provider_uri, checksum_public_address=checksum_address, federated_only=federated_only, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath) # Authenticated Configurations else: # Deserialize network domain name if override passed if network: domain_constant = getattr(constants, network.upper()) domains = {domain_constant} else: domains = None ursula_config = UrsulaConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_uri=provider_uri, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, # TODO: Handle Boolean overrides # poa=poa, # federated_only=federated_only, ) try: # Unlock Keyring if not quiet: click.secho('Decrypting keyring...', fg='blue') ursula_config.keyring.unlock(password=click_config.get_password() ) # Takes ~3 seconds, ~1GB Ram except CryptoError: raise ursula_config.keyring.AuthenticationFailed if not ursula_config.federated_only: try: ursula_config.connect_to_blockchain(recompile_contracts=False) ursula_config.connect_to_contracts() except EthereumContractRegistry.NoRegistry: message = "Cannot configure blockchain character: No contract registry found; " \ "Did you mean to pass --federated-only?" raise EthereumContractRegistry.NoRegistry(message) click_config.ursula_config = ursula_config # Pass Ursula's config onto staking sub-command # # Launch Warnings # if not quiet: if ursula_config.federated_only: click.secho("WARNING: Running in Federated mode", fg='yellow') # # Action Switch # if action == 'run': """Seed, Produce, Run!""" # # Seed - Step 1 # teacher_nodes = list() if teacher_uri: node = Ursula.from_teacher_uri( teacher_uri=teacher_uri, min_stake=min_stake, federated_only=ursula_config.federated_only) teacher_nodes.append(node) # # Produce - Step 2 # ursula = ursula_config(known_nodes=teacher_nodes, lonely=lonely) # GO! try: # # Run - Step 3 # click.secho("Connecting to {}".format(','.join( str(d) for d in ursula_config.domains)), fg='blue', bold=True) click.secho("Running Ursula {} on {}".format( ursula, ursula.rest_interface), fg='green', bold=True) if not debug: stdio.StandardIO(UrsulaCommandProtocol(ursula=ursula)) if dry_run: # That's all folks! return ursula.get_deployer().run() # <--- Blocking Call (Reactor) except Exception as e: ursula_config.log.critical(str(e)) click.secho("{} {}".format(e.__class__.__name__, str(e)), fg='red') raise # Crash :-( finally: if not quiet: click.secho("Stopping Ursula") ursula_config.cleanup() if not quiet: click.secho("Ursula Stopped", fg='red') return elif action == "save-metadata": """Manually save a node self-metadata file""" ursula = ursula_config.produce(ursula_config=ursula_config) metadata_path = ursula.write_node_metadata(node=ursula) if not quiet: click.secho("Successfully saved node metadata to {}.".format( metadata_path), fg='green') return elif action == "view": """Paint an existing configuration to the console""" paint_configuration( config_filepath=config_file or ursula_config.config_file_location) return elif action == "forget": """Forget all known nodes via storages""" click.confirm("Permanently delete all known node data?", abort=True) ursula_config.forget_nodes() message = "Removed all stored node node metadata and certificates" click.secho(message=message, fg='red') return else: raise click.BadArgumentUsage("No such argument {}".format(action))
def ursula( click_config, action, dev, quiet, dry_run, force, lonely, network, teacher_uri, min_stake, rest_host, rest_port, db_filepath, checksum_address, federated_only, poa, config_root, config_file, metadata_dir, # TODO: Start nodes from an additional existing metadata dir provider_uri, recompile_solidity, no_registry, registry_filepath) -> None: """ Manage and run an "Ursula" PRE node. \b Actions ------------------------------------------------- \b run Run an "Ursula" node. init Create a new Ursula node configuration. view View the Ursula node's configuration. forget Forget all known nodes. save-metadata Manually write node metadata to disk without running destroy Delete Ursula node configuration. """ # # Boring Setup Stuff # if not quiet: log = Logger('ursula.cli') if click_config.debug and quiet: raise click.BadOptionUsage( option_name="quiet", message="--debug and --quiet cannot be used at the same time.") if click_config.debug: click_config.log_to_sentry = False click_config.log_to_file = True globalLogPublisher.removeObserver(logToSentry) # Sentry GlobalConsoleLogger.set_log_level("debug") elif quiet: globalLogPublisher.removeObserver(logToSentry) globalLogPublisher.removeObserver(SimpleObserver) globalLogPublisher.removeObserver(getJsonFileObserver()) if not click_config.json_ipc and not click_config.quiet: click.secho(URSULA_BANNER) # # Pre-Launch Warnings # if not quiet: if dev: click.secho("WARNING: Running in development mode", fg='yellow') if force: click.secho("WARNING: Force is enabled", fg='yellow') # # Unauthenticated Configurations # if action == "init": """Create a brand-new persistent Ursula""" if not network: raise click.BadArgumentUsage( '--network is required to initialize a new configuration.') if dev: actions.handle_control_output( message="WARNING: Using temporary storage area", color='yellow', quiet=quiet, json=click_config.json) if not config_root: # Flag config_root = click_config.config_file # Envvar if not rest_host: rest_host = click.prompt( "Enter Ursula's public-facing IPv4 address" ) # TODO: Remove this step ursula_config = UrsulaConfiguration.generate( password=click_config.get_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, domains={network} if network else None, federated_only=federated_only, checksum_public_address=checksum_address, no_registry=federated_only or no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, poa=poa) click_config.emitter(message="Generated keyring {}".format( ursula_config.keyring_dir), color='green') click_config.emitter(message="Saved configuration file {}".format( ursula_config.config_file_location), color='green') # Give the use a suggestion as to what to do next... how_to_run_message = "\nTo run an Ursula node from the default configuration filepath run: \n\n'{}'\n" suggested_command = 'nucypher ursula run' if config_root is not None: config_file_location = os.path.join( config_root, config_file or UrsulaConfiguration.CONFIG_FILENAME) suggested_command += ' --config-file {}'.format( config_file_location) return click_config.emitter( message=how_to_run_message.format(suggested_command), color='green') # Development Configuration if dev: ursula_config = UrsulaConfiguration( dev_mode=True, domains={TEMPORARY_DOMAIN}, poa=poa, registry_filepath=registry_filepath, provider_uri=provider_uri, checksum_public_address=checksum_address, federated_only=federated_only, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath) # Authenticated Configurations else: # Deserialize network domain name if override passed if network: domain_constant = getattr(constants, network.upper()) domains = {domain_constant} else: domains = None ursula_config = UrsulaConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_uri=provider_uri, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, # TODO: Handle Boolean overrides # poa=poa, # federated_only=federated_only, ) actions.unlock_keyring(configuration=ursula_config, password=click_config.get_password()) if not ursula_config.federated_only: actions.connect_to_blockchain(configuration=ursula_config, recompile_contracts=recompile_solidity) click_config.ursula_config = ursula_config # Pass Ursula's config onto staking sub-command # # Launch Warnings # if ursula_config.federated_only: click_config.emitter(message="WARNING: Running in Federated mode", color='yellow') # # Action Switch # if action == 'run': """Seed, Produce, Run!""" # # Seed - Step 1 # teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) # # Produce - Step 2 # URSULA = ursula_config(known_nodes=teacher_nodes, lonely=lonely) # GO! try: # # Run - Step 3 # click_config.emitter(message="Connecting to {}".format(','.join( str(d) for d in ursula_config.domains)), color='green', bold=True) click_config.emitter(message="Running Ursula {} on {}".format( URSULA, URSULA.rest_interface), color='green', bold=True) if not click_config.debug: stdio.StandardIO(UrsulaCommandProtocol(ursula=URSULA)) if dry_run: # That's all folks! return URSULA.get_deployer().run() # <--- Blocking Call (Reactor) except Exception as e: ursula_config.log.critical(str(e)) click_config.emitter(message="{} {}".format( e.__class__.__name__, str(e)), color='red', bold=True) raise # Crash :-( finally: click_config.emitter(message="Stopping Ursula", color='green') ursula_config.cleanup() click_config.emitter(message="Ursula Stopped", color='red') return elif action == "save-metadata": """Manually save a node self-metadata file""" URSULA = ursula_config.produce(ursula_config=ursula_config) metadata_path = ursula.write_node_metadata(node=URSULA) return click_config.emitter( message="Successfully saved node metadata to {}.".format( metadata_path), color='green') elif action == "view": """Paint an existing configuration to the console""" response = UrsulaConfiguration._read_configuration_file( filepath=config_file or ursula_config.config_file_location) return click_config.emitter(response=response) elif action == "forget": # TODO: Move to character control actions.forget(configuration=ursula_config) return elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_filepath = destroy_system_configuration( config_class=UrsulaConfiguration, config_file=config_file, network=network, config_root=ursula_config.config_file_location, force=force) return click_config.emitter(message=f"Destroyed {destroyed_filepath}", color='green') else: raise click.BadArgumentUsage("No such argument {}".format(action))