diff mbox series

[2/3] scripts: render_block_graph: Implement proper argument parser

Message ID 00eab2a417ecdb7f0ea7eaf3880806f3309133dc.1742315602.git.pkrempa@redhat.com (mailing list archive)
State New
Headers show
Series scripts: render_block_graph: Fix with new python and improve argument parsing | expand

Commit Message

Peter Krempa March 18, 2025, 4:36 p.m. UTC
From: Peter Krempa <pkrempa@redhat.com>

As no argument parsing is employed the script is hard to use and when
running without arguments it blurbs:

 $ ./scripts/render_block_graph.py
 Traceback (most recent call last):
   File "/home/pipo/git/qemu.git/./scripts/render_block_graph.py", line 135, in <module>
     obj = sys.argv[1]
          ~~~~~~~~^^^
 IndexError: list index out of range

instead of an actionable error. The user then usually needs to read the
script to understand arguments.

Implement proper argument parsing via 'argparse'. The following
arguments will be supported:

 $ ./scripts/render_block_graph.py --help
 usage: render_block_graph.py [-h] [--socket SOCKET] [--vm VM] [--uri URI] [--output OUTPUT]

 Tool that renders the qemu block graph into a image.

 options:
   -h, --help       show this help message and exit
   --socket SOCKET  direct mode - path to qemu monitor socket
   --vm VM          libvirt mode - name of libvirt VM
   --uri URI        libvirt URI to connect to
   --output OUTPUT  path to output image; .png suffix will be added; in libvirt mode default is the name of the VM

Usage then requires one of '--vm' or '--socket'. In libvirt mode the
output file is by default populated from the VM name and the '--uri'
parameter allows overriding the libvirt connection uri.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 scripts/render_block_graph.py | 53 ++++++++++++++++++++++++++++-------
 1 file changed, 43 insertions(+), 10 deletions(-)

Comments

Pavel Hrdina March 18, 2025, 8:46 p.m. UTC | #1
On Tue, Mar 18, 2025 at 05:36:03PM +0100, Peter Krempa wrote:
> From: Peter Krempa <pkrempa@redhat.com>
> 
> As no argument parsing is employed the script is hard to use and when
> running without arguments it blurbs:
> 
>  $ ./scripts/render_block_graph.py
>  Traceback (most recent call last):
>    File "/home/pipo/git/qemu.git/./scripts/render_block_graph.py", line 135, in <module>
>      obj = sys.argv[1]
>           ~~~~~~~~^^^
>  IndexError: list index out of range
> 
> instead of an actionable error. The user then usually needs to read the
> script to understand arguments.
> 
> Implement proper argument parsing via 'argparse'. The following
> arguments will be supported:
> 
>  $ ./scripts/render_block_graph.py --help
>  usage: render_block_graph.py [-h] [--socket SOCKET] [--vm VM] [--uri URI] [--output OUTPUT]
> 
>  Tool that renders the qemu block graph into a image.
> 
>  options:
>    -h, --help       show this help message and exit
>    --socket SOCKET  direct mode - path to qemu monitor socket
>    --vm VM          libvirt mode - name of libvirt VM
>    --uri URI        libvirt URI to connect to
>    --output OUTPUT  path to output image; .png suffix will be added; in libvirt mode default is the name of the VM
> 
> Usage then requires one of '--vm' or '--socket'. In libvirt mode the
> output file is by default populated from the VM name and the '--uri'
> parameter allows overriding the libvirt connection uri.
> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>  scripts/render_block_graph.py | 53 ++++++++++++++++++++++++++++-------
>  1 file changed, 43 insertions(+), 10 deletions(-)
> 
> diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
> index 14b2d02ec2..7a6738410c 100755
> --- a/scripts/render_block_graph.py
> +++ b/scripts/render_block_graph.py
> @@ -23,6 +23,7 @@
>  import subprocess
>  import json
>  from graphviz import Digraph
> +import argparse
> 
>  sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
>  from qemu.qmp import QMPError
> @@ -91,13 +92,19 @@ def render_block_graph(qmp, filename, format='png'):
> 
> 
>  class LibvirtGuest():
> -    def __init__(self, name):
> +    def __init__(self, name, uri=None):
>          self.name = name
> +        self.uri = uri
> 
>      def cmd(self, cmd):
>          # only supports qmp commands without parameters
>          m = {'execute': cmd}
> -        ar = ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)]
> +        ar = ['virsh']
> +
> +        if self.uri:
> +            ar += ['-c', self.uri]
> +
> +        ar += ['qemu-monitor-command', self.name, json.dumps(m)]
> 
>          reply = json.loads(subprocess.check_output(ar))
> 
> @@ -108,15 +115,41 @@ def cmd(self, cmd):
> 
> 
>  if __name__ == '__main__':
> -    obj = sys.argv[1]
> -    out = sys.argv[2]
> +    parser = argparse.ArgumentParser(
> +            description='Tool that renders the qemu block graph into a image.')
> +
> +    parser.add_argument('--socket',
> +                        help='direct mode - path to qemu monitor socket')
> +
> +    parser.add_argument('--vm', help='libvirt mode - name of libvirt VM')
> +    parser.add_argument('--uri', help='libvirt URI to connect to')
> +
> +    parser.add_argument('--output',
> +                        help='path to output image (.png suffix added);'
> +                             'in libvirt mode default is the name of the VM')
> +
> +    args = parser.parse_args()
> 
> -    if os.path.exists(obj):
> -        # assume unix socket
> -        qmp = QEMUMonitorProtocol(obj)
> +    if (args.socket and args.vm) or (not args.socket and not args.vm):
> +        print("One of --socket or --vm is required.", file=sys.stderr)
> +        parser.print_help()
> +        sys.exit(1)

It's possible to do with argparse as well:

modegroup = parser.add_mutually_exclusive_group(required=True)
modegroup.add_argument('--socket',
                       help='direct mode - path to qemu monitor socket')
modegroup.add_argument('--vm', help='libvirt mode - name of libvirt VM')

The only difference is that it will print usage `parser.print_usage()`.

> +
> +    if args.socket:
> +        qmp = QEMUMonitorProtocol(args.socket)
>          qmp.connect()
> -    else:
> -        # assume libvirt guest name
> -        qmp = LibvirtGuest(obj)
> +
> +    if args.vm:
> +        qmp = LibvirtGuest(args.vm, args.uri)
> +
> +        if args.output:
> +            out = args.output
> +        else:
> +            out = args.vm
> +
> +    if not out:

This needs to use args.output otherwise python will complain that it
doesn't know `out` variable.

> +        print("--output required", file=sys.stderr)
> +        parser.print_help()

Probably use `parser.print_usage()` if you decide to use the
add_mutually_exclusive_group().

Pavel

> +        sys.exit(1)
> 
>      render_block_graph(qmp, out)
> -- 
> 2.48.1
> 
>
diff mbox series

Patch

diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
index 14b2d02ec2..7a6738410c 100755
--- a/scripts/render_block_graph.py
+++ b/scripts/render_block_graph.py
@@ -23,6 +23,7 @@ 
 import subprocess
 import json
 from graphviz import Digraph
+import argparse

 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
 from qemu.qmp import QMPError
@@ -91,13 +92,19 @@  def render_block_graph(qmp, filename, format='png'):


 class LibvirtGuest():
-    def __init__(self, name):
+    def __init__(self, name, uri=None):
         self.name = name
+        self.uri = uri

     def cmd(self, cmd):
         # only supports qmp commands without parameters
         m = {'execute': cmd}
-        ar = ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)]
+        ar = ['virsh']
+
+        if self.uri:
+            ar += ['-c', self.uri]
+
+        ar += ['qemu-monitor-command', self.name, json.dumps(m)]

         reply = json.loads(subprocess.check_output(ar))

@@ -108,15 +115,41 @@  def cmd(self, cmd):


 if __name__ == '__main__':
-    obj = sys.argv[1]
-    out = sys.argv[2]
+    parser = argparse.ArgumentParser(
+            description='Tool that renders the qemu block graph into a image.')
+
+    parser.add_argument('--socket',
+                        help='direct mode - path to qemu monitor socket')
+
+    parser.add_argument('--vm', help='libvirt mode - name of libvirt VM')
+    parser.add_argument('--uri', help='libvirt URI to connect to')
+
+    parser.add_argument('--output',
+                        help='path to output image (.png suffix added);'
+                             'in libvirt mode default is the name of the VM')
+
+    args = parser.parse_args()

-    if os.path.exists(obj):
-        # assume unix socket
-        qmp = QEMUMonitorProtocol(obj)
+    if (args.socket and args.vm) or (not args.socket and not args.vm):
+        print("One of --socket or --vm is required.", file=sys.stderr)
+        parser.print_help()
+        sys.exit(1)
+
+    if args.socket:
+        qmp = QEMUMonitorProtocol(args.socket)
         qmp.connect()
-    else:
-        # assume libvirt guest name
-        qmp = LibvirtGuest(obj)
+
+    if args.vm:
+        qmp = LibvirtGuest(args.vm, args.uri)
+
+        if args.output:
+            out = args.output
+        else:
+            out = args.vm
+
+    if not out:
+        print("--output required", file=sys.stderr)
+        parser.print_help()
+        sys.exit(1)

     render_block_graph(qmp, out)