From 7d77a26761107b6b79561ec609cf20be0fad44fc Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Fri, 24 Apr 2020 09:38:05 +0300 Subject: [PATCH] datetime: Handle timesyncd service runs conditionally systemd-timesyncd service does not run if we have another NTP daemon installed or FreedomBox runs inside a container where the host manages the time. In this case, make the application as unmanaged - app can't be disabled, no app diagnostics is shown and enable/disable functional tests are skipped. Closes #1616 Tests performed: - Run FreedomBox inside a KVM virtualization module, check that systemd-timesyncd is running, datetime app can be disabled and all diagnostics and date_and_time functional tests pass. - Run FreedomBox inside a systemd-nspawn container, check that systemd-timesyncd is not running, datetime app can't be disabled, the diagnostics button is not shown and two date_and_time functional tests are skipped. Signed-off-by: Veiko Aasa Reviewed-by: James Valleroy --- .../features/date_and_time.feature | 6 ++- .../step_definitions/application.py | 6 +++ functional_tests/support/application.py | 7 ++++ plinth/modules/datetime/__init__.py | 37 +++++++++++++++++-- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/functional_tests/features/date_and_time.feature b/functional_tests/features/date_and_time.feature index 2e49d66f6..504057609 100644 --- a/functional_tests/features/date_and_time.feature +++ b/functional_tests/features/date_and_time.feature @@ -8,12 +8,14 @@ Background: Given I'm a logged in user Scenario: Disable network time application - Given the network time application is enabled + Given the network time application can be disabled + And the network time application is enabled When I disable the network time application Then the network time service should not be running Scenario: Enable network time application - Given the network time application is disabled + Given the network time application can be disabled + And the network time application is disabled When I enable the network time application Then the network time service should be running diff --git a/functional_tests/step_definitions/application.py b/functional_tests/step_definitions/application.py index 78b041b29..88f2328df 100644 --- a/functional_tests/step_definitions/application.py +++ b/functional_tests/step_definitions/application.py @@ -33,6 +33,12 @@ def ntp_is_disabled(session_browser): application.disable(session_browser, 'ntp') +@given(parsers.parse('the network time application can be disabled')) +def ntp_can_be_disabled(session_browser): + if not application.can_be_disabled(session_browser, 'ntp'): + pytest.skip(f'network time application can\'t be disabled') + + @when(parsers.parse('I set the time zone to {time_zone:S}')) def time_zone_set(session_browser, time_zone): application.time_zone_set(session_browser, time_zone) diff --git a/functional_tests/support/application.py b/functional_tests/support/application.py index 3abd8912f..128a58f3f 100644 --- a/functional_tests/support/application.py +++ b/functional_tests/support/application.py @@ -121,6 +121,13 @@ def disable(browser, app_name): _change_app_status(browser, app_name, 'disabled') +def can_be_disabled(browser, app_name): + """Return whether the application can be disabled.""" + interface.nav_to_module(browser, get_app_module(app_name)) + button = browser.find_by_css('button[name="app_enable_disable_button"]') + return bool(button) + + def wait_for_config_update(browser, app_name): while browser.is_element_present_by_css('.running-status.loading'): sleep(0.1) diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py index 00b978409..1832b3de8 100644 --- a/plinth/modules/datetime/__init__.py +++ b/plinth/modules/datetime/__init__.py @@ -29,11 +29,13 @@ _description = [ app = None -class DateTimeApp(app_module.App): - """FreedomBox app for date and time.""" +class UnmanagedDateTimeApp(app_module.App): + """FreedomBox app for date and time if time syncronization is unmanaged.""" app_id = 'datetime' + can_be_disabled = False + def __init__(self): """Create components for the app.""" super().__init__() @@ -48,6 +50,16 @@ class DateTimeApp(app_module.App): 'datetime:index', parent_url_name='system') self.add(menu_item) + +class ManagedDateTimeApp(UnmanagedDateTimeApp): + """FreedomBox app for date and time if time syncronization is managed.""" + + can_be_disabled = True + + def __init__(self): + """Create components for the app.""" + super().__init__() + daemon = Daemon('daemon-datetime', managed_services[0]) self.add(daemon) @@ -61,7 +73,12 @@ class DateTimeApp(app_module.App): def init(): """Initialize the date/time module.""" global app - app = DateTimeApp() + + if _is_time_managed(): + app = ManagedDateTimeApp() + else: + app = UnmanagedDateTimeApp() + if app.is_enabled(): app.set_enabled(True) @@ -83,3 +100,17 @@ def _diagnose_time_synchronized(): pass return [_('Time synchronized to NTP server'), result] + + +def _is_time_managed(): + """Check whether time should be syncronized by the systemd-timesyncd. + + systemd-timesyncd does not run if we have another NTP daemon installed or + FreedomBox runs inside a container where the host manages the time. + + """ + output = subprocess.check_output([ + 'systemctl', 'show', '--property=ConditionResult', '--value', + 'systemd-timesyncd' + ]) + return 'yes' in output.decode()