xref: /spdk/scripts/rpc.py (revision e18d2b768751504a9f673d45f20172210c027970)
1#!/usr/bin/env python
2
3from rpc.client import print_dict, JSONRPCException
4
5import argparse
6import rpc
7
8try:
9    from shlex import quote
10except ImportError:
11    from pipes import quote
12
13
14def print_array(a):
15    print(" ".join((quote(v) for v in a)))
16
17
18def call_cmd(func):
19    def rpc_cmd(*args, **kwargs):
20        try:
21            func(*args, **kwargs)
22        except JSONRPCException as ex:
23            print(ex.message)
24            exit(1)
25    return rpc_cmd
26
27
28if __name__ == "__main__":
29    parser = argparse.ArgumentParser(
30        description='SPDK RPC command line interface')
31    parser.add_argument('-s', dest='server_addr',
32                        help='RPC server address', default='/var/tmp/spdk.sock')
33    parser.add_argument('-p', dest='port',
34                        help='RPC port number (if server_addr is IP address)',
35                        default=5260, type=int)
36    parser.add_argument('-t', dest='timeout',
37                        help='Timout as a floating point number expressed in seconds waiting for reponse. Default: 60.0',
38                        default=60.0, type=float)
39    parser.add_argument('-v', dest='verbose',
40                        help='Verbose mode', action='store_true')
41    subparsers = parser.add_subparsers(help='RPC methods')
42
43    @call_cmd
44    def get_rpc_methods(args):
45        print_dict(rpc.get_rpc_methods(args.client))
46
47    p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods')
48    p.set_defaults(func=get_rpc_methods)
49
50    @call_cmd
51    def save_config(args):
52        rpc.save_config(args.client, args)
53
54    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets.
55    If no filename is given write configuration to stdout.""")
56    p.add_argument('-f', '--filename', help="""File where to save JSON configuration to.""")
57    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. If filename is not given default
58    indent level is 2. If writing to file of filename is '-' then default is compact mode.""", type=int, default=2)
59    p.set_defaults(func=save_config)
60
61    @call_cmd
62    def load_config(args):
63        rpc.load_config(args.client, args)
64
65    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and tagets using JSON RPC. If no file is
66    provided or file is '-' read configuration from stdin.""")
67    p.add_argument('--filename', help="""JSON Configuration file.""")
68    p.set_defaults(func=load_config)
69
70    # app
71    @call_cmd
72    def kill_instance(args):
73        rpc.app.kill_instance(args.client, args)
74
75    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
76    p.add_argument('sig_name', help='signal will be sent to server.')
77    p.set_defaults(func=kill_instance)
78
79    @call_cmd
80    def context_switch_monitor(args):
81        print_dict(rpc.app.context_switch_monitor(args.client, args))
82
83    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
84    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
85    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
86    p.set_defaults(func=context_switch_monitor)
87
88    # bdev
89    @call_cmd
90    def construct_malloc_bdev(args):
91        print_array(rpc.bdev.construct_malloc_bdev(args.client, args))
92
93    p = subparsers.add_parser('construct_malloc_bdev',
94                              help='Add a bdev with malloc backend')
95    p.add_argument('-b', '--name', help="Name of the bdev")
96    p.add_argument('-u', '--uuid', help="UUID of the bdev")
97    p.add_argument(
98        'total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
99    p.add_argument('block_size', help='Block size for this bdev', type=int)
100    p.set_defaults(func=construct_malloc_bdev)
101
102    @call_cmd
103    def construct_null_bdev(args):
104        print_array(rpc.bdev.construct_null_bdev(args.client, args))
105
106    p = subparsers.add_parser('construct_null_bdev',
107                              help='Add a bdev with null backend')
108    p.add_argument('name', help='Block device name')
109    p.add_argument('-u', '--uuid', help='UUID of the bdev')
110    p.add_argument(
111        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
112    p.add_argument('block_size', help='Block size for this bdev', type=int)
113    p.set_defaults(func=construct_null_bdev)
114
115    @call_cmd
116    def construct_aio_bdev(args):
117        print_array(rpc.bdev.construct_aio_bdev(args.client, args))
118
119    p = subparsers.add_parser('construct_aio_bdev',
120                              help='Add a bdev with aio backend')
121    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
122    p.add_argument('name', help='Block device name')
123    p.add_argument('block_size', help='Block size for this bdev', type=int, default=argparse.SUPPRESS)
124    p.set_defaults(func=construct_aio_bdev)
125
126    @call_cmd
127    def construct_nvme_bdev(args):
128        print_array(rpc.bdev.construct_nvme_bdev(args.client, args))
129
130    p = subparsers.add_parser('construct_nvme_bdev',
131                              help='Add bdev with nvme backend')
132    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
133    p.add_argument('-t', '--trtype',
134                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
135    p.add_argument('-a', '--traddr',
136                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
137    p.add_argument('-f', '--adrfam',
138                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
139    p.add_argument('-s', '--trsvcid',
140                   help='NVMe-oF target trsvcid: e.g., a port number')
141    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
142    p.set_defaults(func=construct_nvme_bdev)
143
144    @call_cmd
145    def construct_rbd_bdev(args):
146        print_array(rpc.bdev.construct_rbd_bdev(args.client, args))
147
148    p = subparsers.add_parser('construct_rbd_bdev',
149                              help='Add a bdev with ceph rbd backend')
150    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
151    p.add_argument('pool_name', help='rbd pool name')
152    p.add_argument('rbd_name', help='rbd image name')
153    p.add_argument('block_size', help='rbd block size', type=int)
154    p.set_defaults(func=construct_rbd_bdev)
155
156    @call_cmd
157    def construct_error_bdev(args):
158        rpc.bdev.construct_error_bdev(args.client, args)
159
160    p = subparsers.add_parser('construct_error_bdev',
161                              help='Add bdev with error injection backend')
162    p.add_argument('base_name', help='base bdev name')
163    p.set_defaults(func=construct_error_bdev)
164
165    @call_cmd
166    def construct_pmem_bdev(args):
167        print_array(rpc.bdev.construct_pmem_bdev(args.client, args))
168
169    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
170    p.add_argument('pmem_file', help='Path to pmemblk pool file')
171    p.add_argument('-n', '--name', help='Block device name', required=True)
172    p.set_defaults(func=construct_pmem_bdev)
173
174    @call_cmd
175    def construct_passthru_bdev(args):
176        print_array(rpc.bdev.construct_passthru_bdev(args.client, args))
177
178    p = subparsers.add_parser('construct_passthru_bdev',
179                              help='Add a pass through bdev on existing bdev')
180    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
181    p.add_argument('-p', '--passthru-bdev-name', help="Name of the passthru bdev", required=True)
182    p.set_defaults(func=construct_passthru_bdev)
183
184    @call_cmd
185    def get_bdevs(args):
186        print_dict(rpc.bdev.get_bdevs(args.client, args))
187
188    p = subparsers.add_parser(
189        'get_bdevs', help='Display current blockdev list or required blockdev')
190    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
191    p.set_defaults(func=get_bdevs)
192
193    @call_cmd
194    def get_bdevs_config(args):
195        print_dict(rpc.bdev.get_bdevs_config(args.client, args))
196
197    p = subparsers.add_parser(
198        'get_bdevs_config', help='Display current (live) blockdev configuration list or required blockdev')
199    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
200    p.set_defaults(func=get_bdevs_config)
201
202    @call_cmd
203    def delete_bdev(args):
204        rpc.bdev.delete_bdev(args.client, args)
205
206    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
207    p.add_argument(
208        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
209    p.set_defaults(func=delete_bdev)
210
211    @call_cmd
212    def set_bdev_qos_limit_iops(args):
213        rpc.bdev.set_bdev_qos_limit_iops(args.client, args)
214
215    p = subparsers.add_parser('set_bdev_qos_limit_iops', help='Set QoS IOPS limit on a blockdev')
216    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
217    p.add_argument('ios_per_sec',
218                   help='IOs per second limit (>=10000, example: 20000). 0 means unlimited.', type=int)
219    p.set_defaults(func=set_bdev_qos_limit_iops)
220
221    @call_cmd
222    def bdev_inject_error(args):
223        rpc.bdev.bdev_inject_error(args.client, args)
224
225    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
226    p.add_argument('name', help="""the name of the error injection bdev""")
227    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
228    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
229    p.add_argument(
230        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
231    p.set_defaults(func=bdev_inject_error)
232
233    @call_cmd
234    def apply_firmware(args):
235        print_dict(rpc.bdev.apply_firmware(args.client, args))
236
237    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
238    p.add_argument('filename', help='filename of the firmware to download')
239    p.add_argument('bdev_name', help='name of the NVMe device')
240    p.set_defaults(func=apply_firmware)
241
242    # iSCSI
243    @call_cmd
244    def get_portal_groups(args):
245        print_dict(rpc.iscsi.get_portal_groups(args.client, args))
246
247    p = subparsers.add_parser(
248        'get_portal_groups', help='Display current portal group configuration')
249    p.set_defaults(func=get_portal_groups)
250
251    @call_cmd
252    def get_initiator_groups(args):
253        print_dict(rpc.iscsi.get_initiator_groups(args.client, args))
254
255    p = subparsers.add_parser('get_initiator_groups',
256                              help='Display current initiator group configuration')
257    p.set_defaults(func=get_initiator_groups)
258
259    @call_cmd
260    def get_target_nodes(args):
261        print_dict(rpc.iscsi.get_target_nodes(args.client, args))
262
263    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
264    p.set_defaults(func=get_target_nodes)
265
266    @call_cmd
267    def construct_target_node(args):
268        rpc.iscsi.construct_target_node(args.client, args)
269
270    p = subparsers.add_parser('construct_target_node',
271                              help='Add a target node')
272    p.add_argument('name', help='Target node name (ASCII)')
273    p.add_argument('alias_name', help='Target node alias name (ASCII)')
274    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
275    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
276    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
277    *** The bdevs must pre-exist ***
278    *** LUN0 (id = 0) is required ***
279    *** bdevs names cannot contain space or colon characters ***""")
280    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
281    Whitespace separated, quoted, mapping defined with colon
282    separated list of "tags" (int > 0)
283    Example: '1:1 2:2 2:1'
284    *** The Portal/Initiator Groups must be precreated ***""")
285    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
286    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
287    *** Authentication group must be precreated ***""", type=int, default=0)
288    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
289    *** Mutually exclusive with --require-chap ***""", action='store_true')
290    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
291    *** Mutually exclusive with --disable-chap ***""", action='store_true')
292    p.add_argument(
293        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
294    p.add_argument('-H', '--header-digest',
295                   help='Header Digest should be required for this target node.', action='store_true')
296    p.add_argument('-D', '--data-digest',
297                   help='Data Digest should be required for this target node.', action='store_true')
298    p.set_defaults(func=construct_target_node)
299
300    @call_cmd
301    def target_node_add_lun(args):
302        rpc.iscsi.target_node_add_lun(args.client, args)
303
304    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
305    p.add_argument('name', help='Target node name (ASCII)')
306    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
307    *** bdev name cannot contain space or colon characters ***""")
308    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
309    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
310    p.set_defaults(func=target_node_add_lun)
311
312    @call_cmd
313    def add_pg_ig_maps(args):
314        rpc.iscsi.add_pg_ig_maps(args.client, args)
315
316    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
317    p.add_argument('name', help='Target node name (ASCII)')
318    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
319    Whitespace separated, quoted, mapping defined with colon
320    separated list of "tags" (int > 0)
321    Example: '1:1 2:2 2:1'
322    *** The Portal/Initiator Groups must be precreated ***""")
323    p.set_defaults(func=add_pg_ig_maps)
324
325    @call_cmd
326    def delete_pg_ig_maps(args):
327        rpc.iscsi.delete_pg_ig_maps(args.client, args)
328
329    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
330    p.add_argument('name', help='Target node name (ASCII)')
331    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
332    Whitespace separated, quoted, mapping defined with colon
333    separated list of "tags" (int > 0)
334    Example: '1:1 2:2 2:1'
335    *** The Portal/Initiator Groups must be precreated ***""")
336    p.set_defaults(func=delete_pg_ig_maps)
337
338    @call_cmd
339    def add_portal_group(args):
340        rpc.iscsi.add_portal_group(args.client, args)
341
342    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
343    p.add_argument(
344        'tag', help='Portal group tag (unique, integer > 0)', type=int)
345    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
346    (cpumask is optional and can be skipped)
347    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
348    p.set_defaults(func=add_portal_group)
349
350    @call_cmd
351    def add_initiator_group(args):
352        rpc.iscsi.add_initiator_group(args.client, args)
353
354    p = subparsers.add_parser('add_initiator_group',
355                              help='Add an initiator group')
356    p.add_argument(
357        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
358    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
359    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
360    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
361    Example: '255.255.0.0 255.248.0.0' etc""")
362    p.set_defaults(func=add_initiator_group)
363
364    @call_cmd
365    def add_initiators_to_initiator_group(args):
366        rpc.iscsi.add_initiators_to_initiator_group(args.client, args)
367
368    p = subparsers.add_parser('add_initiators_to_initiator_group',
369                              help='Add initiators to an existing initiator group')
370    p.add_argument(
371        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
372    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
373    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
374    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
375    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
376    p.set_defaults(func=add_initiators_to_initiator_group)
377
378    @call_cmd
379    def delete_initiators_from_initiator_group(args):
380        rpc.iscsi.delete_initiators_from_initiator_group(args.client, args)
381
382    p = subparsers.add_parser('delete_initiators_from_initiator_group',
383                              help='Delete initiators from an existing initiator group')
384    p.add_argument(
385        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
386    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
387    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
388    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
389    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
390    p.set_defaults(func=delete_initiators_from_initiator_group)
391
392    @call_cmd
393    def delete_target_node(args):
394        rpc.iscsi.delete_target_node(args.client, args)
395
396    p = subparsers.add_parser('delete_target_node',
397                              help='Delete a target node')
398    p.add_argument('target_node_name',
399                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
400    p.set_defaults(func=delete_target_node)
401
402    @call_cmd
403    def delete_portal_group(args):
404        rpc.iscsi.delete_portal_group(args.client, args)
405
406    p = subparsers.add_parser('delete_portal_group',
407                              help='Delete a portal group')
408    p.add_argument(
409        'tag', help='Portal group tag (unique, integer > 0)', type=int)
410    p.set_defaults(func=delete_portal_group)
411
412    @call_cmd
413    def delete_initiator_group(args):
414        rpc.iscsi.delete_initiator_group(args.client, args)
415
416    p = subparsers.add_parser('delete_initiator_group',
417                              help='Delete an initiator group')
418    p.add_argument(
419        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
420    p.set_defaults(func=delete_initiator_group)
421
422    @call_cmd
423    def get_iscsi_connections(args):
424        print_dict(rpc.iscsi.get_iscsi_connections(args.client, args))
425
426    p = subparsers.add_parser('get_iscsi_connections',
427                              help='Display iSCSI connections')
428    p.set_defaults(func=get_iscsi_connections)
429
430    @call_cmd
431    def get_iscsi_global_params(args):
432        print_dict(rpc.iscsi.get_iscsi_global_params(args.client, args))
433
434    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
435    p.set_defaults(func=get_iscsi_global_params)
436
437    @call_cmd
438    def get_scsi_devices(args):
439        print_dict(rpc.iscsi.get_scsi_devices(args.client, args))
440
441    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
442    p.set_defaults(func=get_scsi_devices)
443
444    # log
445    @call_cmd
446    def set_trace_flag(args):
447        rpc.log.set_trace_flag(args.client, args)
448
449    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
450    p.add_argument(
451        'flag', help='trace mask we want to set. (for example "nvme").')
452    p.set_defaults(func=set_trace_flag)
453
454    @call_cmd
455    def clear_trace_flag(args):
456        rpc.log.clear_trace_flag(args.client, args)
457
458    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
459    p.add_argument(
460        'flag', help='trace mask we want to clear. (for example "nvme").')
461    p.set_defaults(func=clear_trace_flag)
462
463    @call_cmd
464    def get_trace_flags(args):
465        print_dict(rpc.log.get_trace_flags(args.client, args))
466
467    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
468    p.set_defaults(func=get_trace_flags)
469
470    @call_cmd
471    def set_log_level(args):
472        rpc.log.set_log_level(args.client, args)
473
474    p = subparsers.add_parser('set_log_level', help='set log level')
475    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
476    p.set_defaults(func=set_log_level)
477
478    @call_cmd
479    def get_log_level(args):
480        print_dict(rpc.log.get_log_level(args.client, args))
481
482    p = subparsers.add_parser('get_log_level', help='get log level')
483    p.set_defaults(func=get_log_level)
484
485    @call_cmd
486    def set_log_print_level(args):
487        rpc.log.set_log_print_level(args.client, args)
488
489    p = subparsers.add_parser('set_log_print_level', help='set log print level')
490    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
491    p.set_defaults(func=set_log_print_level)
492
493    @call_cmd
494    def get_log_print_level(args):
495        print_dict(rpc.log.get_log_print_level(args.client, args))
496
497    p = subparsers.add_parser('get_log_print_level', help='get log print level')
498    p.set_defaults(func=get_log_print_level)
499
500    # lvol
501    @call_cmd
502    def construct_lvol_store(args):
503        print_array(rpc.lvol.construct_lvol_store(args.client,
504                                                  bdev_name=args.bdev_name,
505                                                  lvs_name=args.lvs_name,
506                                                  cluster_sz=args.cluster_sz))
507
508    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
509    p.add_argument('bdev_name', help='base bdev name')
510    p.add_argument('lvs_name', help='name for lvol store')
511    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
512    p.set_defaults(func=construct_lvol_store)
513
514    @call_cmd
515    def rename_lvol_store(args):
516        rpc.lvol.rename_lvol_store(args.client,
517                                   old_name=args.old_name,
518                                   new_name=args.new_name)
519
520    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
521    p.add_argument('old_name', help='old name')
522    p.add_argument('new_name', help='new name')
523    p.set_defaults(func=rename_lvol_store)
524
525    @call_cmd
526    def construct_lvol_bdev(args):
527        print_array(rpc.lvol.construct_lvol_bdev(args.client,
528                                                 lvol_name=args.lvol_name,
529                                                 size=args.size * 1024 * 1024,
530                                                 thin_provision=args.thin_provision,
531                                                 uuid=args.uuid,
532                                                 lvs_name=args.lvs_name))
533
534    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
535    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
536    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
537    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
538    p.add_argument('lvol_name', help='name for this lvol')
539    p.add_argument('size', help='size in MiB for this bdev', type=int)
540    p.set_defaults(func=construct_lvol_bdev)
541
542    @call_cmd
543    def snapshot_lvol_bdev(args):
544        rpc.lvol.snapshot_lvol_bdev(args.client,
545                                    lvol_name=args.lvol_name,
546                                    snapshot_name=args.snapshot_name)
547
548    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
549    p.add_argument('lvol_name', help='lvol bdev name')
550    p.add_argument('snapshot_name', help='lvol snapshot name')
551    p.set_defaults(func=snapshot_lvol_bdev)
552
553    @call_cmd
554    def clone_lvol_bdev(args):
555        rpc.lvol.clone_lvol_bdev(args.client,
556                                 snapshot_name=args.snapshot_name,
557                                 clone_name=args.clone_name)
558
559    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
560    p.add_argument('snapshot_name', help='lvol snapshot name')
561    p.add_argument('clone_name', help='lvol clone name')
562    p.set_defaults(func=clone_lvol_bdev)
563
564    @call_cmd
565    def rename_lvol_bdev(args):
566        rpc.lvol.rename_lvol_bdev(args.client,
567                                  old_name=args.old_name,
568                                  new_name=args.new_name)
569
570    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
571    p.add_argument('old_name', help='lvol bdev name')
572    p.add_argument('new_name', help='new lvol name')
573    p.set_defaults(func=rename_lvol_bdev)
574
575    @call_cmd
576    def resize_lvol_bdev(args):
577        rpc.lvol.resize_lvol_bdev(args.client,
578                                  name=args.name,
579                                  size=args.size * 1024 * 1024)
580
581    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
582    p.add_argument('name', help='lvol bdev name')
583    p.add_argument('size', help='new size in MiB for this bdev', type=int)
584    p.set_defaults(func=resize_lvol_bdev)
585
586    @call_cmd
587    def destroy_lvol_bdev(args):
588        rpc.lvol.destroy_lvol_bdev(args.client,
589                                   name=args.name)
590
591    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
592    p.add_argument('name', help='lvol bdev name')
593    p.set_defaults(func=destroy_lvol_bdev)
594
595    @call_cmd
596    def destroy_lvol_store(args):
597        rpc.lvol.destroy_lvol_store(args.client,
598                                    uuid=args.uuid,
599                                    lvs_name=args.lvs_name)
600
601    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
602    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
603    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
604    p.set_defaults(func=destroy_lvol_store)
605
606    @call_cmd
607    def get_lvol_stores(args):
608        print_dict(rpc.lvol.get_lvol_stores(args.client,
609                                            uuid=args.uuid,
610                                            lvs_name=args.lvs_name))
611
612    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
613    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
614    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
615    p.set_defaults(func=get_lvol_stores)
616
617    # split
618    def construct_split_vbdev(args):
619        print_dict(rpc.bdev.construct_split_vbdev(args.client, args))
620
621    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
622    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
623    available (during examination process).""")
624    p.add_argument('base_bdev', help='base bdev name')
625    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
626    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
627    exceed the base bdev size.""", type=int)
628    p.set_defaults(func=construct_split_vbdev)
629
630    def destruct_split_vbdev(args):
631        rpc.destruct_split_vbdev(args.client, args)
632
633    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
634    p.add_argument('base_bdev', help='base bdev name')
635    p.set_defaults(func=destruct_split_vbdev)
636
637    # nbd
638    @call_cmd
639    def start_nbd_disk(args):
640        rpc.nbd.start_nbd_disk(args.client,
641                               bdev_name=args.bdev_name,
642                               nbd_device=args.nbd_device)
643
644    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
645    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
646    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
647    p.set_defaults(func=start_nbd_disk)
648
649    @call_cmd
650    def stop_nbd_disk(args):
651        rpc.nbd.stop_nbd_disk(args.client,
652                              nbd_device=args.nbd_device)
653
654    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
655    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
656    p.set_defaults(func=stop_nbd_disk)
657
658    @call_cmd
659    def get_nbd_disks(args):
660        print_dict(rpc.nbd.get_nbd_disks(args.client,
661                                         nbd_device=args.nbd_device))
662
663    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
664    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
665    p.set_defaults(func=get_nbd_disks)
666
667    # net
668    @call_cmd
669    def add_ip_address(args):
670        rpc.net.add_ip_address(args.client, args)
671
672    p = subparsers.add_parser('add_ip_address', help='Add IP address')
673    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
674    p.add_argument('ip_addr', help='ip address will be added.')
675    p.set_defaults(func=add_ip_address)
676
677    @call_cmd
678    def delete_ip_address(args):
679        rpc.net.delete_ip_address(args.client, args)
680
681    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
682    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
683    p.add_argument('ip_addr', help='ip address will be deleted.')
684    p.set_defaults(func=delete_ip_address)
685
686    @call_cmd
687    def get_interfaces(args):
688        print_dict(rpc.net.get_interfaces(args.client, args))
689
690    p = subparsers.add_parser(
691        'get_interfaces', help='Display current interface list')
692    p.set_defaults(func=get_interfaces)
693
694    # NVMe-oF
695    @call_cmd
696    def get_nvmf_subsystems(args):
697        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client, args))
698
699    p = subparsers.add_parser('get_nvmf_subsystems',
700                              help='Display nvmf subsystems')
701    p.set_defaults(func=get_nvmf_subsystems)
702
703    @call_cmd
704    def construct_nvmf_subsystem(args):
705        rpc.nvmf.construct_nvmf_subsystem(args.client, args)
706
707    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
708    p.add_argument('nqn', help='Target nqn(ASCII)')
709    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
710    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
711    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
712    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
713    Format:  'nqn1 nqn2' etc
714    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
715    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
716    p.add_argument("-s", "--serial-number", help="""
717    Format:  'sn' etc
718    Example: 'SPDK00000000000001'""", default='0000:00:01.0')
719    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
720    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
721    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
722    *** The devices must pre-exist ***""")
723    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
724                   type=int, default=0)
725    p.set_defaults(func=construct_nvmf_subsystem)
726
727    @call_cmd
728    def delete_nvmf_subsystem(args):
729        rpc.nvmf.delete_nvmf_subsystem(args.client, args)
730
731    p = subparsers.add_parser('delete_nvmf_subsystem',
732                              help='Delete a nvmf subsystem')
733    p.add_argument('subsystem_nqn',
734                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
735    p.set_defaults(func=delete_nvmf_subsystem)
736
737    @call_cmd
738    def nvmf_subsystem_add_listener(args):
739        rpc.nvmf.nvmf_subsystem_add_listener(args.client, args)
740
741    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
742    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
743    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
744    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
745    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
746    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
747    p.set_defaults(func=nvmf_subsystem_add_listener)
748
749    @call_cmd
750    def nvmf_subsystem_remove_listener(args):
751        rpc.nvmf.nvmf_subsystem_remove_listener(args.client, args)
752
753    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
754    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
755    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
756    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
757    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
758    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
759    p.set_defaults(func=nvmf_subsystem_remove_listener)
760
761    @call_cmd
762    def nvmf_subsystem_add_ns(args):
763        rpc.nvmf.nvmf_subsystem_add_ns(args.client, args)
764
765    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
766    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
767    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
768    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
769    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
770    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
771    p.set_defaults(func=nvmf_subsystem_add_ns)
772
773    @call_cmd
774    def nvmf_subsystem_remove_ns(args):
775        rpc.nvmf.nvmf_subsystem_remove_ns(args.client, args)
776
777    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
778    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
779    p.add_argument('nsid', help='The requested NSID', type=int)
780    p.set_defaults(func=nvmf_subsystem_remove_ns)
781
782    @call_cmd
783    def nvmf_subsystem_add_host(args):
784        rpc.nvmf.nvmf_subsystem_add_host(args.client, args)
785
786    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
787    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
788    p.add_argument('host', help='Host NQN to allow')
789    p.set_defaults(func=nvmf_subsystem_add_host)
790
791    @call_cmd
792    def nvmf_subsystem_remove_host(args):
793        rpc.nvmf.nvmf_subsystem_remove_host(args.client, args)
794
795    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
796    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
797    p.add_argument('host', help='Host NQN to remove')
798    p.set_defaults(func=nvmf_subsystem_remove_host)
799
800    @call_cmd
801    def nvmf_subsystem_allow_any_host(args):
802        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client, args)
803
804    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
805    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
806    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
807    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
808    p.set_defaults(func=nvmf_subsystem_allow_any_host)
809
810    # pmem
811    @call_cmd
812    def create_pmem_pool(args):
813        rpc.pmem.create_pmem_pool(args.client, args)
814
815    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
816    p.add_argument('pmem_file', help='Path to pmemblk pool file')
817    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
818    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
819    p.set_defaults(func=create_pmem_pool)
820
821    @call_cmd
822    def pmem_pool_info(args):
823        print_dict(rpc.pmem.pmem_pool_info(args.client, args))
824
825    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
826    p.add_argument('pmem_file', help='Path to pmemblk pool file')
827    p.set_defaults(func=pmem_pool_info)
828
829    @call_cmd
830    def delete_pmem_pool(args):
831        rpc.pmem.delete_pmem_pool(args.client, args)
832
833    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
834    p.add_argument('pmem_file', help='Path to pmemblk pool file')
835    p.set_defaults(func=delete_pmem_pool)
836
837    # subsystem
838    @call_cmd
839    def get_subsystems(args):
840        print_dict(rpc.subsystem.get_subsystems(args.client))
841
842    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
843    entry contain (unsorted) array of subsystems it depends on.""")
844    p.set_defaults(func=get_subsystems)
845
846    @call_cmd
847    def get_subsystem_config(args):
848        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
849
850    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
851    p.add_argument('name', help='Name of subsystem to query')
852    p.set_defaults(func=get_subsystem_config)
853
854    # vhost
855    @call_cmd
856    def set_vhost_controller_coalescing(args):
857        rpc.vhost.set_vhost_controller_coalescing(args.client, args)
858
859    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
860    p.add_argument('ctrlr', help='controller name')
861    p.add_argument('delay_base_us', help='Base delay time', type=int)
862    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
863    p.set_defaults(func=set_vhost_controller_coalescing)
864
865    @call_cmd
866    def construct_vhost_scsi_controller(args):
867        rpc.vhost.construct_vhost_scsi_controller(args.client, args)
868
869    p = subparsers.add_parser(
870        'construct_vhost_scsi_controller', help='Add new vhost controller')
871    p.add_argument('ctrlr', help='controller name')
872    p.add_argument('--cpumask', help='cpu mask for this controller')
873    p.set_defaults(func=construct_vhost_scsi_controller)
874
875    @call_cmd
876    def add_vhost_scsi_lun(args):
877        rpc.vhost.add_vhost_scsi_lun(args.client, args)
878
879    p = subparsers.add_parser('add_vhost_scsi_lun',
880                              help='Add lun to vhost controller')
881    p.add_argument('ctrlr', help='conntroller name where add lun')
882    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
883    p.add_argument('bdev_name', help='bdev name')
884    p.set_defaults(func=add_vhost_scsi_lun)
885
886    @call_cmd
887    def remove_vhost_scsi_target(args):
888        rpc.vhost.remove_vhost_scsi_target(args.client, args)
889
890    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
891    p.add_argument('ctrlr', help='controller name to remove target from')
892    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
893    p.set_defaults(func=remove_vhost_scsi_target)
894
895    @call_cmd
896    def construct_vhost_blk_controller(args):
897        rpc.vhost.construct_vhost_blk_controller(args.client, args)
898
899    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
900    p.add_argument('ctrlr', help='controller name')
901    p.add_argument('dev_name', help='device name')
902    p.add_argument('--cpumask', help='cpu mask for this controller')
903    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
904    p.set_defaults(func=construct_vhost_blk_controller)
905
906    @call_cmd
907    def construct_vhost_nvme_controller(args):
908        rpc.vhost.construct_vhost_nvme_controller(args.client, args)
909
910    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
911    p.add_argument('ctrlr', help='controller name')
912    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
913    p.add_argument('--cpumask', help='cpu mask for this controller')
914    p.set_defaults(func=construct_vhost_nvme_controller)
915
916    @call_cmd
917    def add_vhost_nvme_ns(args):
918        rpc.vhost.add_vhost_nvme_ns(args.client, args)
919
920    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
921    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
922    p.add_argument('bdev_name', help='block device name for a new Namespace')
923    p.set_defaults(func=add_vhost_nvme_ns)
924
925    @call_cmd
926    def get_vhost_controllers(args):
927        print_dict(rpc.vhost.get_vhost_controllers(args.client, args))
928
929    p = subparsers.add_parser('get_vhost_controllers', help='List vhost controllers')
930    p.set_defaults(func=get_vhost_controllers)
931
932    @call_cmd
933    def remove_vhost_controller(args):
934        rpc.vhost.remove_vhost_controller(args.client, args)
935
936    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
937    p.add_argument('ctrlr', help='controller name')
938    p.set_defaults(func=remove_vhost_controller)
939
940    @call_cmd
941    def construct_virtio_dev(args):
942        print_dict(rpc.vhost.construct_virtio_dev(args.client, args))
943
944    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
945    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
946    remote side. Result is array of added bdevs.""")
947    p.add_argument('name', help="Use this name as base for new created bdevs")
948    p.add_argument('-t', '--trtype',
949                   help='Virtio target transport type: pci or user', required=True)
950    p.add_argument('-a', '--traddr',
951                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
952    p.add_argument('-d', '--dev-type',
953                   help='Device type: blk or scsi', required=True)
954    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
955    p.add_argument('--vq-size', help='Size of each queue', type=int)
956    p.set_defaults(func=construct_virtio_dev)
957
958    @call_cmd
959    def construct_virtio_user_scsi_bdev(args):
960        print_dict(rpc.vhost.construct_virtio_user_scsi_bdev(args.client, args))
961
962    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
963    This imply scan and add bdevs offered by remote side.
964    Result is array of added bdevs.""")
965    p.add_argument('path', help='Path to Virtio SCSI socket')
966    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
967    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
968    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
969    p.add_argument('--vq-size', help='Size of each queue', type=int)
970    p.set_defaults(func=construct_virtio_user_scsi_bdev)
971
972    @call_cmd
973    def construct_virtio_pci_scsi_bdev(args):
974        print_dict(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client, args))
975
976    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
977    SCSI device from a virtio-pci device.""")
978    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
979    domain.bus.device.function format""")
980    p.add_argument('name', help="""Name for the virtio device.
981    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
982    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
983
984    @call_cmd
985    def get_virtio_scsi_devs(args):
986        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client, args))
987
988    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
989    p.set_defaults(func=get_virtio_scsi_devs)
990
991    @call_cmd
992    def remove_virtio_scsi_bdev(args):
993        rpc.vhost.remove_virtio_scsi_bdev(args.client, args)
994
995    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
996    This will delete all bdevs exposed by this device""")
997    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
998    p.set_defaults(func=remove_virtio_scsi_bdev)
999
1000    @call_cmd
1001    def construct_virtio_user_blk_bdev(args):
1002        print_dict(rpc.vhost.construct_virtio_user_blk_bdev(args.client, args))
1003
1004    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1005    p.add_argument('path', help='Path to Virtio BLK socket')
1006    p.add_argument('name', help='Name for the bdev')
1007    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1008    p.add_argument('--vq-size', help='Size of each queue', type=int)
1009    p.set_defaults(func=construct_virtio_user_blk_bdev)
1010
1011    @call_cmd
1012    def construct_virtio_pci_blk_bdev(args):
1013        print_dict(rpc.vhost.construct_virtio_pci_blk_bdev(args.client, args))
1014
1015    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1016    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1017    domain.bus.device.function format""")
1018    p.add_argument('name', help='Name for the bdev')
1019    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1020
1021    args = parser.parse_args()
1022
1023    try:
1024        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1025    except JSONRPCException as ex:
1026        print(ex.message)
1027        exit(1)
1028    args.func(args)
1029