From nobody Wed Jul 16 12:23:05 2025 Delivered-To: importer2@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+importer2=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1622823343; cv=none; d=zohomail.com; s=zohoarc; b=RhsbN8yrloVrOM9TdeMz3rrvShJ4Ex8luqJ7FssmAgHrdQ7wdaASSiyYorbeACDBUY0yMc30Tv4TM1jkuehuTdHbUPzQNz1cY4xZ/CbwEorGVNbidyEjjaD1NwF4nJ/gOKyoDaS63gfTOxxeHecClsrRQAjl0GB6UnxQtFgHIKc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622823343; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=54sqjr9wbeFj3idsTg9R70lwcdtZnQkFQTrwyK+XX9Y=; b=Gy75ein6Id7/c4/4s1TcsJN/pIl+XMN4WN4cXexVi6ly3PC7qSA1gnTE6wBFG5AgpZ1ef1Cj6e5oB+MXzFSZbdcNXWhyNdyZs+PODKogHtvCgIzqkd53n9B/f1PtQ5x/mpPtWx0I8qnd51wGVloBX5rRAYebRSaG1YxQgZ/VaCI= ARC-Authentication-Results: i=1; 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+importer2=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16228233431531000.746336751737; Fri, 4 Jun 2021 09:15:43 -0700 (PDT) Received: from localhost ([::1]:53322 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lpCU2-000798-16 for importer2@patchew.org; Fri, 04 Jun 2021 12:15:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45628) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lpCAt-0001CO-Rk for qemu-devel@nongnu.org; Fri, 04 Jun 2021 11:55:55 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:56961) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lpCAl-0001W9-Vl for qemu-devel@nongnu.org; Fri, 04 Jun 2021 11:55:54 -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-333-mS07WCrxOeaux6IasYmp2g-1; Fri, 04 Jun 2021 11:55:43 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 604FF9F93A; Fri, 4 Jun 2021 15:55:42 +0000 (UTC) Received: from scv.redhat.com (ovpn-116-137.rdu2.redhat.com [10.10.116.137]) by smtp.corp.redhat.com (Postfix) with ESMTP id A52B5620DE; Fri, 4 Jun 2021 15:55:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1622822146; 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=54sqjr9wbeFj3idsTg9R70lwcdtZnQkFQTrwyK+XX9Y=; b=KJBGlNk2F5PfXUafhyjsP2Iz1Sqp+oLTRLWghu9HcJJWHDN7PyhCoxe5/xNp5JCDJ2qamx 5OYSVzjXG+tQSPNml6u4WlbQOJ8s3TiGDOeCWVAGhJLgA9OtFw5PWrbehvyLiWSRwKEkhA /7PEoIkbZAIA91ay+uP38lZ8SAzwgAQ= X-MC-Unique: mS07WCrxOeaux6IasYmp2g-1 From: John Snow To: qemu-devel@nongnu.org Subject: [PATCH 08/11] scripts/qemu-ga-client: add mypy type hints Date: Fri, 4 Jun 2021 11:55:29 -0400 Message-Id: <20210604155532.1499282-9-jsnow@redhat.com> In-Reply-To: <20210604155532.1499282-1-jsnow@redhat.com> References: <20210604155532.1499282-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 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+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -31 X-Spam_score: -3.2 X-Spam_bar: --- X-Spam_report: (-3.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.373, 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_H4=0.001, RCVD_IN_MSPIKE_WL=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: Markus Armbruster , John Snow , "Niteesh G . S ." , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" This script is in slightly rough shape, but it still works. A lot of care went into its initial development. In good faith, I'm updating it to the latest Python coding standards. If there is in interest in this script, though, I'll be asking for a contributor to take care of it further. Signed-off-by: John Snow --- scripts/qmp/qemu-ga-client | 89 +++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/scripts/qmp/qemu-ga-client b/scripts/qmp/qemu-ga-client index ece9f74fa8..a7d0ef8347 100755 --- a/scripts/qmp/qemu-ga-client +++ b/scripts/qmp/qemu-ga-client @@ -44,10 +44,18 @@ import errno import os import random import sys +from typing import ( + Any, + Callable, + Dict, + Optional, + Sequence, +) =20 =20 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'pytho= n')) from qemu import qmp +from qemu.qmp import SocketAddrT =20 =20 # This script has not seen many patches or careful attention in quite @@ -58,18 +66,18 @@ from qemu import qmp =20 =20 class QemuGuestAgent(qmp.QEMUMonitorProtocol): - def __getattr__(self, name): - def wrapper(**kwds): + def __getattr__(self, name: str) -> Callable[..., Any]: + def wrapper(**kwds: object) -> object: return self.command('guest-' + name.replace('_', '-'), **kwds) return wrapper =20 =20 class QemuGuestAgentClient: - def __init__(self, address): + def __init__(self, address: SocketAddrT): self.qga =3D QemuGuestAgent(address) self.qga.connect(negotiate=3DFalse) =20 - def sync(self, timeout=3D3): + def sync(self, timeout: Optional[float] =3D 3) -> None: # Avoid being blocked forever if not self.ping(timeout): raise EnvironmentError('Agent seems not alive') @@ -79,9 +87,9 @@ class QemuGuestAgentClient: if isinstance(ret, int) and int(ret) =3D=3D uid: break =20 - def __file_read_all(self, handle): + def __file_read_all(self, handle: int) -> bytes: eof =3D False - data =3D '' + data =3D b'' while not eof: ret =3D self.qga.file_read(handle=3Dhandle, count=3D1024) _data =3D base64.b64decode(ret['buf-b64']) @@ -89,7 +97,7 @@ class QemuGuestAgentClient: eof =3D ret['eof'] return data =20 - def read(self, path): + def read(self, path: str) -> bytes: handle =3D self.qga.file_open(path=3Dpath) try: data =3D self.__file_read_all(handle) @@ -97,7 +105,7 @@ class QemuGuestAgentClient: self.qga.file_close(handle=3Dhandle) return data =20 - def info(self): + def info(self) -> str: info =3D self.qga.info() =20 msgs =3D [] @@ -113,14 +121,14 @@ class QemuGuestAgentClient: return '\n'.join(msgs) =20 @classmethod - def __gen_ipv4_netmask(cls, prefixlen): + def __gen_ipv4_netmask(cls, prefixlen: int) -> str: mask =3D int('1' * prefixlen + '0' * (32 - prefixlen), 2) return '.'.join([str(mask >> 24), str((mask >> 16) & 0xff), str((mask >> 8) & 0xff), str(mask & 0xff)]) =20 - def ifconfig(self): + def ifconfig(self) -> str: nifs =3D self.qga.network_get_interfaces() =20 msgs =3D [] @@ -141,7 +149,7 @@ class QemuGuestAgentClient: =20 return '\n'.join(msgs) =20 - def ping(self, timeout): + def ping(self, timeout: Optional[float]) -> bool: self.qga.settimeout(timeout) try: self.qga.ping() @@ -149,37 +157,40 @@ class QemuGuestAgentClient: return False return True =20 - def fsfreeze(self, cmd): + def fsfreeze(self, cmd: str) -> object: if cmd not in ['status', 'freeze', 'thaw']: raise Exception('Invalid command: ' + cmd) - + # Can be int (freeze, thaw) or GuestFsfreezeStatus (status) return getattr(self.qga, 'fsfreeze' + '_' + cmd)() =20 - def fstrim(self, minimum=3D0): - return getattr(self.qga, 'fstrim')(minimum=3Dminimum) + def fstrim(self, minimum: int) -> Dict[str, object]: + # returns GuestFilesystemTrimResponse + ret =3D getattr(self.qga, 'fstrim')(minimum=3Dminimum) + assert isinstance(ret, dict) + return ret =20 - def suspend(self, mode): + def suspend(self, mode: str) -> None: if mode not in ['disk', 'ram', 'hybrid']: raise Exception('Invalid mode: ' + mode) =20 try: getattr(self.qga, 'suspend' + '_' + mode)() # On error exception will raise - except self.qga.timeout: + except TimeoutError: # On success command will timed out return =20 - def shutdown(self, mode=3D'powerdown'): + def shutdown(self, mode: str =3D 'powerdown') -> None: if mode not in ['powerdown', 'halt', 'reboot']: raise Exception('Invalid mode: ' + mode) =20 try: self.qga.shutdown(mode=3Dmode) - except self.qga.timeout: - return + except TimeoutError: + pass =20 =20 -def _cmd_cat(client, args): +def _cmd_cat(client: QemuGuestAgentClient, args: Sequence[str]) -> None: if len(args) !=3D 1: print('Invalid argument') print('Usage: cat ') @@ -187,7 +198,7 @@ def _cmd_cat(client, args): print(client.read(args[0])) =20 =20 -def _cmd_fsfreeze(client, args): +def _cmd_fsfreeze(client: QemuGuestAgentClient, args: Sequence[str]) -> No= ne: usage =3D 'Usage: fsfreeze status|freeze|thaw' if len(args) !=3D 1: print('Invalid argument') @@ -201,13 +212,14 @@ def _cmd_fsfreeze(client, args): ret =3D client.fsfreeze(cmd) if cmd =3D=3D 'status': print(ret) - elif cmd =3D=3D 'freeze': - print("%d filesystems frozen" % ret) - else: - print("%d filesystems thawed" % ret) + return =20 + assert isinstance(ret, int) + verb =3D 'frozen' if cmd =3D=3D 'freeze' else 'thawed' + print(f"{ret:d} filesystems {verb}") =20 -def _cmd_fstrim(client, args): + +def _cmd_fstrim(client: QemuGuestAgentClient, args: Sequence[str]) -> None: if len(args) =3D=3D 0: minimum =3D 0 else: @@ -215,28 +227,25 @@ def _cmd_fstrim(client, args): print(client.fstrim(minimum)) =20 =20 -def _cmd_ifconfig(client, args): +def _cmd_ifconfig(client: QemuGuestAgentClient, args: Sequence[str]) -> No= ne: assert not args print(client.ifconfig()) =20 =20 -def _cmd_info(client, args): +def _cmd_info(client: QemuGuestAgentClient, args: Sequence[str]) -> None: assert not args print(client.info()) =20 =20 -def _cmd_ping(client, args): - if len(args) =3D=3D 0: - timeout =3D 3 - else: - timeout =3D float(args[0]) +def _cmd_ping(client: QemuGuestAgentClient, args: Sequence[str]) -> None: + timeout =3D 3.0 if len(args) =3D=3D 0 else float(args[0]) alive =3D client.ping(timeout) if not alive: print("Not responded in %s sec" % args[0]) sys.exit(1) =20 =20 -def _cmd_suspend(client, args): +def _cmd_suspend(client: QemuGuestAgentClient, args: Sequence[str]) -> Non= e: usage =3D 'Usage: suspend disk|ram|hybrid' if len(args) !=3D 1: print('Less argument') @@ -249,7 +258,7 @@ def _cmd_suspend(client, args): client.suspend(args[0]) =20 =20 -def _cmd_shutdown(client, args): +def _cmd_shutdown(client: QemuGuestAgentClient, args: Sequence[str]) -> No= ne: assert not args client.shutdown() =20 @@ -257,12 +266,12 @@ def _cmd_shutdown(client, args): _cmd_powerdown =3D _cmd_shutdown =20 =20 -def _cmd_halt(client, args): +def _cmd_halt(client: QemuGuestAgentClient, args: Sequence[str]) -> None: assert not args client.shutdown('halt') =20 =20 -def _cmd_reboot(client, args): +def _cmd_reboot(client: QemuGuestAgentClient, args: Sequence[str]) -> None: assert not args client.shutdown('reboot') =20 @@ -270,7 +279,7 @@ def _cmd_reboot(client, args): commands =3D [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m] =20 =20 -def send_command(address, cmd, args): +def send_command(address: str, cmd: str, args: Sequence[str]) -> None: if not os.path.exists(address): print('%s not found' % address) sys.exit(1) @@ -296,7 +305,7 @@ def send_command(address, cmd, args): globals()['_cmd_' + cmd](client, args) =20 =20 -def main(): +def main() -> None: address =3D os.environ.get('QGA_CLIENT_ADDRESS') =20 parser =3D argparse.ArgumentParser() --=20 2.31.1