CLI

Command line user interface for the node component

Attributes

cli module-attribute

cli = NodeCLI()

imp_cli_utils module-attribute

imp_cli_utils = partial(import_module, 'fedbiomed.node.cli_utils')

Classes

DatasetArgumentParser

DatasetArgumentParser(subparser)

Bases: CLIArgumentParser

Initializes CLI options for dataset actions

Source code in fedbiomed/common/cli.py
def __init__(self, subparser: argparse.ArgumentParser):

    self._subparser = subparser
    # Parser that is going to be add using subparser
    self._parser = None

Functions

add
add(args)

Adds datasets

Source code in fedbiomed/node/cli.py
def add(self, args):
    """Adds datasets"""

    global add_database

    add_database = imp_cli_utils().add_database

    if args.mnist:
        return add_database(interactive=False, path=args.mnist)

    if args.file:
        return self._add_dataset_from_file(path=args.file)

    # All operation is handled by CLI utils add_database
    return add_database()
delete
delete(args)

Deletes datasets

Source code in fedbiomed/node/cli.py
def delete(self, args):
    """Deletes datasets"""

    cli_utils = imp_cli_utils()

    if args.all:
        return cli_utils.delete_all_database()

    if args.mnist:
        return cli_utils.delete_database(interactive=False)

    return cli_utils.delete_database()
initialize
initialize()

Initializes dataset options for the node CLI

Source code in fedbiomed/node/cli.py
def initialize(self):
    """Initializes dataset options for the node CLI"""

    self._parser = self._subparser.add_parser(
        "dataset",
        help="Dataset operations"
    )
    self._parser.set_defaults(func=self.default)

    # Creates subparser of dataset option
    dataset_subparsers = self._parser.add_subparsers()


    # Add option
    add = dataset_subparsers.add_parser(
        "add",
        help="Adds dataset"
    )

    # List option
    list_ = dataset_subparsers.add_parser(
        "list",
        help="List datasets that are deployed in the node.")

    # Delete option
    delete = dataset_subparsers.add_parser(
        "delete",
        help="Deletes dataset that are deployed in the node.")


    add.add_argument(
        "--mnist",
        "-m",
        metavar="MNIST_DATA_PATH",
        help="Deploys MNIST dataset by downloading form default source to given path.",
        required=False
    )

    add.add_argument(
        "--file",
        "-fl",
        required=False,
        metavar="File that describes the dataset",
        help="File path the dataset file desciptro. This option adds dataset by given file which is has"
             "cutom format that describes the dataset.")

    delete.add_argument(
        "--all",
        '-a',
        required=False,
        action="store_true",
        help="Removes entire dataset database.")

    delete.add_argument(
        "--mnist",
        '-m',
        required=False,
        action="store_true",
        help="Removes MNIST dataset.")

    add.set_defaults(func=self.add)
    list_.set_defaults(func=self.list)
    delete.set_defaults(func=self.delete)
list
list(unused_args)

List datasets

Parameters:

Name Type Description Default
unused_args

Empty arguments since list command no positional args.

required
Source code in fedbiomed/node/cli.py
def list(self, unused_args):
    """List datasets

    Args:
      unused_args: Empty arguments since `list` command no positional args.
    """
    dataset_manager = imp_cli_utils().dataset_manager

    print('Listing your data available')
    data = dataset_manager.list_my_data(verbose=True)
    if len(data) == 0:
        print('No data has been set up.')

GUIControl

GUIControl(subparser)

Bases: CLIArgumentParser

Source code in fedbiomed/common/cli.py
def __init__(self, subparser: argparse.ArgumentParser):

    self._subparser = subparser
    # Parser that is going to be add using subparser
    self._parser = None

Functions

forward
forward(args, extra_args)

Forwards gui commands to ./script/fedbiomed_gui Extra arguments

TODO: Implement argument GUI parseing and execution

Source code in fedbiomed/node/cli.py
    def forward(self, args, extra_args):
        """Forwards gui commands to ./script/fedbiomed_gui Extra arguments

        TODO: Implement argument GUI parseing and execution
        """

#        commad = []
#        command.extend(['--data-folder', args.data_folder, '--port', args.port, '--host', args.host])


#        if args.key_file:
#            command.extend(['--key-file', args.key_file])
#
#        if args.cert_file:
#            command.extend(['--cert-file', args.cert_file])
#
#        if args.recreate:
#            command.append('--recreate')
#
#        if args.debug:
#            command.append('--debug')


        gui_script = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'scripts', 'fedbiomed_gui'))
        command = [gui_script, *extra_args]
        process = subprocess.Popen(command)

        try:
            process.wait()
        except KeyboardInterrupt:
            try:
                process.terminate()
            except Exception:
                pass
            process.wait()
initialize
initialize()

Initializes GUI commands

Source code in fedbiomed/node/cli.py
def initialize(self):
    """Initializes GUI commands"""
    self._parser = self._subparser.add_parser("gui", add_help=False, help="Action to manage Node user interface")
    self._parser.set_defaults(func=self.forward)

NodeCLI

NodeCLI()

Bases: CommonCLI

Source code in fedbiomed/node/cli.py
def __init__(self):
    super().__init__()

    self._parser.prog = "fedbiomed_run node"
    self.description = f"{__intro__} \nA CLI app for fedbiomed node component."
    # Parent parser for parameters that are common for Node CLI actions
    self.initialize()

Attributes

description instance-attribute
description = f'{__intro__} 
A CLI app for fedbiomed node component.'

Functions

initialize
initialize()

Initializes node module

Source code in fedbiomed/node/cli.py
def initialize(self):
    """Initializes node module"""


    class ConfigNameActionNode(ConfigNameAction):

        _this = self
        _component = ComponentType.NODE

        def import_environ(self) -> 'fedbiomed.node.environ.Environ':
            """Imports dynamically node environ object"""
            return importlib.import_module("fedbiomed.node.environ").environ

    self._parser.add_argument(
        "--config",
        "-cf",
        nargs="?",
        action=ConfigNameActionNode,
        default="config_node.ini",
        help="Name of the config file that the CLI will be activated for. Default is 'config_node.ini'.")

    super().initialize()

NodeControl

NodeControl(subparser)

Bases: CLIArgumentParser

CLI argument parser for starting the node

Source code in fedbiomed/common/cli.py
def __init__(self, subparser: argparse.ArgumentParser):

    self._subparser = subparser
    # Parser that is going to be add using subparser
    self._parser = None

Functions

initialize
initialize()

Initializes missinon control argument parser

Source code in fedbiomed/node/cli.py
def initialize(self):
    """Initializes missinon control argument parser"""
    start = self._subparser.add_parser("start", help="Starts the node")
    start.set_defaults(func=self.start)

    start.add_argument(
        "--gpu",
        action="store_true",
        help="Activate GPU usage if the flag is present")

    start.add_argument(
        "--gpu-num",
        "-gn",
        type=int,
        nargs="?",
        required=False,
        default=1,
        help="Number of GPU that is going to be used")

    start.add_argument(
        "--gpu-only",
        "-go",
        action="store_true",
        help="Node performs training only using GPU resources."
             "This flag automatically activate GPU.")
start
start(args)

Starts the node

Source code in fedbiomed/node/cli.py
def start(self, args):
    """Starts the node"""

    global start_node

    intro()
    environ = importlib.import_module("fedbiomed.node.environ").environ


    # Define arguments
    node_args = {
        "gpu": (args.gpu is True) or (args.gpu_only is True),
        "gpu_num": args.gpu_num,
        "gpu_only": True if args.gpu_only else False}

    p = Process(target=start_node, name='node-' + environ['NODE_ID'], args=(node_args,))
    p.deamon = True
    p.start()

    logger.info("Node started as process with pid = " + str(p.pid))
    try:
        print('To stop press Ctrl + C.')
        p.join()
    except KeyboardInterrupt:
        p.terminate()
        time.sleep(1)
        while p.is_alive():
            logger.info("Terminating process id =" + str(p.pid))
            time.sleep(1)
        logger.info('Exited with code ' + str(p.exitcode))
        sys.exit(0)

TrainingPlanArgumentParser

TrainingPlanArgumentParser(subparser)

Bases: CLIArgumentParser

Argument parser for training-plan operations

Source code in fedbiomed/common/cli.py
def __init__(self, subparser: argparse.ArgumentParser):

    self._subparser = subparser
    # Parser that is going to be add using subparser
    self._parser = None

Functions

approve
approve(args)

Approves training plan

Source code in fedbiomed/node/cli.py
def approve(self, args):
    """Approves training plan"""
    approve_training_plan = imp_cli_utils().approve_training_plan
    approve_training_plan(id=args.id)
delete
delete(args)

Deletes training plan

Source code in fedbiomed/node/cli.py
def delete(self, args):
    """Deletes training plan"""
    delete_training_plan = imp_cli_utils().delete_training_plan
    delete_training_plan(id=args.id)
initialize
initialize()
Source code in fedbiomed/node/cli.py
def initialize(self):

    self._parser = self._subparser.add_parser(
        "training-plan",
        help="CLI operations for TrainingPlans register/list/delete/approve/reject etc."
    )

    training_plan_suparsers = self._parser.add_subparsers()
    self._parser.set_defaults(func=self.default)


    common_reject_approve = argparse.ArgumentParser(add_help=False)
    common_reject_approve.add_argument(
        '--id',
        type=str,
        nargs='?',
        required=False,
        help='ID of the training plan that will be processed.'
    )


    update = training_plan_suparsers.add_parser(
        "update", help="Updates training plan"
    )
    update.set_defaults(func=self.update)

    register = training_plan_suparsers.add_parser(
        "register", help="Registers training plans manually by selected file thorugh interactive browser."
    )
    register.set_defaults(func=self.register)

    list = training_plan_suparsers.add_parser(
        "list", help="Lists all saved/registered training plans with their status.")
    list.set_defaults(func=self.list)

    delete = training_plan_suparsers.add_parser(
        "delete",
        parents=[common_reject_approve],
        help="Deletes interactively selected training plan from the database.")
    delete.set_defaults(func=self.delete)

    approve = training_plan_suparsers.add_parser(
        "approve",
        parents=[common_reject_approve],
        help="Approves interactively selected training plans.")
    approve.set_defaults(func=self.approve)

    reject = training_plan_suparsers.add_parser(
        "reject",
        parents=[common_reject_approve],
        help="Rejects interactively selected training plans.")

    reject.add_argument(
        "--notes",
        type=str,
        nargs="?",
        required=False,
        default="No notes provided.",
        help="Note to explain why training plan is rejected."
    )
    reject.set_defaults(func=self.reject)

    view = training_plan_suparsers.add_parser(
        "view", help="View interactively selected training plans.")
    view.set_defaults(func=self.view)
list
list()

Lists training plans

Source code in fedbiomed/node/cli.py
def list(self):
    """Lists training plans"""
    tp_security_manager = imp_cli_utils().tp_security_manager
    tp_security_manager.list_training_plans(verbose=True)
register
register()

Registers training plan

Source code in fedbiomed/node/cli.py
def register(self):
    """Registers training plan"""
    register_training_plan = imp_cli_utils().register_training_plan
    register_training_plan()
reject
reject(args)

Approves training plan

Source code in fedbiomed/node/cli.py
def reject(self, args):
    """Approves training plan"""
    reject_training_plan = imp_cli_utils().reject_training_plan
    reject_training_plan(id=args.id, notes=args.notes)
update
update()

Updates training plan

Source code in fedbiomed/node/cli.py
def update(self):
    """Updates training plan"""
    update_training_plan = imp_cli_utils().update_training_plan
    update_training_plan()
view
view()

Views training plan

Source code in fedbiomed/node/cli.py
def view(self):
    """Views training plan"""
    view_training_plan = imp_cli_utils().view_training_plan
    view_training_plan()

Functions

intro

intro()

Prints intro for the CLI

Source code in fedbiomed/node/cli.py
def intro():
    """Prints intro for the CLI"""

    print(__intro__)
    print('\t- 🆔 Your node ID:', os.environ['FEDBIOMED_ACTIVE_NODE_ID'], '\n')

start_node

start_node(node_args)

Starts the node

Source code in fedbiomed/node/cli.py
def start_node(node_args):
    """Starts the node"""

    cli_utils = imp_cli_utils()

    tp_security_manager = cli_utils.tp_security_manager
    dataset_manager = cli_utils.dataset_manager
    Node = importlib.import_module("fedbiomed.node.node").Node
    environ = importlib.import_module("fedbiomed.node.environ").environ

    try:
        signal.signal(signal.SIGTERM, _node_signal_handler)

        logger.info('Launching node...')

        # Register default training plans and update hashes
        if environ["TRAINING_PLAN_APPROVAL"]:
            # This methods updates hashes if hashing algorithm has changed
            tp_security_manager.check_hashes_for_registered_training_plans()
            if environ["ALLOW_DEFAULT_TRAINING_PLANS"]:
                logger.info('Loading default training plans')
                tp_security_manager.register_update_default_training_plans()
        else:
            logger.warning('Training plan approval for train request is not activated. ' +
                           'This might cause security problems. Please, consider to enable training plan approval.')

        logger.info('Starting communication channel with network')
        _node = Node(dataset_manager=dataset_manager,
                     tp_security_manager=tp_security_manager,
                     node_args=node_args)
        _node.start_messaging(_node_signal_trigger_term)
        logger.info('Starting node to node router')
        _node.start_protocol()
        logger.info('Starting task manager')
        _node.task_manager()  # handling training tasks in queue

    except FedbiomedError:
        logger.critical("Node stopped.")
        # we may add extra information for the user depending on the error

    except Exception as exp:
        # must send info to the researcher (no mqqt should be handled
        # by the previous FedbiomedError)
        _node.send_error(ErrorNumbers.FB300, extra_msg="Error = " + str(exp))
        logger.critical("Node stopped.")