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:
parent
18b0fa9db7
commit
bfb09f567f
@ -108,14 +108,20 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
update_count = int(untrusted_update_count)
|
update_count = int(untrusted_update_count)
|
||||||
del 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:
|
if self.src.updateable:
|
||||||
# Just trust information from VM itself
|
# Just trust information from VM itself
|
||||||
self.src.features['updates-available'] = bool(update_count)
|
self.src.features['updates-available'] = bool(update_count)
|
||||||
self.app.save()
|
self.app.save()
|
||||||
elif getattr(self.src, 'template', None) is not None:
|
elif updateable_template is not None:
|
||||||
# Hint about updates availability in template
|
# Hint about updates availability in template
|
||||||
# If template is running - it will notify about updates itself
|
# If template is running - it will notify about updates itself
|
||||||
if self.src.template.is_running():
|
if updateable_template.is_running():
|
||||||
return
|
return
|
||||||
# Ignore no-updates info
|
# Ignore no-updates info
|
||||||
if update_count > 0:
|
if update_count > 0:
|
||||||
@ -123,6 +129,6 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
# in the template - ignore info
|
# in the template - ignore info
|
||||||
if self.src.storage.outdated_volumes:
|
if self.src.storage.outdated_volumes:
|
||||||
return
|
return
|
||||||
self.src.template.features['updates-available'] = bool(
|
updateable_template.features['updates-available'] = bool(
|
||||||
update_count)
|
update_count)
|
||||||
self.app.save()
|
self.app.save()
|
||||||
|
@ -249,6 +249,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
|
|||||||
response = self.call_mgmt_func(b'qubes.NotifyUpdates', payload=b'0\n')
|
response = self.call_mgmt_func(b'qubes.NotifyUpdates', payload=b'0\n')
|
||||||
self.assertIsNone(response)
|
self.assertIsNone(response)
|
||||||
self.assertEqual(self.tpl.mock_calls, [
|
self.assertEqual(self.tpl.mock_calls, [
|
||||||
|
mock.call.updateable.__bool__(),
|
||||||
mock.call.is_running(),
|
mock.call.is_running(),
|
||||||
])
|
])
|
||||||
self.assertEqual(self.app.mock_calls, [])
|
self.assertEqual(self.app.mock_calls, [])
|
||||||
@ -262,6 +263,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
|
|||||||
self.assertIsNone(response)
|
self.assertIsNone(response)
|
||||||
self.assertEqual(self.src.mock_calls, [])
|
self.assertEqual(self.src.mock_calls, [])
|
||||||
self.assertEqual(self.tpl.mock_calls, [
|
self.assertEqual(self.tpl.mock_calls, [
|
||||||
|
mock.call.updateable.__bool__(),
|
||||||
mock.call.is_running(),
|
mock.call.is_running(),
|
||||||
mock.call.features.__setitem__('updates-available', True),
|
mock.call.features.__setitem__('updates-available', True),
|
||||||
])
|
])
|
||||||
@ -277,6 +279,7 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
|
|||||||
self.assertIsNone(response)
|
self.assertIsNone(response)
|
||||||
self.assertEqual(self.src.mock_calls, [])
|
self.assertEqual(self.src.mock_calls, [])
|
||||||
self.assertEqual(self.tpl.mock_calls, [
|
self.assertEqual(self.tpl.mock_calls, [
|
||||||
|
mock.call.updateable.__bool__(),
|
||||||
mock.call.is_running(),
|
mock.call.is_running(),
|
||||||
])
|
])
|
||||||
self.assertIsInstance(self.tpl.updates_available, mock.Mock)
|
self.assertIsInstance(self.tpl.updates_available, mock.Mock)
|
||||||
@ -290,8 +293,29 @@ class TC_00_API_Misc(qubes.tests.QubesTestCase):
|
|||||||
self.assertIsNone(response)
|
self.assertIsNone(response)
|
||||||
self.assertEqual(self.src.mock_calls, [])
|
self.assertEqual(self.src.mock_calls, [])
|
||||||
self.assertEqual(self.tpl.mock_calls, [
|
self.assertEqual(self.tpl.mock_calls, [
|
||||||
|
mock.call.updateable.__bool__(),
|
||||||
mock.call.is_running(),
|
mock.call.is_running(),
|
||||||
])
|
])
|
||||||
self.assertIsInstance(self.src.updates_available, mock.Mock)
|
self.assertIsInstance(self.src.updates_available, mock.Mock)
|
||||||
self.assertEqual(self.app.mock_calls, [])
|
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()
|
||||||
|
])
|
||||||
|
Loading…
Reference in New Issue
Block a user