Merge branch 'devel-1'
* devel-1: toos: fix handling default command (qvm-device, qvm-volume, ...) events: fix parsing events with empty parameters tools: ignore qvm-template-postprocess calls in chroot app: close payload_stream in qubesd_call
This commit is contained in:
commit
a42dffcb89
@ -350,6 +350,8 @@ class QubesLocal(QubesBase):
|
|||||||
:param payload: Payload send to the method
|
:param payload: Payload send to the method
|
||||||
:param payload_stream: file-like object to read payload from
|
:param payload_stream: file-like object to read payload from
|
||||||
:return: Data returned by qubesd (string)
|
:return: Data returned by qubesd (string)
|
||||||
|
|
||||||
|
.. warning:: *payload_stream* will get closed by this function
|
||||||
'''
|
'''
|
||||||
if payload and payload_stream:
|
if payload and payload_stream:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -369,6 +371,7 @@ class QubesLocal(QubesBase):
|
|||||||
qrexec_call_env['QREXEC_REQUESTED_TARGET'] = dest
|
qrexec_call_env['QREXEC_REQUESTED_TARGET'] = dest
|
||||||
proc = subprocess.Popen([method_path, arg], stdin=payload_stream,
|
proc = subprocess.Popen([method_path, arg], stdin=payload_stream,
|
||||||
stdout=subprocess.PIPE, env=qrexec_call_env)
|
stdout=subprocess.PIPE, env=qrexec_call_env)
|
||||||
|
payload_stream.close()
|
||||||
(return_data, _) = proc.communicate()
|
(return_data, _) = proc.communicate()
|
||||||
return self._parse_qubesd_response(return_data)
|
return self._parse_qubesd_response(return_data)
|
||||||
|
|
||||||
@ -455,6 +458,8 @@ class QubesRemote(QubesBase):
|
|||||||
:param payload: Payload send to the method
|
:param payload: Payload send to the method
|
||||||
:param payload_stream: file-like object to read payload from
|
:param payload_stream: file-like object to read payload from
|
||||||
:return: Data returned by qubesd (string)
|
:return: Data returned by qubesd (string)
|
||||||
|
|
||||||
|
.. warning:: *payload_stream* will get closed by this function
|
||||||
'''
|
'''
|
||||||
if payload and payload_stream:
|
if payload and payload_stream:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -467,6 +472,8 @@ class QubesRemote(QubesBase):
|
|||||||
stdin=(payload_stream or subprocess.PIPE),
|
stdin=(payload_stream or subprocess.PIPE),
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
|
if payload_stream is not None:
|
||||||
|
payload_stream.close()
|
||||||
(stdout, stderr) = p.communicate(payload)
|
(stdout, stderr) = p.communicate(payload)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
# TODO: use dedicated exception
|
# TODO: use dedicated exception
|
||||||
|
@ -147,25 +147,32 @@ class EventsDispatcher(object):
|
|||||||
some_event_received = False
|
some_event_received = False
|
||||||
while not reader.at_eof():
|
while not reader.at_eof():
|
||||||
try:
|
try:
|
||||||
event_data = yield from reader.readuntil(b'\0\0')
|
event_header = yield from reader.readuntil(b'\0')
|
||||||
if event_data == b'1\0\0':
|
if event_header != b'1\0':
|
||||||
# event with non-VM subject contains \0\0 inside of
|
raise qubesadmin.exc.QubesDaemonCommunicationError(
|
||||||
# event, need to receive rest of the data
|
'Non-event received on events connection: '
|
||||||
event_data += yield from reader.readuntil(b'\0\0')
|
+ repr(event_header))
|
||||||
|
subject = (yield from reader.readuntil(b'\0'))[:-1].decode(
|
||||||
|
'utf-8')
|
||||||
|
event = (yield from reader.readuntil(b'\0'))[:-1].decode(
|
||||||
|
'utf-8')
|
||||||
|
kwargs = {}
|
||||||
|
while True:
|
||||||
|
key = (yield from reader.readuntil(b'\0'))[:-1].decode(
|
||||||
|
'utf-8')
|
||||||
|
if not key:
|
||||||
|
break
|
||||||
|
value = (yield from reader.readuntil(b'\0'))[:-1].\
|
||||||
|
decode('utf-8')
|
||||||
|
kwargs[key] = value
|
||||||
except asyncio.IncompleteReadError as err:
|
except asyncio.IncompleteReadError as err:
|
||||||
if err.partial == b'':
|
if err.partial == b'':
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if not event_data.startswith(b'1\0'):
|
if not subject:
|
||||||
raise qubesadmin.exc.QubesDaemonCommunicationError(
|
subject = None
|
||||||
'Non-event received on events connection: '
|
|
||||||
+ repr(event_data))
|
|
||||||
event_data = event_data.decode('utf-8')
|
|
||||||
_, subject, event, *kwargs = event_data.split('\0')
|
|
||||||
# convert list to dict, remove last empty entry
|
|
||||||
kwargs = dict(zip(kwargs[:-2:2], kwargs[1:-2:2]))
|
|
||||||
self.handle(subject, event, **kwargs)
|
self.handle(subject, event, **kwargs)
|
||||||
|
|
||||||
some_event_received = True
|
some_event_received = True
|
||||||
|
@ -107,7 +107,7 @@ class TC_00_Events(qubesadmin.tests.QubesTestCase):
|
|||||||
events = [
|
events = [
|
||||||
b'1\0\0some-event\0arg1\0value1\0\0',
|
b'1\0\0some-event\0arg1\0value1\0\0',
|
||||||
b'1\0some-vm\0some-event\0arg1\0value1\0\0',
|
b'1\0some-vm\0some-event\0arg1\0value1\0\0',
|
||||||
b'1\0some-vm\0some-event\0\0',
|
b'1\0some-vm\0some-event\0arg_without_value\0\0arg2\0value\0\0',
|
||||||
b'1\0some-vm\0other-event\0\0',
|
b'1\0some-vm\0other-event\0\0',
|
||||||
]
|
]
|
||||||
asyncio.ensure_future(self.send_events(stream, events))
|
asyncio.ensure_future(self.send_events(stream, events))
|
||||||
@ -117,7 +117,9 @@ class TC_00_Events(qubesadmin.tests.QubesTestCase):
|
|||||||
unittest.mock.call(None, 'some-event', arg1='value1'),
|
unittest.mock.call(None, 'some-event', arg1='value1'),
|
||||||
unittest.mock.call(
|
unittest.mock.call(
|
||||||
self.app.domains['some-vm'], 'some-event', arg1='value1'),
|
self.app.domains['some-vm'], 'some-event', arg1='value1'),
|
||||||
unittest.mock.call(self.app.domains['some-vm'], 'some-event'),
|
unittest.mock.call(
|
||||||
|
self.app.domains['some-vm'], 'some-event',
|
||||||
|
arg_without_value='', arg2='value'),
|
||||||
])
|
])
|
||||||
cleanup_func.assert_called_once_with()
|
cleanup_func.assert_called_once_with()
|
||||||
loop.close()
|
loop.close()
|
||||||
|
@ -389,6 +389,8 @@ class QubesArgumentParser(argparse.ArgumentParser):
|
|||||||
argparse._SubParsersAction): # pylint: disable=no-member
|
argparse._SubParsersAction): # pylint: disable=no-member
|
||||||
assert hasattr(namespace, 'command')
|
assert hasattr(namespace, 'command')
|
||||||
command = namespace.command
|
command = namespace.command
|
||||||
|
if command is None:
|
||||||
|
continue
|
||||||
subparser = action._name_parser_map[command]
|
subparser = action._name_parser_map[command]
|
||||||
for subaction in subparser._actions:
|
for subaction in subparser._actions:
|
||||||
if issubclass(subaction.__class__, QubesAction):
|
if issubclass(subaction.__class__, QubesAction):
|
||||||
|
@ -201,6 +201,10 @@ def get_parser(device_class=None):
|
|||||||
else:
|
else:
|
||||||
parser.add_argument('devclass', metavar='DEVICE_CLASS', action='store',
|
parser.add_argument('devclass', metavar='DEVICE_CLASS', action='store',
|
||||||
help="Device class to manage ('pci', 'usb', etc)")
|
help="Device class to manage ('pci', 'usb', etc)")
|
||||||
|
|
||||||
|
# default action
|
||||||
|
parser.set_defaults(func=list_devices)
|
||||||
|
|
||||||
sub_parsers = parser.add_subparsers(
|
sub_parsers = parser.add_subparsers(
|
||||||
title='commands',
|
title='commands',
|
||||||
description="For more information see qvm-device command -h",
|
description="For more information see qvm-device command -h",
|
||||||
|
@ -96,13 +96,12 @@ def import_root_img(vm, source_dir):
|
|||||||
tar = subprocess.Popen(['tar', 'xSOf', '-'],
|
tar = subprocess.Popen(['tar', 'xSOf', '-'],
|
||||||
stdin=cat.stdout,
|
stdin=cat.stdout,
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
|
cat.stdout.close()
|
||||||
vm.volumes['root'].import_data(stream=tar.stdout)
|
vm.volumes['root'].import_data(stream=tar.stdout)
|
||||||
if tar.wait() != 0:
|
if tar.wait() != 0:
|
||||||
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
||||||
if cat.wait() != 0:
|
if cat.wait() != 0:
|
||||||
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
||||||
cat.stdout.close()
|
|
||||||
tar.stdout.close()
|
|
||||||
elif os.path.exists(root_path):
|
elif os.path.exists(root_path):
|
||||||
if vm.app.qubesd_connection_type == 'socket':
|
if vm.app.qubesd_connection_type == 'socket':
|
||||||
# check if root.img was already overwritten, i.e. if the source
|
# check if root.img was already overwritten, i.e. if the source
|
||||||
@ -212,9 +211,29 @@ def pre_remove(args):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def is_chroot():
|
||||||
|
'''Detect if running inside chroot'''
|
||||||
|
try:
|
||||||
|
stat_root = os.stat('/')
|
||||||
|
stat_init_root = os.stat('/proc/1/root/.')
|
||||||
|
return (
|
||||||
|
stat_root.st_dev != stat_init_root.st_dev or
|
||||||
|
stat_root.st_ino != stat_init_root.st_ino)
|
||||||
|
except IOError:
|
||||||
|
print('Stat failed, assuming not chroot', file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main(args=None, app=None):
|
def main(args=None, app=None):
|
||||||
'''Main function of qvm-template-postprocess'''
|
'''Main function of qvm-template-postprocess'''
|
||||||
args = parser.parse_args(args, app=app)
|
args = parser.parse_args(args, app=app)
|
||||||
|
|
||||||
|
if is_chroot():
|
||||||
|
print('Running in chroot, ignoring request. Import template with:',
|
||||||
|
file=sys.stderr)
|
||||||
|
print(' '.join(sys.argv), file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
if not args.really:
|
if not args.really:
|
||||||
parser.error('Do not call this tool directly.')
|
parser.error('Do not call this tool directly.')
|
||||||
if args.action == 'post-install':
|
if args.action == 'post-install':
|
||||||
|
@ -192,6 +192,7 @@ def init_extend_parser(sub_parsers):
|
|||||||
extend_parser.add_argument('size', help='New size in bytes')
|
extend_parser.add_argument('size', help='New size in bytes')
|
||||||
extend_parser.set_defaults(func=extend_volumes)
|
extend_parser.set_defaults(func=extend_volumes)
|
||||||
|
|
||||||
|
|
||||||
def get_parser():
|
def get_parser():
|
||||||
'''Create :py:class:`argparse.ArgumentParser` suitable for
|
'''Create :py:class:`argparse.ArgumentParser` suitable for
|
||||||
:program:`qvm-block`.
|
:program:`qvm-block`.
|
||||||
@ -207,6 +208,8 @@ def get_parser():
|
|||||||
init_extend_parser(sub_parsers)
|
init_extend_parser(sub_parsers)
|
||||||
init_list_parser(sub_parsers)
|
init_list_parser(sub_parsers)
|
||||||
init_revert_parser(sub_parsers)
|
init_revert_parser(sub_parsers)
|
||||||
|
# default action
|
||||||
|
parser.set_defaults(func=list_volumes)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user