storage: improve error reporting

- make it clear that failed qubes.ResizeDisk service call means the need
to resize filesystem manually (but not necessarily the volume itself)
- propagate exceptions raised by async storage pool implementations

Related QubesOS/qubes-issues#3173
This commit is contained in:
Marek Marczykowski-Górecki 2017-10-16 01:52:34 +02:00
parent 27b96cce4c
commit 49e35e66aa
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -28,6 +28,7 @@ import inspect
import os
import os.path
import string # pylint: disable=deprecated-module
import subprocess
import time
from datetime import datetime
@ -481,9 +482,17 @@ class Storage(object):
if asyncio.iscoroutine(ret):
yield from ret
if self.vm.is_running():
yield from self.vm.run_service_for_stdio('qubes.ResizeDisk',
input=volume.name.encode(),
user='root')
try:
yield from self.vm.run_service_for_stdio('qubes.ResizeDisk',
input=volume.name.encode(),
user='root')
except subprocess.CalledProcessError as e:
service_error = e.stderr.decode('ascii', errors='ignore')
service_error = service_error.replace('%', '')
raise StoragePoolException(
'Online resize of volume {} failed (you need to resize '
'filesystem manually): {}'.format(volume, service_error))
@asyncio.coroutine
def create(self):
@ -573,7 +582,10 @@ class Storage(object):
if asyncio.iscoroutine(ret):
futures.append(ret)
if futures:
yield from asyncio.wait(futures)
done, _ = yield from asyncio.wait(futures)
for task in done:
# re-raise any exception from async task
task.result()
self.vm.fire_event('domain-verify-files')
return True
@ -595,7 +607,10 @@ class Storage(object):
if futures:
try:
yield from asyncio.wait(futures)
done, _ = yield from asyncio.wait(futures)
for task in done:
# re-raise any exception from async task
task.result()
except (IOError, OSError) as e:
self.vm.log.exception("Failed to remove some volume", e)
@ -609,7 +624,10 @@ class Storage(object):
futures.append(ret)
if futures:
yield from asyncio.wait(futures)
done, _ = yield from asyncio.wait(futures)
for task in done:
# re-raise any exception from async task
task.result()
@asyncio.coroutine
def stop(self):
@ -621,7 +639,10 @@ class Storage(object):
futures.append(ret)
if futures:
yield from asyncio.wait(futures)
done, _ = yield from asyncio.wait(futures)
for task in done:
# re-raise any exception from async task
task.result()
def unused_frontend(self):
''' Find an unused device name '''