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