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_stream: file-like object to read payload from
|
||||
:return: Data returned by qubesd (string)
|
||||
|
||||
.. warning:: *payload_stream* will get closed by this function
|
||||
'''
|
||||
if payload and payload_stream:
|
||||
raise ValueError(
|
||||
@ -369,6 +371,7 @@ class QubesLocal(QubesBase):
|
||||
qrexec_call_env['QREXEC_REQUESTED_TARGET'] = dest
|
||||
proc = subprocess.Popen([method_path, arg], stdin=payload_stream,
|
||||
stdout=subprocess.PIPE, env=qrexec_call_env)
|
||||
payload_stream.close()
|
||||
(return_data, _) = proc.communicate()
|
||||
return self._parse_qubesd_response(return_data)
|
||||
|
||||
@ -455,6 +458,8 @@ class QubesRemote(QubesBase):
|
||||
:param payload: Payload send to the method
|
||||
:param payload_stream: file-like object to read payload from
|
||||
:return: Data returned by qubesd (string)
|
||||
|
||||
.. warning:: *payload_stream* will get closed by this function
|
||||
'''
|
||||
if payload and payload_stream:
|
||||
raise ValueError(
|
||||
@ -467,6 +472,8 @@ class QubesRemote(QubesBase):
|
||||
stdin=(payload_stream or subprocess.PIPE),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
if payload_stream is not None:
|
||||
payload_stream.close()
|
||||
(stdout, stderr) = p.communicate(payload)
|
||||
if p.returncode != 0:
|
||||
# TODO: use dedicated exception
|
||||
|
@ -147,25 +147,32 @@ class EventsDispatcher(object):
|
||||
some_event_received = False
|
||||
while not reader.at_eof():
|
||||
try:
|
||||
event_data = yield from reader.readuntil(b'\0\0')
|
||||
if event_data == b'1\0\0':
|
||||
# event with non-VM subject contains \0\0 inside of
|
||||
# event, need to receive rest of the data
|
||||
event_data += yield from reader.readuntil(b'\0\0')
|
||||
event_header = yield from reader.readuntil(b'\0')
|
||||
if event_header != b'1\0':
|
||||
raise qubesadmin.exc.QubesDaemonCommunicationError(
|
||||
'Non-event received on events connection: '
|
||||
+ 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:
|
||||
if err.partial == b'':
|
||||
break
|
||||
else:
|
||||
raise
|
||||
|
||||
if not event_data.startswith(b'1\0'):
|
||||
raise qubesadmin.exc.QubesDaemonCommunicationError(
|
||||
'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]))
|
||||
if not subject:
|
||||
subject = None
|
||||
self.handle(subject, event, **kwargs)
|
||||
|
||||
some_event_received = True
|
||||
|
@ -107,7 +107,7 @@ class TC_00_Events(qubesadmin.tests.QubesTestCase):
|
||||
events = [
|
||||
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\0\0',
|
||||
b'1\0some-vm\0some-event\0arg_without_value\0\0arg2\0value\0\0',
|
||||
b'1\0some-vm\0other-event\0\0',
|
||||
]
|
||||
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(
|
||||
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()
|
||||
loop.close()
|
||||
|
@ -389,6 +389,8 @@ class QubesArgumentParser(argparse.ArgumentParser):
|
||||
argparse._SubParsersAction): # pylint: disable=no-member
|
||||
assert hasattr(namespace, 'command')
|
||||
command = namespace.command
|
||||
if command is None:
|
||||
continue
|
||||
subparser = action._name_parser_map[command]
|
||||
for subaction in subparser._actions:
|
||||
if issubclass(subaction.__class__, QubesAction):
|
||||
|
@ -201,6 +201,10 @@ def get_parser(device_class=None):
|
||||
else:
|
||||
parser.add_argument('devclass', metavar='DEVICE_CLASS', action='store',
|
||||
help="Device class to manage ('pci', 'usb', etc)")
|
||||
|
||||
# default action
|
||||
parser.set_defaults(func=list_devices)
|
||||
|
||||
sub_parsers = parser.add_subparsers(
|
||||
title='commands',
|
||||
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', '-'],
|
||||
stdin=cat.stdout,
|
||||
stdout=subprocess.PIPE)
|
||||
cat.stdout.close()
|
||||
vm.volumes['root'].import_data(stream=tar.stdout)
|
||||
if tar.wait() != 0:
|
||||
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
||||
if cat.wait() != 0:
|
||||
raise qubesadmin.exc.QubesException('root.img extraction failed')
|
||||
cat.stdout.close()
|
||||
tar.stdout.close()
|
||||
elif os.path.exists(root_path):
|
||||
if vm.app.qubesd_connection_type == 'socket':
|
||||
# check if root.img was already overwritten, i.e. if the source
|
||||
@ -212,9 +211,29 @@ def pre_remove(args):
|
||||
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):
|
||||
'''Main function of qvm-template-postprocess'''
|
||||
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:
|
||||
parser.error('Do not call this tool directly.')
|
||||
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.set_defaults(func=extend_volumes)
|
||||
|
||||
|
||||
def get_parser():
|
||||
'''Create :py:class:`argparse.ArgumentParser` suitable for
|
||||
:program:`qvm-block`.
|
||||
@ -207,6 +208,8 @@ def get_parser():
|
||||
init_extend_parser(sub_parsers)
|
||||
init_list_parser(sub_parsers)
|
||||
init_revert_parser(sub_parsers)
|
||||
# default action
|
||||
parser.set_defaults(func=list_volumes)
|
||||
|
||||
return parser
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user