From f553f805e86d766da6208eb1682f7cf12c7907ac Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 7 Jun 2024 13:00:13 +0200 Subject: [PATCH] CLI: Add RabbitMQ options to `verdi profile setup` (#6453) The `verdi profile setup` command was added to replace the deprecated command `verdi setup`. The new command dynamically generates a subcommand for each installed storage plugin. However, the new command did not allow to configure the connection parameters for the RabbitMQ broker, unlike `verdi setup`. These common options are now added to the subcommands. In addition, a new option is added `--use-rabbitmq/--no-use-rabbitmq`. This flag is on by default, to keep the old behavior of `verdi setup`. When toggled to `--no-use-rabbitmq`, the RabbitMQ configuration options are no longer required and are also not prompted for. The profile is then configured without a broker. --- src/aiida/cmdline/commands/cmd_profile.py | 47 +++++++++++++++---- .../cmdline/params/options/commands/setup.py | 9 ++++ src/aiida/manage/configuration/profile.py | 2 +- src/aiida/storage/sqlite_dos/backend.py | 5 +- tests/cmdline/commands/test_profile.py | 13 +++++ 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/aiida/cmdline/commands/cmd_profile.py b/src/aiida/cmdline/commands/cmd_profile.py index b1922058af..2de2ce173d 100644 --- a/src/aiida/cmdline/commands/cmd_profile.py +++ b/src/aiida/cmdline/commands/cmd_profile.py @@ -52,6 +52,23 @@ def command_create_profile( _, storage_entry_point = get_entry_point_from_class(storage_cls.__module__, storage_cls.__name__) assert storage_entry_point is not None + if kwargs.pop('use_rabbitmq'): + broker_backend = 'core.rabbitmq' + broker_config = { + key: kwargs.get(key) + for key in ( + 'broker_protocol', + 'broker_username', + 'broker_password', + 'broker_host', + 'broker_port', + 'broker_virtual_host', + ) + } + else: + broker_backend = None + broker_config = None + try: profile = create_profile( ctx.obj.config, @@ -62,15 +79,8 @@ def command_create_profile( institution=institution, storage_backend=storage_entry_point.name, storage_config=kwargs, - broker_backend='core.rabbitmq', - broker_config={ - 'broker_protocol': 'amqp', - 'broker_username': 'guest', - 'broker_password': 'guest', - 'broker_host': '127.0.0.1', - 'broker_port': 5672, - 'broker_virtual_host': '', - }, + broker_backend=broker_backend, + broker_config=broker_config, ) except (ValueError, TypeError, exceptions.EntryPointError, exceptions.StorageMigrationError) as exception: echo.echo_critical(str(exception)) @@ -93,6 +103,25 @@ def command_create_profile( setup.SETUP_USER_FIRST_NAME(), setup.SETUP_USER_LAST_NAME(), setup.SETUP_USER_INSTITUTION(), + setup.SETUP_USE_RABBITMQ(), + setup.SETUP_BROKER_PROTOCOL( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), + setup.SETUP_BROKER_USERNAME( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), + setup.SETUP_BROKER_PASSWORD( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), + setup.SETUP_BROKER_HOST( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), + setup.SETUP_BROKER_PORT( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), + setup.SETUP_BROKER_VIRTUAL_HOST( + prompt_fn=lambda ctx: ctx.params['use_rabbitmq'], required_fn=lambda ctx: ctx.params['use_rabbitmq'] + ), ], ) def profile_setup(): diff --git a/src/aiida/cmdline/params/options/commands/setup.py b/src/aiida/cmdline/params/options/commands/setup.py index 3a0d6c3a67..bbd980c976 100644 --- a/src/aiida/cmdline/params/options/commands/setup.py +++ b/src/aiida/cmdline/params/options/commands/setup.py @@ -323,6 +323,15 @@ def get_quicksetup_password(ctx, param, value): cls=options.interactive.InteractiveOption, ) +SETUP_USE_RABBITMQ = options.OverridableOption( + '--use-rabbitmq/--no-use-rabbitmq', + prompt='Use RabbitMQ?', + is_flag=True, + default=True, + cls=options.interactive.InteractiveOption, + help='Whether to configure the RabbitMQ broker. Required to enable the daemon and submitting processes.', +) + SETUP_BROKER_PROTOCOL = QUICKSETUP_BROKER_PROTOCOL.clone( prompt='Broker protocol', required=True, diff --git a/src/aiida/manage/configuration/profile.py b/src/aiida/manage/configuration/profile.py index 6365e7a1b5..acaca2e892 100644 --- a/src/aiida/manage/configuration/profile.py +++ b/src/aiida/manage/configuration/profile.py @@ -128,7 +128,7 @@ def process_control_backend(self) -> str | None: @property def process_control_config(self) -> Dict[str, Any]: """Return the configuration required by the process control backend.""" - return self._attributes[self.KEY_PROCESS][self.KEY_PROCESS_CONFIG] + return self._attributes[self.KEY_PROCESS][self.KEY_PROCESS_CONFIG] or {} def set_process_controller(self, name: str, config: Dict[str, Any]) -> None: """Set the process control backend and its configuration. diff --git a/src/aiida/storage/sqlite_dos/backend.py b/src/aiida/storage/sqlite_dos/backend.py index 21195d2475..3b13764b3d 100644 --- a/src/aiida/storage/sqlite_dos/backend.py +++ b/src/aiida/storage/sqlite_dos/backend.py @@ -93,9 +93,10 @@ def initialise_database(self) -> None: class SqliteDosStorage(PsqlDosBackend): - """A lightweight backend intended for demos and testing. + """A lightweight storage that is easy to install. - This backend implementation uses an Sqlite database and + This backend implementation uses an SQLite database and a disk-objectstore container as the file repository. As + such, this storage plugin does not require any services, making it easy to install and use on most systems. """ migrator = SqliteDosMigrator diff --git a/tests/cmdline/commands/test_profile.py b/tests/cmdline/commands/test_profile.py index a78876ad0c..909562245a 100644 --- a/tests/cmdline/commands/test_profile.py +++ b/tests/cmdline/commands/test_profile.py @@ -256,3 +256,16 @@ def test_setup_email_required(run_cli_command, isolated_config, tmp_path, entry_ else: result = run_cli_command(cmd_profile.profile_setup, options, use_subprocess=False, raises=True) assert 'Invalid value for --email: The option is required for storages that are not read-only.' in result.output + + +def test_setup_no_use_rabbitmq(run_cli_command, isolated_config): + """Test the ``--no-use-rabbitmq`` option.""" + profile_name = 'profile-no-broker' + options = ['core.sqlite_dos', '-n', '--email', 'a@a', '--profile', profile_name, '--no-use-rabbitmq'] + + result = run_cli_command(cmd_profile.profile_setup, options, use_subprocess=False) + assert f'Created new profile `{profile_name}`.' in result.output + assert profile_name in isolated_config.profile_names + profile = isolated_config.get_profile(profile_name) + assert profile.process_control_backend is None + assert profile.process_control_config == {}