Cleanup Admin API denial reporting
Rename QubesDaemonNoResponseError to more intuitive QubesDaemonAccessError (keep legacy name still working). Use QubesPropertyAccessError whenever the access is about @property - this makes it easy to use `getattr` to use default value instead. QubesOS/qubes-issues#5811
This commit is contained in:
parent
b04a14685c
commit
7425a5359b
@ -838,7 +838,7 @@ class QubesRemote(QubesBase):
|
|||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
(stdout, stderr) = p.communicate(payload)
|
(stdout, stderr) = p.communicate(payload)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise qubesadmin.exc.QubesDaemonNoResponseError(
|
raise qubesadmin.exc.QubesDaemonAccessError(
|
||||||
'Service call error: %s', stderr.decode())
|
'Service call error: %s', stderr.decode())
|
||||||
|
|
||||||
return self._parse_qubesd_response(stdout)
|
return self._parse_qubesd_response(stdout)
|
||||||
|
@ -78,7 +78,7 @@ class PropertyHolder(object):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
if response_data == b'':
|
if response_data == b'':
|
||||||
raise qubesadmin.exc.QubesDaemonNoResponseError(
|
raise qubesadmin.exc.QubesDaemonAccessError(
|
||||||
'Got empty response from qubesd. See journalctl in dom0 for '
|
'Got empty response from qubesd. See journalctl in dom0 for '
|
||||||
'details.')
|
'details.')
|
||||||
|
|
||||||
@ -151,11 +151,14 @@ class PropertyHolder(object):
|
|||||||
# cached properties list
|
# cached properties list
|
||||||
if self._properties is not None and item not in self._properties:
|
if self._properties is not None and item not in self._properties:
|
||||||
raise AttributeError(item)
|
raise AttributeError(item)
|
||||||
property_str = self.qubesd_call(
|
try:
|
||||||
self._method_dest,
|
property_str = self.qubesd_call(
|
||||||
self._method_prefix + 'Get',
|
self._method_dest,
|
||||||
item,
|
self._method_prefix + 'Get',
|
||||||
None)
|
item,
|
||||||
|
None)
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError(item)
|
||||||
is_default, value = self._deserialize_property(property_str)
|
is_default, value = self._deserialize_property(property_str)
|
||||||
if self.app.cache_enabled:
|
if self.app.cache_enabled:
|
||||||
self._properties_cache[item] = (is_default, value)
|
self._properties_cache[item] = (is_default, value)
|
||||||
@ -170,11 +173,14 @@ class PropertyHolder(object):
|
|||||||
'''
|
'''
|
||||||
if item.startswith('_'):
|
if item.startswith('_'):
|
||||||
raise AttributeError(item)
|
raise AttributeError(item)
|
||||||
property_str = self.qubesd_call(
|
try:
|
||||||
self._method_dest,
|
property_str = self.qubesd_call(
|
||||||
self._method_prefix + 'GetDefault',
|
self._method_dest,
|
||||||
item,
|
self._method_prefix + 'GetDefault',
|
||||||
None)
|
item,
|
||||||
|
None)
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError(item)
|
||||||
if not property_str:
|
if not property_str:
|
||||||
raise AttributeError(item + ' has no default')
|
raise AttributeError(item + ' has no default')
|
||||||
(prop_type, value) = property_str.split(b' ', 1)
|
(prop_type, value) = property_str.split(b' ', 1)
|
||||||
|
@ -161,13 +161,17 @@ class BackupRestoreError(QubesException):
|
|||||||
self.backup_log = backup_log
|
self.backup_log = backup_log
|
||||||
|
|
||||||
# pylint: disable=too-many-ancestors
|
# pylint: disable=too-many-ancestors
|
||||||
class QubesDaemonNoResponseError(QubesDaemonCommunicationError):
|
class QubesDaemonAccessError(QubesDaemonCommunicationError):
|
||||||
'''Got empty response from qubesd'''
|
'''Got empty response from qubesd. This can be lack of permission,
|
||||||
|
or some server-side issue.'''
|
||||||
|
|
||||||
|
|
||||||
class QubesPropertyAccessError(QubesException, AttributeError):
|
class QubesPropertyAccessError(QubesDaemonAccessError, AttributeError):
|
||||||
'''Failed to read/write property value, cause is unknown (insufficient
|
'''Failed to read/write property value, cause is unknown (insufficient
|
||||||
permissions, no such property, invalid value, other)'''
|
permissions, no such property, invalid value, other)'''
|
||||||
def __init__(self, prop):
|
def __init__(self, prop):
|
||||||
super(QubesPropertyAccessError, self).__init__(
|
super(QubesPropertyAccessError, self).__init__(
|
||||||
'Failed to access \'%s\' property' % prop)
|
'Failed to access \'%s\' property' % prop)
|
||||||
|
|
||||||
|
# legacy name
|
||||||
|
QubesDaemonNoResponseError = QubesDaemonAccessError
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
'''Storage subsystem.'''
|
'''Storage subsystem.'''
|
||||||
|
import qubesadmin.exc
|
||||||
|
|
||||||
class Volume(object):
|
class Volume(object):
|
||||||
'''Storage volume.'''
|
'''Storage volume.'''
|
||||||
@ -112,7 +113,10 @@ class Volume(object):
|
|||||||
'''Storage volume pool name.'''
|
'''Storage volume pool name.'''
|
||||||
if self._pool is not None:
|
if self._pool is not None:
|
||||||
return self._pool
|
return self._pool
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('pool')
|
||||||
return str(self._info['pool'])
|
return str(self._info['pool'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -120,25 +124,37 @@ class Volume(object):
|
|||||||
'''Storage volume id, unique within given pool.'''
|
'''Storage volume id, unique within given pool.'''
|
||||||
if self._vid is not None:
|
if self._vid is not None:
|
||||||
return self._vid
|
return self._vid
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('vid')
|
||||||
return str(self._info['vid'])
|
return str(self._info['vid'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
'''Size of volume, in bytes.'''
|
'''Size of volume, in bytes.'''
|
||||||
self._fetch_info(True)
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('size')
|
||||||
return int(self._info['size'])
|
return int(self._info['size'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self):
|
def usage(self):
|
||||||
'''Used volume space, in bytes.'''
|
'''Used volume space, in bytes.'''
|
||||||
self._fetch_info(True)
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('usage')
|
||||||
return int(self._info['usage'])
|
return int(self._info['usage'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rw(self):
|
def rw(self):
|
||||||
'''True if volume is read-write.'''
|
'''True if volume is read-write.'''
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('rw')
|
||||||
return self._info['rw'] == 'True'
|
return self._info['rw'] == 'True'
|
||||||
|
|
||||||
@rw.setter
|
@rw.setter
|
||||||
@ -150,13 +166,19 @@ class Volume(object):
|
|||||||
@property
|
@property
|
||||||
def snap_on_start(self):
|
def snap_on_start(self):
|
||||||
'''Create a snapshot from source on VM start.'''
|
'''Create a snapshot from source on VM start.'''
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('snap_on_start')
|
||||||
return self._info['snap_on_start'] == 'True'
|
return self._info['snap_on_start'] == 'True'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def save_on_stop(self):
|
def save_on_stop(self):
|
||||||
'''Commit changes to original volume on VM stop.'''
|
'''Commit changes to original volume on VM stop.'''
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('save_on_stop')
|
||||||
return self._info['save_on_stop'] == 'True'
|
return self._info['save_on_stop'] == 'True'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -165,7 +187,10 @@ class Volume(object):
|
|||||||
|
|
||||||
If None, this volume itself will be used.
|
If None, this volume itself will be used.
|
||||||
'''
|
'''
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('source')
|
||||||
if self._info['source']:
|
if self._info['source']:
|
||||||
return self._info['source']
|
return self._info['source']
|
||||||
return None
|
return None
|
||||||
@ -173,7 +198,10 @@ class Volume(object):
|
|||||||
@property
|
@property
|
||||||
def revisions_to_keep(self):
|
def revisions_to_keep(self):
|
||||||
'''Number of revisions to keep around'''
|
'''Number of revisions to keep around'''
|
||||||
self._fetch_info()
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('revisions_to_keep')
|
||||||
return int(self._info['revisions_to_keep'])
|
return int(self._info['revisions_to_keep'])
|
||||||
|
|
||||||
@revisions_to_keep.setter
|
@revisions_to_keep.setter
|
||||||
@ -186,7 +214,10 @@ class Volume(object):
|
|||||||
'''Returns `True` if this snapshot of a source volume (for
|
'''Returns `True` if this snapshot of a source volume (for
|
||||||
`snap_on_start`=True) is outdated.
|
`snap_on_start`=True) is outdated.
|
||||||
'''
|
'''
|
||||||
self._fetch_info(True)
|
try:
|
||||||
|
self._fetch_info()
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('is_outdated')
|
||||||
return self._info.get('is_outdated', False) == 'True'
|
return self._info.get('is_outdated', False) == 'True'
|
||||||
|
|
||||||
def resize(self, size):
|
def resize(self, size):
|
||||||
@ -290,8 +321,11 @@ class Pool(object):
|
|||||||
@property
|
@property
|
||||||
def usage_details(self):
|
def usage_details(self):
|
||||||
''' Storage pool usage details (current - not cached) '''
|
''' Storage pool usage details (current - not cached) '''
|
||||||
pool_usage_data = self.app.qubesd_call(
|
try:
|
||||||
'dom0', 'admin.pool.UsageDetails', self.name, None)
|
pool_usage_data = self.app.qubesd_call(
|
||||||
|
'dom0', 'admin.pool.UsageDetails', self.name, None)
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('usage_details')
|
||||||
pool_usage_data = pool_usage_data.decode('utf-8')
|
pool_usage_data = pool_usage_data.decode('utf-8')
|
||||||
assert pool_usage_data.endswith('\n') or pool_usage_data == ''
|
assert pool_usage_data.endswith('\n') or pool_usage_data == ''
|
||||||
pool_usage_data = pool_usage_data[:-1]
|
pool_usage_data = pool_usage_data[:-1]
|
||||||
@ -306,8 +340,11 @@ class Pool(object):
|
|||||||
def config(self):
|
def config(self):
|
||||||
''' Storage pool config '''
|
''' Storage pool config '''
|
||||||
if self._config is None:
|
if self._config is None:
|
||||||
pool_info_data = self.app.qubesd_call(
|
try:
|
||||||
'dom0', 'admin.pool.Info', self.name, None)
|
pool_info_data = self.app.qubesd_call(
|
||||||
|
'dom0', 'admin.pool.Info', self.name, None)
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('config')
|
||||||
pool_info_data = pool_info_data.decode('utf-8')
|
pool_info_data = pool_info_data.decode('utf-8')
|
||||||
assert pool_info_data.endswith('\n')
|
assert pool_info_data.endswith('\n')
|
||||||
pool_info_data = pool_info_data[:-1]
|
pool_info_data = pool_info_data[:-1]
|
||||||
@ -355,8 +392,11 @@ class Pool(object):
|
|||||||
@property
|
@property
|
||||||
def volumes(self):
|
def volumes(self):
|
||||||
''' Volumes managed by this pool '''
|
''' Volumes managed by this pool '''
|
||||||
volumes_data = self.app.qubesd_call(
|
try:
|
||||||
'dom0', 'admin.pool.volume.List', self.name, None)
|
volumes_data = self.app.qubesd_call(
|
||||||
|
'dom0', 'admin.pool.volume.List', self.name, None)
|
||||||
|
except qubesadmin.exc.QubesDaemonAccessError:
|
||||||
|
raise qubesadmin.exc.QubesPropertyAccessError('volumes')
|
||||||
assert volumes_data.endswith(b'\n')
|
assert volumes_data.endswith(b'\n')
|
||||||
volumes_data = volumes_data[:-1].decode('ascii')
|
volumes_data = volumes_data[:-1].decode('ascii')
|
||||||
for vid in volumes_data.splitlines():
|
for vid in volumes_data.splitlines():
|
||||||
|
Loading…
Reference in New Issue
Block a user