Esempio n. 1
0
    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
Esempio n. 2
0
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')
Esempio n. 3
0
    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__)
Esempio n. 4
0
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)
Esempio n. 5
0
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
Esempio n. 6
0
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)
Esempio n. 7
0
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))
Esempio n. 8
0
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))