Fix saving 'updates-available' flag reported by TemplateBasedVM

Look for the first updateable template up in the template chain, instead
of going just one level up. Especially this applies to
DispVM -> AppVM -> TemplateVM case.
If DispVM reports available updates, 'updates-available'
flag should be set on relevant TemplateVM, not AppVM (*-dvm).

Include test for the new case.

Fixes QubesOS/qubes-issues#3736
This commit is contained in:
Marek Marczykowski-Górecki 2019-01-11 21:26:49 +01:00
parent 18b0fa9db7
commit bfb09f567f
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 33 additions and 3 deletions

View File

@ -108,14 +108,20 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
update_count = int(untrusted_update_count)
del untrusted_update_count
# look for the nearest updateable VM up in the template chain
updateable_template = getattr(self.src, 'template', None)
while updateable_template is not None and \
not updateable_template.updateable:
updateable_template = getattr(updateable_template, 'template', None)
if self.src.updateable:
# Just trust information from VM itself
self.src.features['updates-available'] = bool(update_count)
self.app.save()
elif getattr(self.src, 'template', None) is not None:
elif updateable_template is not None:
# Hint about updates availability in template
# If template is running - it will notify about updates itself
if self.src.template.is_running():
if updateable_template.is_running():
return
# Ignore no-updates info
if update_count > 0:
@ -123,6 +129,6 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
# in the template - ignore info
if self.src.storage.outdated_volumes:
return
self.src.template.features['updates-available'] = bool(
updateable_template.features['updates-available'] = bool(
update_count)
self.app.save()

View File

@ -249,6 +249,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
response = self.call_mgmt_func(b'qubes.NotifyUpdates', payload=b'0\n')
self.assertIsNone(response)
self.assertEqual(self.tpl.mock_calls, [
mock.call.updateable.__bool__(),
mock.call.is_running(),
])
self.assertEqual(self.app.mock_calls, [])
@ -262,6 +263,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
self.assertIsNone(response)
self.assertEqual(self.src.mock_calls, [])
self.assertEqual(self.tpl.mock_calls, [
mock.call.updateable.__bool__(),
mock.call.is_running(),
mock.call.features.__setitem__('updates-available', True),
])
@ -277,6 +279,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
self.assertIsNone(response)
self.assertEqual(self.src.mock_calls, [])
self.assertEqual(self.tpl.mock_calls, [
mock.call.updateable.__bool__(),
mock.call.is_running(),
])
self.assertIsInstance(self.tpl.updates_available, mock.Mock)
@ -290,8 +293,29 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
self.assertIsNone(response)
self.assertEqual(self.src.mock_calls, [])
self.assertEqual(self.tpl.mock_calls, [
mock.call.updateable.__bool__(),
mock.call.is_running(),
])
self.assertIsInstance(self.src.updates_available, mock.Mock)
self.assertEqual(self.app.mock_calls, [])
def test_028_notify_updates_template_based_dispvm(self):
self.dvm = self.src
self.dvm.updateable = False
self.srv = mock.NonCallableMagicMock(template=self.dvm)
self.src.updateable = False
self.src.template.is_running.return_value = False
self.src.storage.outdated_volumes = []
response = self.call_mgmt_func(b'qubes.NotifyUpdates', payload=b'1\n')
self.assertIsNone(response)
self.assertEqual(self.src.mock_calls, [])
self.assertEqual(self.dvm.mock_calls, [])
self.assertEqual(self.tpl.mock_calls, [
mock.call.updateable.__bool__(),
mock.call.is_running(),
mock.call.features.__setitem__('updates-available', True),
])
self.assertIsInstance(self.src.updates_available, mock.Mock)
self.assertEqual(self.app.mock_calls, [
mock.call.save()
])