From nobody Mon Feb 9 13:22:23 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1635271478209587.2519655459657; Tue, 26 Oct 2021 11:04:38 -0700 (PDT) Received: from localhost ([::1]:49464 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mfQoN-0004Xf-Vp for importer@patchew.org; Tue, 26 Oct 2021 14:04:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51552) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfQga-0003eA-Lw for qemu-devel@nongnu.org; Tue, 26 Oct 2021 13:56:32 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:21039) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfQgT-0004Yu-7x for qemu-devel@nongnu.org; Tue, 26 Oct 2021 13:56:32 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-186-onZLZHGNOmKwWVnDnKlZgA-1; Tue, 26 Oct 2021 13:56:21 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9293681CBDB; Tue, 26 Oct 2021 17:56:20 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.17.51]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7F521ADC8; Tue, 26 Oct 2021 17:56:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1635270984; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pNkumLhAQCxxnmqXVCE5nbKfqoIhJY7Inz+zB/lk0AE=; b=Te2LRuYI/R+cCdpu0F2Ts//UNzenKelKFEe1TbHMm/oXKGj9HcyAk+Rm9afAYedxDkdEa7 vvN6w65LryQN0W55xsQDFyzdgszkQZfZhKABdMs2v4tISnbziXbA1+21fKcMfiKFt65K0/ 4OFuxT83QBDlHoeQQrPpTjcwnGLuXvA= X-MC-Unique: onZLZHGNOmKwWVnDnKlZgA-1 From: John Snow To: qemu-devel@nongnu.org Subject: [PATCH v5 7/8] python/aqmp: Create sync QMP wrapper for iotests Date: Tue, 26 Oct 2021 13:56:11 -0400 Message-Id: <20211026175612.4127598-8-jsnow@redhat.com> In-Reply-To: <20211026175612.4127598-1-jsnow@redhat.com> References: <20211026175612.4127598-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Vladimir Sementsov-Ogievskiy , Eduardo Habkost , qemu-block@nongnu.org, Hanna Reitz , Cleber Rosa , John Snow Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1635271479443100001 Content-Type: text/plain; charset="utf-8" This is a wrapper around the async QMPClient that mimics the old, synchronous QEMUMonitorProtocol class. It is designed to be interchangeable with the old implementation. It does not, however, attempt to mimic Exception compatibility. Signed-off-by: John Snow Acked-by: Hanna Reitz --- python/qemu/aqmp/legacy.py | 138 +++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 python/qemu/aqmp/legacy.py diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py new file mode 100644 index 00000000000..9e7b9fb80b9 --- /dev/null +++ b/python/qemu/aqmp/legacy.py @@ -0,0 +1,138 @@ +""" +Sync QMP Wrapper + +This class pretends to be qemu.qmp.QEMUMonitorProtocol. +""" + +import asyncio +from typing import ( + Awaitable, + List, + Optional, + TypeVar, + Union, +) + +import qemu.qmp +from qemu.qmp import QMPMessage, QMPReturnValue, SocketAddrT + +from .qmp_client import QMPClient + + +# pylint: disable=3Dmissing-docstring + + +class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol): + def __init__(self, address: SocketAddrT, + server: bool =3D False, + nickname: Optional[str] =3D None): + + # pylint: disable=3Dsuper-init-not-called + self._aqmp =3D QMPClient(nickname) + self._aloop =3D asyncio.get_event_loop() + self._address =3D address + self._timeout: Optional[float] =3D None + + _T =3D TypeVar('_T') + + def _sync( + self, future: Awaitable[_T], timeout: Optional[float] =3D None + ) -> _T: + return self._aloop.run_until_complete( + asyncio.wait_for(future, timeout=3Dtimeout) + ) + + def _get_greeting(self) -> Optional[QMPMessage]: + if self._aqmp.greeting is not None: + # pylint: disable=3Dprotected-access + return self._aqmp.greeting._asdict() + return None + + # __enter__ and __exit__ need no changes + # parse_address needs no changes + + def connect(self, negotiate: bool =3D True) -> Optional[QMPMessage]: + self._aqmp.await_greeting =3D negotiate + self._aqmp.negotiate =3D negotiate + + self._sync( + self._aqmp.connect(self._address) + ) + return self._get_greeting() + + def accept(self, timeout: Optional[float] =3D 15.0) -> QMPMessage: + self._aqmp.await_greeting =3D True + self._aqmp.negotiate =3D True + + self._sync( + self._aqmp.accept(self._address), + timeout + ) + + ret =3D self._get_greeting() + assert ret is not None + return ret + + def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: + return dict( + self._sync( + # pylint: disable=3Dprotected-access + + # _raw() isn't a public API, because turning off + # automatic ID assignment is discouraged. For + # compatibility with iotests *only*, do it anyway. + self._aqmp._raw(qmp_cmd, assign_id=3DFalse), + self._timeout + ) + ) + + # Default impl of cmd() delegates to cmd_obj + + def command(self, cmd: str, **kwds: object) -> QMPReturnValue: + return self._sync( + self._aqmp.execute(cmd, kwds), + self._timeout + ) + + def pull_event(self, + wait: Union[bool, float] =3D False) -> Optional[QMPMess= age]: + if not wait: + # wait is False/0: "do not wait, do not except." + if self._aqmp.events.empty(): + return None + + # If wait is 'True', wait forever. If wait is False/0, the events + # queue must not be empty; but it still needs some real amount + # of time to complete. + timeout =3D None + if wait and isinstance(wait, float): + timeout =3D wait + + return dict( + self._sync( + self._aqmp.events.get(), + timeout + ) + ) + + def get_events(self, wait: Union[bool, float] =3D False) -> List[QMPMe= ssage]: + events =3D [dict(x) for x in self._aqmp.events.clear()] + if events: + return events + + event =3D self.pull_event(wait) + return [event] if event is not None else [] + + def clear_events(self) -> None: + self._aqmp.events.clear() + + def close(self) -> None: + self._sync( + self._aqmp.disconnect() + ) + + def settimeout(self, timeout: Optional[float]) -> None: + self._timeout =3D timeout + + def send_fd_scm(self, fd: int) -> None: + self._aqmp.send_fd_scm(fd) --=20 2.31.1