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