Skip to content

Commit

Permalink
Config: add the hidden warnings.rabbitmq_version option
Browse files Browse the repository at this point in the history
This option can be used to suppress the warning that is emitted when a
profile storage is loaded that is configured with a version of RabbitMQ
that is known to be able to cause problems. The option is hidden because
the warning is very important and should not easily be ignorable by
normal users, but it is mostly intended for developers.

The `check_rabbitmq_version` and `check_version` free functions are
moved to `Manager` as methods which allows to use `get_option` instead
of the `get_config_option` free function which is just an indirect way
of calling `Manager.get_option`.

The `is_rabbitmq_version_supported` function is also corrected. It was
still using `< parse('3.8')` as a condition whereas it should be
`< parse('3.8.15')` which was recently already changed for the
`check_rabbitmq_version` function.
  • Loading branch information
sphuber committed Mar 9, 2022
1 parent c50a61a commit f4fda1f
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 52 deletions.
4 changes: 2 additions & 2 deletions aiida/cmdline/commands/cmd_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def verdi_status(print_traceback, no_rmq):
from aiida.cmdline.utils.daemon import delete_stale_pid_file, get_daemon_status
from aiida.common.utils import Capturing
from aiida.manage.configuration.settings import AIIDA_CONFIG_FOLDER
from aiida.manage.manager import check_rabbitmq_version, get_manager
from aiida.manage.manager import get_manager

exit_code = ExitCode.SUCCESS

Expand Down Expand Up @@ -125,7 +125,7 @@ def verdi_status(print_traceback, no_rmq):
print_status(ServiceStatus.ERROR, 'rabbitmq', message, exception=exc, print_traceback=print_traceback)
exit_code = ExitCode.CRITICAL
else:
version, supported = check_rabbitmq_version(comm)
version, supported = manager.check_rabbitmq_version(comm)
connection = f'Connected to RabbitMQ v{version} as {profile.get_rmq_url()}'
if supported:
print_status(ServiceStatus.UP, 'rabbitmq', connection)
Expand Down
5 changes: 5 additions & 0 deletions aiida/manage/configuration/schema/config-v8.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
"description": "Whether to print a warning when a profile is loaded while a development version is installed",
"global_only": true
},
"warnings.rabbitmq_version": {
"type": "boolean",
"default": true,
"description": "Whether to print a warning when an incompatible version of RabbitMQ is configured"
},
"transport.task_retry_initial_interval": {
"type": "integer",
"default": 20,
Expand Down
93 changes: 49 additions & 44 deletions aiida/manage/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def load_profile(self, profile: Union[None, str, 'Profile'] = None, allow_switch

# Check whether a development version is being run. Note that needs to be called after ``configure_logging``
# because this function relies on the logging being properly configured for the warning to show.
check_version()
self.check_version()

return self._profile

Expand Down Expand Up @@ -309,8 +309,10 @@ def create_communicator(self, task_prefetch_count: Optional[int] = None) -> 'Rmq
# testing_mode cannot be set.
testing_mode=profile.is_test_profile,
)

# Check whether a compatible version of RabbitMQ is being used.
check_rabbitmq_version(communicator)
self.check_rabbitmq_version(communicator)

return communicator

def get_daemon_client(self) -> 'DaemonClient':
Expand Down Expand Up @@ -423,62 +425,65 @@ def create_daemon_runner(self, loop: Optional[asyncio.AbstractEventLoop] = None)

return runner

def check_rabbitmq_version(self, communicator: 'RmqThreadCommunicator'):
"""Check the version of RabbitMQ that is being connected to and emit warning if the version is not compatible.
def is_rabbitmq_version_supported(communicator: 'RmqThreadCommunicator') -> bool:
"""Return whether the version of RabbitMQ configured for the current profile is supported.
Versions 3.8.15 and above are not compatible with AiiDA with default configuration.
"""
from packaging.version import parse

Versions 3.8 and above are not compatible with AiiDA with default configuration.
from aiida.cmdline.utils import echo

:return: boolean whether the current RabbitMQ version is supported.
"""
from packaging.version import parse
return get_rabbitmq_version(communicator) < parse('3.8')
show_warning = self.get_option('warnings.rabbitmq_version')
version = get_rabbitmq_version(communicator)

if show_warning and version >= parse('3.8.15'):
echo.echo_warning(f'RabbitMQ v{version} is not supported and will cause unexpected problems!')
echo.echo_warning('It can cause long-running workflows to crash and jobs to be submitted multiple times.')
echo.echo_warning('See https://github.com/aiidateam/aiida-core/wiki/RabbitMQ-version-to-use for details.')
return version, False

def get_rabbitmq_version(communicator: 'RmqThreadCommunicator'):
"""Return the version of the RabbitMQ server that the current profile connects to.
return version, True

:return: :class:`packaging.version.Version`
"""
from packaging.version import parse
return parse(communicator.server_properties['version'].decode('utf-8'))
def check_version(self):
"""Check the currently installed version of ``aiida-core`` and warn if it is a post release development version.
The ``aiida-core`` package maintains the protocol that the ``develop`` branch will use a post release version
number. This means it will always append `.post0` to the version of the latest release. This should mean that if
this protocol is maintained properly, this method will print a warning if the currently installed version is a
post release development branch and not an actual release.
"""
from packaging.version import parse

def check_rabbitmq_version(communicator: 'RmqThreadCommunicator'):
"""Check the version of RabbitMQ that is being connected to and emit warning if the version is not compatible."""
from packaging.version import parse
from aiida import __version__
from aiida.cmdline.utils import echo

from aiida.cmdline.utils import echo
version = get_rabbitmq_version(communicator)
if version >= parse('3.8.15'):
echo.echo_warning(f'RabbitMQ v{version} is not supported and will cause unexpected problems!')
echo.echo_warning('It can cause long-running workflows to crash and jobs to be submitted multiple times.')
echo.echo_warning('See https://github.com/aiidateam/aiida-core/wiki/RabbitMQ-version-to-use for details.')
return version, False
return version, True
# Showing of the warning can be turned off by setting the following option to false.
show_warning = self.get_option('warnings.development_version')
version = parse(__version__)

if version.is_postrelease and show_warning:
echo.echo_warning(f'You are currently using a post release development version of AiiDA: {version}')
echo.echo_warning('Be aware that this is not recommended for production and is not officially supported.')
echo.echo_warning('Databases used with this version may not be compatible with future releases of AiiDA')
echo.echo_warning('as you might not be able to automatically migrate your data.\n')

def check_version():
"""Check the currently installed version of ``aiida-core`` and warn if it is a post release development version.

The ``aiida-core`` package maintains the protocol that the ``develop`` branch will use a post release version
number. This means it will always append `.post0` to the version of the latest release. This should mean that if
this protocol is maintained properly, this method will print a warning if the currently installed version is a
post release development branch and not an actual release.
def is_rabbitmq_version_supported(communicator: 'RmqThreadCommunicator') -> bool:
"""Return whether the version of RabbitMQ configured for the current profile is supported.
Versions 3.8.15 and above are not compatible with AiiDA with default configuration.
:return: boolean whether the current RabbitMQ version is supported.
"""
from packaging.version import parse
return get_rabbitmq_version(communicator) < parse('3.8.15')

from aiida import __version__
from aiida.cmdline.utils import echo
from aiida.manage.configuration import get_config_option

version = parse(__version__)

# Showing of the warning can be turned off by setting the following option to false.
show_warning = get_config_option('warnings.development_version')
def get_rabbitmq_version(communicator: 'RmqThreadCommunicator'):
"""Return the version of the RabbitMQ server that the current profile connects to.
if version.is_postrelease and show_warning:
echo.echo_warning(f'You are currently using a post release development version of AiiDA: {version}')
echo.echo_warning('Be aware that this is not recommended for production and is not officially supported.')
echo.echo_warning('Databases used with this version may not be compatible with future releases of AiiDA')
echo.echo_warning('as you might not be able to automatically migrate your data.\n')
:return: :class:`packaging.version.Version`
"""
from packaging.version import parse
return parse(communicator.server_properties['version'].decode('utf-8'))
10 changes: 5 additions & 5 deletions tests/manage/configuration/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import pytest

import aiida
from aiida.manage.manager import check_version
from aiida.manage.manager import get_manager


def test_check_version_release(monkeypatch, capsys, isolated_config):
"""Test that ``check_version`` prints nothing for a release version.
"""Test that ``Manager.check_version`` prints nothing for a release version.
If a warning is emitted, it should be printed to stdout. So even though it will go through the logging system, the
logging configuration of AiiDA will interfere with that of pytest and the ultimately the output will simply be
Expand All @@ -19,15 +19,15 @@ def test_check_version_release(monkeypatch, capsys, isolated_config):
# Explicitly setting the default in case the test profile has it changed.
isolated_config.set_option('warnings.development_version', True)

check_version()
get_manager().check_version()
captured = capsys.readouterr()
assert not captured.err
assert not captured.out


@pytest.mark.parametrize('suppress_warning', (True, False))
def test_check_version_development(monkeypatch, capsys, isolated_config, suppress_warning):
"""Test that ``check_version`` prints a warning for a post release development version.
"""Test that ``Manager.check_version`` prints a warning for a post release development version.
The warning can be suppressed by setting the option ``warnings.development_version`` to ``False``.
Expand All @@ -40,7 +40,7 @@ def test_check_version_development(monkeypatch, capsys, isolated_config, suppres

isolated_config.set_option('warnings.development_version', not suppress_warning)

check_version()
get_manager().check_version()
captured = capsys.readouterr()
assert not captured.err

Expand Down
2 changes: 1 addition & 1 deletion tests/manage/configuration/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class TestConfigurationOptions:
def test_get_option_names(self):
"""Test `get_option_names` function."""
assert isinstance(get_option_names(), list)
assert len(get_option_names()) == 27
assert len(get_option_names()) == 28

def test_get_option(self):
"""Test `get_option` function."""
Expand Down

0 comments on commit f4fda1f

Please sign in to comment.