xref: /spdk/scripts/rpc.py (revision 73204fe2e526f20c3fe7ea2066c0a4ed9dc60272)
1#!/usr/bin/env python3
2
3from rpc.client import print_dict, JSONRPCException
4from rpc.helpers import deprecated_aliases
5
6import logging
7import argparse
8import rpc
9import sys
10import shlex
11
12try:
13    from shlex import quote
14except ImportError:
15    from pipes import quote
16
17
18def print_array(a):
19    print(" ".join((quote(v) for v in a)))
20
21
22if __name__ == "__main__":
23    parser = argparse.ArgumentParser(
24        description='SPDK RPC command line interface')
25    parser.add_argument('-s', dest='server_addr',
26                        help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock')
27    parser.add_argument('-p', dest='port',
28                        help='RPC port number (if server_addr is IP address)',
29                        default=5260, type=int)
30    parser.add_argument('-t', dest='timeout',
31                        help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0',
32                        default=60.0, type=float)
33    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
34                        help='Set verbose mode to INFO', default="ERROR")
35    parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'],
36                        help="""Set verbose level. """)
37    subparsers = parser.add_subparsers(help='RPC methods', dest='called_rpc_name')
38
39    def start_subsystem_init(args):
40        rpc.start_subsystem_init(args.client)
41
42    p = subparsers.add_parser('start_subsystem_init', help='Start initialization of subsystems')
43    p.set_defaults(func=start_subsystem_init)
44
45    def wait_subsystem_init(args):
46        rpc.wait_subsystem_init(args.client)
47
48    p = subparsers.add_parser('wait_subsystem_init', help='Block until subsystems have been initialized')
49    p.set_defaults(func=wait_subsystem_init)
50
51    def rpc_get_methods(args):
52        print_dict(rpc.rpc_get_methods(args.client,
53                                       current=args.current))
54
55    p = subparsers.add_parser('rpc_get_methods', help='Get list of supported RPC methods', aliases=['get_rpc_methods'])
56    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
57    p.set_defaults(func=rpc_get_methods)
58
59    def get_spdk_version(args):
60        print(rpc.get_spdk_version(args.client))
61
62    p = subparsers.add_parser('get_spdk_version', help='Get SPDK version')
63    p.set_defaults(func=get_spdk_version)
64
65    def save_config(args):
66        rpc.save_config(args.client,
67                        sys.stdout,
68                        indent=args.indent)
69
70    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
71    """)
72    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
73    """, type=int, default=2)
74    p.set_defaults(func=save_config)
75
76    def load_config(args):
77        rpc.load_config(args.client, sys.stdin)
78
79    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""")
80    p.set_defaults(func=load_config)
81
82    def save_subsystem_config(args):
83        rpc.save_subsystem_config(args.client,
84                                  sys.stdout,
85                                  indent=args.indent,
86                                  name=args.name)
87
88    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
89    """)
90    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
91    """, type=int, default=2)
92    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
93    p.set_defaults(func=save_subsystem_config)
94
95    def load_subsystem_config(args):
96        rpc.load_subsystem_config(args.client,
97                                  sys.stdin)
98
99    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""")
100    p.set_defaults(func=load_subsystem_config)
101
102    # app
103    def kill_instance(args):
104        rpc.app.kill_instance(args.client,
105                              sig_name=args.sig_name)
106
107    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
108    p.add_argument('sig_name', help='signal will be sent to server.')
109    p.set_defaults(func=kill_instance)
110
111    def context_switch_monitor(args):
112        enabled = None
113        if args.enable:
114            enabled = True
115        if args.disable:
116            enabled = False
117        print_dict(rpc.app.context_switch_monitor(args.client,
118                                                  enabled=enabled))
119
120    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
121    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
122    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
123    p.set_defaults(func=context_switch_monitor)
124
125    # bdev
126    def set_bdev_options(args):
127        rpc.bdev.set_bdev_options(args.client,
128                                  bdev_io_pool_size=args.bdev_io_pool_size,
129                                  bdev_io_cache_size=args.bdev_io_cache_size)
130
131    p = subparsers.add_parser('set_bdev_options', help="""Set options of bdev subsystem""")
132    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
133    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
134    p.set_defaults(func=set_bdev_options)
135
136    def construct_compress_bdev(args):
137        print(rpc.bdev.construct_compress_bdev(args.client,
138                                               base_bdev_name=args.base_bdev_name,
139                                               pm_path=args.pm_path,
140                                               comp_pmd=args.comp_pmd))
141    p = subparsers.add_parser('construct_compress_bdev',
142                              help='Add a compress vbdev')
143    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
144    p.add_argument('-p', '--pm_path', help="Path to persistent memory")
145    p.add_argument('-d', '--comp_pmd', help="Name of the compression device driver")
146    p.set_defaults(func=construct_compress_bdev)
147
148    def delete_compress_bdev(args):
149        rpc.bdev.delete_compress_bdev(args.client,
150                                      name=args.name)
151
152    p = subparsers.add_parser('delete_compress_bdev', help='Delete a compress disk')
153    p.add_argument('name', help='compress bdev name')
154    p.set_defaults(func=delete_compress_bdev)
155
156    def construct_crypto_bdev(args):
157        print(rpc.bdev.construct_crypto_bdev(args.client,
158                                             base_bdev_name=args.base_bdev_name,
159                                             name=args.name,
160                                             crypto_pmd=args.crypto_pmd,
161                                             key=args.key))
162    p = subparsers.add_parser('construct_crypto_bdev',
163                              help='Add a crypto vbdev')
164    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
165    p.add_argument('-c', '--name', help="Name of the crypto vbdev")
166    p.add_argument('-d', '--crypto_pmd', help="Name of the crypto device driver")
167    p.add_argument('-k', '--key', help="Key")
168    p.set_defaults(func=construct_crypto_bdev)
169
170    def delete_crypto_bdev(args):
171        rpc.bdev.delete_crypto_bdev(args.client,
172                                    name=args.name)
173
174    p = subparsers.add_parser('delete_crypto_bdev', help='Delete a crypto disk')
175    p.add_argument('name', help='crypto bdev name')
176    p.set_defaults(func=delete_crypto_bdev)
177
178    def construct_ocf_bdev(args):
179        print(rpc.bdev.construct_ocf_bdev(args.client,
180                                          name=args.name,
181                                          mode=args.mode,
182                                          cache_bdev_name=args.cache_bdev_name,
183                                          core_bdev_name=args.core_bdev_name))
184    p = subparsers.add_parser('construct_ocf_bdev',
185                              help='Add an OCF block device')
186    p.add_argument('name', help='Name of resulting OCF bdev')
187    p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt'])
188    p.add_argument('cache_bdev_name', help='Name of underlying cache bdev')
189    p.add_argument('core_bdev_name', help='Name of unerlying core bdev')
190    p.set_defaults(func=construct_ocf_bdev)
191
192    def delete_ocf_bdev(args):
193        rpc.bdev.delete_ocf_bdev(args.client,
194                                 name=args.name)
195
196    p = subparsers.add_parser('delete_ocf_bdev',
197                              help='Delete an OCF block device')
198    p.add_argument('name', help='Name of OCF bdev')
199    p.set_defaults(func=delete_ocf_bdev)
200
201    def get_ocf_stats(args):
202        print_dict(rpc.bdev.get_ocf_stats(args.client,
203                                          name=args.name))
204    p = subparsers.add_parser('get_ocf_stats',
205                              help='Get statistics of chosen OCF block device')
206    p.add_argument('name', help='Name of OCF bdev')
207    p.set_defaults(func=get_ocf_stats)
208
209    def get_ocf_bdevs(args):
210        print_dict(rpc.bdev.get_ocf_bdevs(args.client,
211                                          name=args.name))
212    p = subparsers.add_parser('get_ocf_bdevs',
213                              help='Get list of OCF devices including unregistered ones')
214    p.add_argument('name', nargs='?', default=None, help='name of OCF vbdev or name of cache device or name of core device (optional)')
215    p.set_defaults(func=get_ocf_bdevs)
216
217    def construct_malloc_bdev(args):
218        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
219        print(rpc.bdev.construct_malloc_bdev(args.client,
220                                             num_blocks=int(num_blocks),
221                                             block_size=args.block_size,
222                                             name=args.name,
223                                             uuid=args.uuid))
224    p = subparsers.add_parser('construct_malloc_bdev',
225                              help='Add a bdev with malloc backend')
226    p.add_argument('-b', '--name', help="Name of the bdev")
227    p.add_argument('-u', '--uuid', help="UUID of the bdev")
228    p.add_argument(
229        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
230    p.add_argument('block_size', help='Block size for this bdev', type=int)
231    p.set_defaults(func=construct_malloc_bdev)
232
233    def delete_malloc_bdev(args):
234        rpc.bdev.delete_malloc_bdev(args.client,
235                                    name=args.name)
236
237    p = subparsers.add_parser('delete_malloc_bdev', help='Delete a malloc disk')
238    p.add_argument('name', help='malloc bdev name')
239    p.set_defaults(func=delete_malloc_bdev)
240
241    def construct_null_bdev(args):
242        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
243        print(rpc.bdev.construct_null_bdev(args.client,
244                                           num_blocks=num_blocks,
245                                           block_size=args.block_size,
246                                           name=args.name,
247                                           uuid=args.uuid))
248
249    p = subparsers.add_parser('construct_null_bdev',
250                              help='Add a bdev with null backend')
251    p.add_argument('name', help='Block device name')
252    p.add_argument('-u', '--uuid', help='UUID of the bdev')
253    p.add_argument(
254        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
255    p.add_argument('block_size', help='Block size for this bdev', type=int)
256    p.set_defaults(func=construct_null_bdev)
257
258    def delete_null_bdev(args):
259        rpc.bdev.delete_null_bdev(args.client,
260                                  name=args.name)
261
262    p = subparsers.add_parser('delete_null_bdev', help='Delete a null bdev')
263    p.add_argument('name', help='null bdev name')
264    p.set_defaults(func=delete_null_bdev)
265
266    def construct_aio_bdev(args):
267        print(rpc.bdev.construct_aio_bdev(args.client,
268                                          filename=args.filename,
269                                          name=args.name,
270                                          block_size=args.block_size))
271
272    p = subparsers.add_parser('construct_aio_bdev',
273                              help='Add a bdev with aio backend')
274    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
275    p.add_argument('name', help='Block device name')
276    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
277    p.set_defaults(func=construct_aio_bdev)
278
279    def delete_aio_bdev(args):
280        rpc.bdev.delete_aio_bdev(args.client,
281                                 name=args.name)
282
283    p = subparsers.add_parser('delete_aio_bdev', help='Delete an aio disk')
284    p.add_argument('name', help='aio bdev name')
285    p.set_defaults(func=delete_aio_bdev)
286
287    def set_bdev_nvme_options(args):
288        rpc.bdev.set_bdev_nvme_options(args.client,
289                                       action_on_timeout=args.action_on_timeout,
290                                       timeout_us=args.timeout_us,
291                                       retry_count=args.retry_count,
292                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us,
293                                       nvme_ioq_poll_period_us=args.nvme_ioq_poll_period_us)
294
295    p = subparsers.add_parser('set_bdev_nvme_options',
296                              help='Set options for the bdev nvme type. This is startup command.')
297    p.add_argument('-a', '--action-on-timeout',
298                   help="Action to take on command time out. Valid valies are: none, reset, abort")
299    p.add_argument('-t', '--timeout-us',
300                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
301    p.add_argument('-n', '--retry-count',
302                   help='the number of attempts per I/O when an I/O fails', type=int)
303    p.add_argument('-p', '--nvme-adminq-poll-period-us',
304                   help='How often the admin queue is polled for asynchronous events', type=int)
305    p.add_argument('-i', '--nvme-ioq-poll-period-us',
306                   help='How often to poll I/O queues for completions', type=int)
307    p.set_defaults(func=set_bdev_nvme_options)
308
309    def set_bdev_nvme_hotplug(args):
310        rpc.bdev.set_bdev_nvme_hotplug(args.client, enable=args.enable, period_us=args.period_us)
311
312    p = subparsers.add_parser('set_bdev_nvme_hotplug',
313                              help='Set hotplug options for bdev nvme type.')
314    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
315    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
316    p.add_argument('-r', '--period-us',
317                   help='How often the hotplug is processed for insert and remove events', type=int)
318    p.set_defaults(func=set_bdev_nvme_hotplug)
319
320    def construct_nvme_bdev(args):
321        print_array(rpc.bdev.construct_nvme_bdev(args.client,
322                                                 name=args.name,
323                                                 trtype=args.trtype,
324                                                 traddr=args.traddr,
325                                                 adrfam=args.adrfam,
326                                                 trsvcid=args.trsvcid,
327                                                 subnqn=args.subnqn,
328                                                 hostnqn=args.hostnqn,
329                                                 hostaddr=args.hostaddr,
330                                                 hostsvcid=args.hostsvcid,
331                                                 prchk_reftag=args.prchk_reftag,
332                                                 prchk_guard=args.prchk_guard))
333
334    p = subparsers.add_parser('construct_nvme_bdev',
335                              help='Add bdevs with nvme backend')
336    p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
337    p.add_argument('-t', '--trtype',
338                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
339    p.add_argument('-a', '--traddr',
340                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
341    p.add_argument('-f', '--adrfam',
342                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
343    p.add_argument('-s', '--trsvcid',
344                   help='NVMe-oF target trsvcid: e.g., a port number')
345    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
346    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
347    p.add_argument('-i', '--hostaddr',
348                   help='NVMe-oF host address: e.g., an ip address')
349    p.add_argument('-c', '--hostsvcid',
350                   help='NVMe-oF host svcid: e.g., a port number')
351    p.add_argument('-r', '--prchk-reftag',
352                   help='Enable checking of PI reference tag for I/O processing.', action='store_true')
353    p.add_argument('-g', '--prchk-guard',
354                   help='Enable checking of PI guard for I/O processing.', action='store_true')
355    p.set_defaults(func=construct_nvme_bdev)
356
357    def get_nvme_controllers(args):
358        print_dict(rpc.nvme.get_nvme_controllers(args.client,
359                                                 name=args.name))
360
361    p = subparsers.add_parser(
362        'get_nvme_controllers', help='Display current NVMe controllers list or required NVMe controller')
363    p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False)
364    p.set_defaults(func=get_nvme_controllers)
365
366    def delete_nvme_controller(args):
367        rpc.bdev.delete_nvme_controller(args.client,
368                                        name=args.name)
369
370    p = subparsers.add_parser('delete_nvme_controller',
371                              help='Delete a NVMe controller using controller name')
372    p.add_argument('name', help="Name of the controller")
373    p.set_defaults(func=delete_nvme_controller)
374
375    def construct_rbd_bdev(args):
376        config = None
377        if args.config:
378            config = {}
379            for entry in args.config:
380                parts = entry.split('=', 1)
381                if len(parts) != 2:
382                    raise Exception('--config %s not in key=value form' % entry)
383                config[parts[0]] = parts[1]
384        print(rpc.bdev.construct_rbd_bdev(args.client,
385                                          name=args.name,
386                                          user=args.user,
387                                          config=config,
388                                          pool_name=args.pool_name,
389                                          rbd_name=args.rbd_name,
390                                          block_size=args.block_size))
391
392    p = subparsers.add_parser('construct_rbd_bdev',
393                              help='Add a bdev with ceph rbd backend')
394    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
395    p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False)
396    p.add_argument('--config', action='append', metavar='key=value',
397                   help="adds a key=value configuration option for rados_conf_set (default: rely on config file)")
398    p.add_argument('pool_name', help='rbd pool name')
399    p.add_argument('rbd_name', help='rbd image name')
400    p.add_argument('block_size', help='rbd block size', type=int)
401    p.set_defaults(func=construct_rbd_bdev)
402
403    def delete_rbd_bdev(args):
404        rpc.bdev.delete_rbd_bdev(args.client,
405                                 name=args.name)
406
407    p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev')
408    p.add_argument('name', help='rbd bdev name')
409    p.set_defaults(func=delete_rbd_bdev)
410
411    def bdev_delay_create(args):
412        print(rpc.bdev.bdev_delay_create(args.client,
413                                         base_bdev_name=args.base_bdev_name,
414                                         name=args.name,
415                                         avg_read_latency=args.avg_read_latency,
416                                         p99_read_latency=args.nine_nine_read_latency,
417                                         avg_write_latency=args.avg_write_latency,
418                                         p99_write_latency=args.nine_nine_write_latency))
419
420    p = subparsers.add_parser('bdev_delay_create',
421                              help='Add a delay bdev on existing bdev')
422    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
423    p.add_argument('-d', '--name', help="Name of the delay bdev", required=True)
424    p.add_argument('-r', '--avg-read-latency', help="Average latency to apply before completing read ops", required=True, type=int)
425    p.add_argument('-t', '--nine-nine-read-latency', help="latency to apply to 1 in 100 read ops", required=True, type=int)
426    p.add_argument('-w', '--avg-write-latency', help="Average latency to apply before completing write ops", required=True, type=int)
427    p.add_argument('-n', '--nine-nine-write-latency', help="latency to apply to 1 in 100 write ops", required=True, type=int)
428    p.set_defaults(func=bdev_delay_create)
429
430    def bdev_delay_delete(args):
431        rpc.bdev.bdev_delay_delete(args.client,
432                                   name=args.name)
433
434    p = subparsers.add_parser('bdev_delay_delete', help='Delete a delay bdev')
435    p.add_argument('name', help='delay bdev name')
436    p.set_defaults(func=bdev_delay_delete)
437
438    def construct_error_bdev(args):
439        print(rpc.bdev.construct_error_bdev(args.client,
440                                            base_name=args.base_name))
441
442    p = subparsers.add_parser('construct_error_bdev',
443                              help='Add bdev with error injection backend')
444    p.add_argument('base_name', help='base bdev name')
445    p.set_defaults(func=construct_error_bdev)
446
447    def delete_error_bdev(args):
448        rpc.bdev.delete_error_bdev(args.client,
449                                   name=args.name)
450
451    p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev')
452    p.add_argument('name', help='error bdev name')
453    p.set_defaults(func=delete_error_bdev)
454
455    def construct_iscsi_bdev(args):
456        print(rpc.bdev.construct_iscsi_bdev(args.client,
457                                            name=args.name,
458                                            url=args.url,
459                                            initiator_iqn=args.initiator_iqn))
460
461    p = subparsers.add_parser('construct_iscsi_bdev',
462                              help='Add bdev with iSCSI initiator backend')
463    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
464    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
465    p.add_argument('--url', help="iSCSI Lun URL", required=True)
466    p.set_defaults(func=construct_iscsi_bdev)
467
468    def delete_iscsi_bdev(args):
469        rpc.bdev.delete_iscsi_bdev(args.client,
470                                   name=args.name)
471
472    p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev')
473    p.add_argument('name', help='iSCSI bdev name')
474    p.set_defaults(func=delete_iscsi_bdev)
475
476    def construct_pmem_bdev(args):
477        print(rpc.bdev.construct_pmem_bdev(args.client,
478                                           pmem_file=args.pmem_file,
479                                           name=args.name))
480
481    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
482    p.add_argument('pmem_file', help='Path to pmemblk pool file')
483    p.add_argument('-n', '--name', help='Block device name', required=True)
484    p.set_defaults(func=construct_pmem_bdev)
485
486    def delete_pmem_bdev(args):
487        rpc.bdev.delete_pmem_bdev(args.client,
488                                  name=args.name)
489
490    p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev')
491    p.add_argument('name', help='pmem bdev name')
492    p.set_defaults(func=delete_pmem_bdev)
493
494    def construct_passthru_bdev(args):
495        print(rpc.bdev.construct_passthru_bdev(args.client,
496                                               base_bdev_name=args.base_bdev_name,
497                                               name=args.name))
498
499    p = subparsers.add_parser('construct_passthru_bdev',
500                              help='Add a pass through bdev on existing bdev')
501    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
502    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
503    p.set_defaults(func=construct_passthru_bdev)
504
505    def delete_passthru_bdev(args):
506        rpc.bdev.delete_passthru_bdev(args.client,
507                                      name=args.name)
508
509    p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev')
510    p.add_argument('name', help='pass through bdev name')
511    p.set_defaults(func=delete_passthru_bdev)
512
513    def get_bdevs(args):
514        print_dict(rpc.bdev.get_bdevs(args.client,
515                                      name=args.name))
516
517    p = subparsers.add_parser(
518        'get_bdevs', help='Display current blockdev list or required blockdev')
519    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
520    p.set_defaults(func=get_bdevs)
521
522    def get_bdevs_iostat(args):
523        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
524                                             name=args.name))
525
526    p = subparsers.add_parser(
527        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
528    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
529    p.set_defaults(func=get_bdevs_iostat)
530
531    def enable_bdev_histogram(args):
532        rpc.bdev.enable_bdev_histogram(args.client, name=args.name, enable=args.enable)
533
534    p = subparsers.add_parser('enable_bdev_histogram', help='Enable or disable histogram for specified bdev')
535    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
536    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
537    p.add_argument('name', help='bdev name')
538    p.set_defaults(func=enable_bdev_histogram)
539
540    def get_bdev_histogram(args):
541        print_dict(rpc.bdev.get_bdev_histogram(args.client, name=args.name))
542
543    p = subparsers.add_parser('get_bdev_histogram', help='Get histogram for specified bdev')
544    p.add_argument('name', help='bdev name')
545    p.set_defaults(func=get_bdev_histogram)
546
547    def set_bdev_qd_sampling_period(args):
548        rpc.bdev.set_bdev_qd_sampling_period(args.client,
549                                             name=args.name,
550                                             period=args.period)
551
552    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
553    p.add_argument('name', help='Blockdev name. Example: Malloc0')
554    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
555                   ' If set to 0, polling will be disabled.',
556                   type=int)
557    p.set_defaults(func=set_bdev_qd_sampling_period)
558
559    def set_bdev_qos_limit(args):
560        rpc.bdev.set_bdev_qos_limit(args.client,
561                                    name=args.name,
562                                    rw_ios_per_sec=args.rw_ios_per_sec,
563                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
564                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
565                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
566
567    p = subparsers.add_parser('set_bdev_qos_limit', help='Set QoS rate limit on a blockdev')
568    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
569    p.add_argument('--rw_ios_per_sec',
570                   help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.',
571                   type=int, required=False)
572    p.add_argument('--rw_mbytes_per_sec',
573                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
574                   type=int, required=False)
575    p.add_argument('--r_mbytes_per_sec',
576                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
577                   type=int, required=False)
578    p.add_argument('--w_mbytes_per_sec',
579                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
580                   type=int, required=False)
581    p.set_defaults(func=set_bdev_qos_limit)
582
583    def bdev_inject_error(args):
584        rpc.bdev.bdev_inject_error(args.client,
585                                   name=args.name,
586                                   io_type=args.io_type,
587                                   error_type=args.error_type,
588                                   num=args.num)
589
590    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
591    p.add_argument('name', help="""the name of the error injection bdev""")
592    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
593    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
594    p.add_argument(
595        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
596    p.set_defaults(func=bdev_inject_error)
597
598    def apply_firmware(args):
599        print_dict(rpc.bdev.apply_firmware(args.client,
600                                           bdev_name=args.bdev_name,
601                                           filename=args.filename))
602
603    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
604    p.add_argument('filename', help='filename of the firmware to download')
605    p.add_argument('bdev_name', help='name of the NVMe device')
606    p.set_defaults(func=apply_firmware)
607
608    # iSCSI
609    def set_iscsi_options(args):
610        rpc.iscsi.set_iscsi_options(
611            args.client,
612            auth_file=args.auth_file,
613            node_base=args.node_base,
614            nop_timeout=args.nop_timeout,
615            nop_in_interval=args.nop_in_interval,
616            disable_chap=args.disable_chap,
617            require_chap=args.require_chap,
618            mutual_chap=args.mutual_chap,
619            chap_group=args.chap_group,
620            max_sessions=args.max_sessions,
621            max_queue_depth=args.max_queue_depth,
622            max_connections_per_session=args.max_connections_per_session,
623            default_time2wait=args.default_time2wait,
624            default_time2retain=args.default_time2retain,
625            first_burst_length=args.first_burst_length,
626            immediate_data=args.immediate_data,
627            error_recovery_level=args.error_recovery_level,
628            allow_duplicated_isid=args.allow_duplicated_isid)
629
630    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
631    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
632    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
633    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
634    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
635    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
636    *** Mutually exclusive with --require-chap""", action='store_true')
637    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
638    *** Mutually exclusive with --disable-chap""", action='store_true')
639    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
640    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
641    *** Authentication group must be precreated ***""", type=int)
642    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
643    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
644    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
645    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
646    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
647    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
648    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
649    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
650    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
651    p.set_defaults(func=set_iscsi_options)
652
653    def set_iscsi_discovery_auth(args):
654        rpc.iscsi.set_iscsi_discovery_auth(
655            args.client,
656            disable_chap=args.disable_chap,
657            require_chap=args.require_chap,
658            mutual_chap=args.mutual_chap,
659            chap_group=args.chap_group)
660
661    p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""")
662    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
663    *** Mutually exclusive with --require-chap""", action='store_true')
664    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
665    *** Mutually exclusive with --disable-chap""", action='store_true')
666    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
667    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
668    *** Authentication group must be precreated ***""", type=int)
669    p.set_defaults(func=set_iscsi_discovery_auth)
670
671    def add_iscsi_auth_group(args):
672        secrets = None
673        if args.secrets:
674            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
675
676        rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets)
677
678    p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.')
679    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
680    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
681<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
682Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
683    p.set_defaults(func=add_iscsi_auth_group)
684
685    def delete_iscsi_auth_group(args):
686        rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag)
687
688    p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.')
689    p.add_argument('tag', help='Authentication group tag', type=int)
690    p.set_defaults(func=delete_iscsi_auth_group)
691
692    def add_secret_to_iscsi_auth_group(args):
693        rpc.iscsi.add_secret_to_iscsi_auth_group(
694            args.client,
695            tag=args.tag,
696            user=args.user,
697            secret=args.secret,
698            muser=args.muser,
699            msecret=args.msecret)
700
701    p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.')
702    p.add_argument('tag', help='Authentication group tag', type=int)
703    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
704    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
705    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
706    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
707    p.set_defaults(func=add_secret_to_iscsi_auth_group)
708
709    def delete_secret_from_iscsi_auth_group(args):
710        rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user)
711
712    p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.')
713    p.add_argument('tag', help='Authentication group tag', type=int)
714    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
715    p.set_defaults(func=delete_secret_from_iscsi_auth_group)
716
717    def get_iscsi_auth_groups(args):
718        print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client))
719
720    p = subparsers.add_parser('get_iscsi_auth_groups',
721                              help='Display current authentication group configuration')
722    p.set_defaults(func=get_iscsi_auth_groups)
723
724    def get_portal_groups(args):
725        print_dict(rpc.iscsi.get_portal_groups(args.client))
726
727    p = subparsers.add_parser(
728        'get_portal_groups', help='Display current portal group configuration')
729    p.set_defaults(func=get_portal_groups)
730
731    def get_initiator_groups(args):
732        print_dict(rpc.iscsi.get_initiator_groups(args.client))
733
734    p = subparsers.add_parser('get_initiator_groups',
735                              help='Display current initiator group configuration')
736    p.set_defaults(func=get_initiator_groups)
737
738    def get_target_nodes(args):
739        print_dict(rpc.iscsi.get_target_nodes(args.client))
740
741    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
742    p.set_defaults(func=get_target_nodes)
743
744    def construct_target_node(args):
745        luns = []
746        for u in args.bdev_name_id_pairs.strip().split(" "):
747            bdev_name, lun_id = u.split(":")
748            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
749
750        pg_ig_maps = []
751        for u in args.pg_ig_mappings.strip().split(" "):
752            pg, ig = u.split(":")
753            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
754
755        rpc.iscsi.construct_target_node(
756            args.client,
757            luns=luns,
758            pg_ig_maps=pg_ig_maps,
759            name=args.name,
760            alias_name=args.alias_name,
761            queue_depth=args.queue_depth,
762            chap_group=args.chap_group,
763            disable_chap=args.disable_chap,
764            require_chap=args.require_chap,
765            mutual_chap=args.mutual_chap,
766            header_digest=args.header_digest,
767            data_digest=args.data_digest)
768
769    p = subparsers.add_parser('construct_target_node',
770                              help='Add a target node')
771    p.add_argument('name', help='Target node name (ASCII)')
772    p.add_argument('alias_name', help='Target node alias name (ASCII)')
773    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
774    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
775    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
776    *** The bdevs must pre-exist ***
777    *** LUN0 (id = 0) is required ***
778    *** bdevs names cannot contain space or colon characters ***""")
779    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
780    Whitespace separated, quoted, mapping defined with colon
781    separated list of "tags" (int > 0)
782    Example: '1:1 2:2 2:1'
783    *** The Portal/Initiator Groups must be precreated ***""")
784    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
785    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
786    *** Authentication group must be precreated ***""", type=int, default=0)
787    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
788    *** Mutually exclusive with --require-chap ***""", action='store_true')
789    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
790    *** Mutually exclusive with --disable-chap ***""", action='store_true')
791    p.add_argument(
792        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
793    p.add_argument('-H', '--header-digest',
794                   help='Header Digest should be required for this target node.', action='store_true')
795    p.add_argument('-D', '--data-digest',
796                   help='Data Digest should be required for this target node.', action='store_true')
797    p.set_defaults(func=construct_target_node)
798
799    def target_node_add_lun(args):
800        rpc.iscsi.target_node_add_lun(
801            args.client,
802            name=args.name,
803            bdev_name=args.bdev_name,
804            lun_id=args.lun_id)
805
806    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
807    p.add_argument('name', help='Target node name (ASCII)')
808    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
809    *** bdev name cannot contain space or colon characters ***""")
810    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
811    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
812    p.set_defaults(func=target_node_add_lun)
813
814    def set_iscsi_target_node_auth(args):
815        rpc.iscsi.set_iscsi_target_node_auth(
816            args.client,
817            name=args.name,
818            chap_group=args.chap_group,
819            disable_chap=args.disable_chap,
820            require_chap=args.require_chap,
821            mutual_chap=args.mutual_chap)
822
823    p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
824    p.add_argument('name', help='Target node name (ASCII)')
825    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
826    *** Authentication group must be precreated ***""", type=int, default=0)
827    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
828    *** Mutually exclusive with --require-chap ***""", action='store_true')
829    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
830    *** Mutually exclusive with --disable-chap ***""", action='store_true')
831    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
832                   action='store_true')
833    p.set_defaults(func=set_iscsi_target_node_auth)
834
835    def add_pg_ig_maps(args):
836        pg_ig_maps = []
837        for u in args.pg_ig_mappings.strip().split(" "):
838            pg, ig = u.split(":")
839            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
840        rpc.iscsi.add_pg_ig_maps(
841            args.client,
842            pg_ig_maps=pg_ig_maps,
843            name=args.name)
844
845    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
846    p.add_argument('name', help='Target node name (ASCII)')
847    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
848    Whitespace separated, quoted, mapping defined with colon
849    separated list of "tags" (int > 0)
850    Example: '1:1 2:2 2:1'
851    *** The Portal/Initiator Groups must be precreated ***""")
852    p.set_defaults(func=add_pg_ig_maps)
853
854    def delete_pg_ig_maps(args):
855        pg_ig_maps = []
856        for u in args.pg_ig_mappings.strip().split(" "):
857            pg, ig = u.split(":")
858            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
859        rpc.iscsi.delete_pg_ig_maps(
860            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
861
862    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
863    p.add_argument('name', help='Target node name (ASCII)')
864    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
865    Whitespace separated, quoted, mapping defined with colon
866    separated list of "tags" (int > 0)
867    Example: '1:1 2:2 2:1'
868    *** The Portal/Initiator Groups must be precreated ***""")
869    p.set_defaults(func=delete_pg_ig_maps)
870
871    def add_portal_group(args):
872        portals = []
873        for p in args.portal_list.strip().split(' '):
874            ip, separator, port_cpumask = p.rpartition(':')
875            split_port_cpumask = port_cpumask.split('@')
876            if len(split_port_cpumask) == 1:
877                port = port_cpumask
878                portals.append({'host': ip, 'port': port})
879            else:
880                port = split_port_cpumask[0]
881                cpumask = split_port_cpumask[1]
882                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
883        rpc.iscsi.add_portal_group(
884            args.client,
885            portals=portals,
886            tag=args.tag)
887
888    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
889    p.add_argument(
890        'tag', help='Portal group tag (unique, integer > 0)', type=int)
891    p.add_argument('portal_list', help="""List of portals in host:port@cpumask format, separated by whitespace
892    (cpumask is optional and can be skipped)
893    Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262@0x1""")
894    p.set_defaults(func=add_portal_group)
895
896    def add_initiator_group(args):
897        initiators = []
898        netmasks = []
899        for i in args.initiator_list.strip().split(' '):
900            initiators.append(i)
901        for n in args.netmask_list.strip().split(' '):
902            netmasks.append(n)
903        rpc.iscsi.add_initiator_group(
904            args.client,
905            tag=args.tag,
906            initiators=initiators,
907            netmasks=netmasks)
908
909    p = subparsers.add_parser('add_initiator_group',
910                              help='Add an initiator group')
911    p.add_argument(
912        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
913    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
914    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
915    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
916    Example: '255.255.0.0 255.248.0.0' etc""")
917    p.set_defaults(func=add_initiator_group)
918
919    def add_initiators_to_initiator_group(args):
920        initiators = None
921        netmasks = None
922        if args.initiator_list:
923            initiators = []
924            for i in args.initiator_list.strip().split(' '):
925                initiators.append(i)
926        if args.netmask_list:
927            netmasks = []
928            for n in args.netmask_list.strip().split(' '):
929                netmasks.append(n)
930        rpc.iscsi.add_initiators_to_initiator_group(
931            args.client,
932            tag=args.tag,
933            initiators=initiators,
934            netmasks=netmasks)
935
936    p = subparsers.add_parser('add_initiators_to_initiator_group',
937                              help='Add initiators to an existing initiator group')
938    p.add_argument(
939        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
940    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
941    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
942    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
943    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
944    p.set_defaults(func=add_initiators_to_initiator_group)
945
946    def delete_initiators_from_initiator_group(args):
947        initiators = None
948        netmasks = None
949        if args.initiator_list:
950            initiators = []
951            for i in args.initiator_list.strip().split(' '):
952                initiators.append(i)
953        if args.netmask_list:
954            netmasks = []
955            for n in args.netmask_list.strip().split(' '):
956                netmasks.append(n)
957        rpc.iscsi.delete_initiators_from_initiator_group(
958            args.client,
959            tag=args.tag,
960            initiators=initiators,
961            netmasks=netmasks)
962
963    p = subparsers.add_parser('delete_initiators_from_initiator_group',
964                              help='Delete initiators from an existing initiator group')
965    p.add_argument(
966        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
967    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
968    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
969    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
970    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
971    p.set_defaults(func=delete_initiators_from_initiator_group)
972
973    def delete_target_node(args):
974        rpc.iscsi.delete_target_node(
975            args.client, target_node_name=args.target_node_name)
976
977    p = subparsers.add_parser('delete_target_node',
978                              help='Delete a target node')
979    p.add_argument('target_node_name',
980                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
981    p.set_defaults(func=delete_target_node)
982
983    def delete_portal_group(args):
984        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
985
986    p = subparsers.add_parser('delete_portal_group',
987                              help='Delete a portal group')
988    p.add_argument(
989        'tag', help='Portal group tag (unique, integer > 0)', type=int)
990    p.set_defaults(func=delete_portal_group)
991
992    def delete_initiator_group(args):
993        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
994
995    p = subparsers.add_parser('delete_initiator_group',
996                              help='Delete an initiator group')
997    p.add_argument(
998        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
999    p.set_defaults(func=delete_initiator_group)
1000
1001    def get_iscsi_connections(args):
1002        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
1003
1004    p = subparsers.add_parser('get_iscsi_connections',
1005                              help='Display iSCSI connections')
1006    p.set_defaults(func=get_iscsi_connections)
1007
1008    def get_iscsi_global_params(args):
1009        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
1010
1011    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
1012    p.set_defaults(func=get_iscsi_global_params)
1013
1014    def get_scsi_devices(args):
1015        print_dict(rpc.iscsi.get_scsi_devices(args.client))
1016
1017    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
1018    p.set_defaults(func=get_scsi_devices)
1019
1020    # trace
1021    def enable_tpoint_group(args):
1022        rpc.trace.enable_tpoint_group(args.client, name=args.name)
1023
1024    p = subparsers.add_parser('enable_tpoint_group', help='enable trace on a specific tpoint group')
1025    p.add_argument(
1026        'name', help="""trace group name we want to enable in tpoint_group_mask.
1027        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1028    p.set_defaults(func=enable_tpoint_group)
1029
1030    def disable_tpoint_group(args):
1031        rpc.trace.disable_tpoint_group(args.client, name=args.name)
1032
1033    p = subparsers.add_parser('disable_tpoint_group', help='disable trace on a specific tpoint group')
1034    p.add_argument(
1035        'name', help="""trace group name we want to disable in tpoint_group_mask.
1036        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1037    p.set_defaults(func=disable_tpoint_group)
1038
1039    def get_tpoint_group_mask(args):
1040        print_dict(rpc.trace.get_tpoint_group_mask(args.client))
1041
1042    p = subparsers.add_parser('get_tpoint_group_mask', help='get trace point group mask')
1043    p.set_defaults(func=get_tpoint_group_mask)
1044
1045    # log
1046    def set_log_flag(args):
1047        rpc.log.set_log_flag(args.client, flag=args.flag)
1048
1049    p = subparsers.add_parser('set_log_flag', help='set log flag', aliases=['set_trace_flag'])
1050    p.add_argument(
1051        'flag', help='log flag we want to set. (for example "nvme").')
1052    p.set_defaults(func=set_log_flag)
1053
1054    def clear_log_flag(args):
1055        rpc.log.clear_log_flag(args.client, flag=args.flag)
1056
1057    p = subparsers.add_parser('clear_log_flag', help='clear log flag', aliases=['clear_trace_flag'])
1058    p.add_argument(
1059        'flag', help='log flag we want to clear. (for example "nvme").')
1060    p.set_defaults(func=clear_log_flag)
1061
1062    def get_log_flags(args):
1063        print_dict(rpc.log.get_log_flags(args.client))
1064
1065    p = subparsers.add_parser('get_log_flags', help='get log flags', aliases=['get_trace_flags'])
1066    p.set_defaults(func=get_log_flags)
1067
1068    def set_log_level(args):
1069        rpc.log.set_log_level(args.client, level=args.level)
1070
1071    p = subparsers.add_parser('set_log_level', help='set log level')
1072    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1073    p.set_defaults(func=set_log_level)
1074
1075    def get_log_level(args):
1076        print_dict(rpc.log.get_log_level(args.client))
1077
1078    p = subparsers.add_parser('get_log_level', help='get log level')
1079    p.set_defaults(func=get_log_level)
1080
1081    def set_log_print_level(args):
1082        rpc.log.set_log_print_level(args.client, level=args.level)
1083
1084    p = subparsers.add_parser('set_log_print_level', help='set log print level')
1085    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1086    p.set_defaults(func=set_log_print_level)
1087
1088    def get_log_print_level(args):
1089        print_dict(rpc.log.get_log_print_level(args.client))
1090
1091    p = subparsers.add_parser('get_log_print_level', help='get log print level')
1092    p.set_defaults(func=get_log_print_level)
1093
1094    # lvol
1095    def construct_lvol_store(args):
1096        print(rpc.lvol.construct_lvol_store(args.client,
1097                                            bdev_name=args.bdev_name,
1098                                            lvs_name=args.lvs_name,
1099                                            cluster_sz=args.cluster_sz,
1100                                            clear_method=args.clear_method))
1101
1102    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
1103    p.add_argument('bdev_name', help='base bdev name')
1104    p.add_argument('lvs_name', help='name for lvol store')
1105    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1106    p.add_argument('--clear-method', help="""Change clear method for data region.
1107        Available: none, unmap, write_zeroes""", required=False)
1108    p.set_defaults(func=construct_lvol_store)
1109
1110    def rename_lvol_store(args):
1111        rpc.lvol.rename_lvol_store(args.client,
1112                                   old_name=args.old_name,
1113                                   new_name=args.new_name)
1114
1115    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
1116    p.add_argument('old_name', help='old name')
1117    p.add_argument('new_name', help='new name')
1118    p.set_defaults(func=rename_lvol_store)
1119
1120    def construct_lvol_bdev(args):
1121        print(rpc.lvol.construct_lvol_bdev(args.client,
1122                                           lvol_name=args.lvol_name,
1123                                           size=args.size * 1024 * 1024,
1124                                           thin_provision=args.thin_provision,
1125                                           clear_method=args.clear_method,
1126                                           uuid=args.uuid,
1127                                           lvs_name=args.lvs_name))
1128
1129    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
1130    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1131    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1132    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1133    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1134        Available: none, unmap, write_zeroes""", required=False)
1135    p.add_argument('lvol_name', help='name for this lvol')
1136    p.add_argument('size', help='size in MiB for this bdev', type=int)
1137    p.set_defaults(func=construct_lvol_bdev)
1138
1139    def snapshot_lvol_bdev(args):
1140        print(rpc.lvol.snapshot_lvol_bdev(args.client,
1141                                          lvol_name=args.lvol_name,
1142                                          snapshot_name=args.snapshot_name))
1143
1144    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
1145    p.add_argument('lvol_name', help='lvol bdev name')
1146    p.add_argument('snapshot_name', help='lvol snapshot name')
1147    p.set_defaults(func=snapshot_lvol_bdev)
1148
1149    def clone_lvol_bdev(args):
1150        print(rpc.lvol.clone_lvol_bdev(args.client,
1151                                       snapshot_name=args.snapshot_name,
1152                                       clone_name=args.clone_name))
1153
1154    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
1155    p.add_argument('snapshot_name', help='lvol snapshot name')
1156    p.add_argument('clone_name', help='lvol clone name')
1157    p.set_defaults(func=clone_lvol_bdev)
1158
1159    def rename_lvol_bdev(args):
1160        rpc.lvol.rename_lvol_bdev(args.client,
1161                                  old_name=args.old_name,
1162                                  new_name=args.new_name)
1163
1164    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
1165    p.add_argument('old_name', help='lvol bdev name')
1166    p.add_argument('new_name', help='new lvol name')
1167    p.set_defaults(func=rename_lvol_bdev)
1168
1169    def inflate_lvol_bdev(args):
1170        rpc.lvol.inflate_lvol_bdev(args.client,
1171                                   name=args.name)
1172
1173    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
1174    p.add_argument('name', help='lvol bdev name')
1175    p.set_defaults(func=inflate_lvol_bdev)
1176
1177    def decouple_parent_lvol_bdev(args):
1178        rpc.lvol.decouple_parent_lvol_bdev(args.client,
1179                                           name=args.name)
1180
1181    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
1182    p.add_argument('name', help='lvol bdev name')
1183    p.set_defaults(func=decouple_parent_lvol_bdev)
1184
1185    def resize_lvol_bdev(args):
1186        rpc.lvol.resize_lvol_bdev(args.client,
1187                                  name=args.name,
1188                                  size=args.size * 1024 * 1024)
1189
1190    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
1191    p.add_argument('name', help='lvol bdev name')
1192    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1193    p.set_defaults(func=resize_lvol_bdev)
1194
1195    def set_read_only_lvol_bdev(args):
1196        rpc.lvol.set_read_only_lvol_bdev(args.client,
1197                                         name=args.name)
1198
1199    p = subparsers.add_parser('set_read_only_lvol_bdev', help='Mark lvol bdev as read only')
1200    p.add_argument('name', help='lvol bdev name')
1201    p.set_defaults(func=set_read_only_lvol_bdev)
1202
1203    def destroy_lvol_bdev(args):
1204        rpc.lvol.destroy_lvol_bdev(args.client,
1205                                   name=args.name)
1206
1207    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1208    p.add_argument('name', help='lvol bdev name')
1209    p.set_defaults(func=destroy_lvol_bdev)
1210
1211    def destroy_lvol_store(args):
1212        rpc.lvol.destroy_lvol_store(args.client,
1213                                    uuid=args.uuid,
1214                                    lvs_name=args.lvs_name)
1215
1216    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1217    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1218    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1219    p.set_defaults(func=destroy_lvol_store)
1220
1221    def get_lvol_stores(args):
1222        print_dict(rpc.lvol.get_lvol_stores(args.client,
1223                                            uuid=args.uuid,
1224                                            lvs_name=args.lvs_name))
1225
1226    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1227    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1228    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1229    p.set_defaults(func=get_lvol_stores)
1230
1231    def get_raid_bdevs(args):
1232        print_array(rpc.bdev.get_raid_bdevs(args.client,
1233                                            category=args.category))
1234
1235    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1236    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1237    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1238    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1239    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1240    p.add_argument('category', help='all or online or configuring or offline')
1241    p.set_defaults(func=get_raid_bdevs)
1242
1243    def construct_raid_bdev(args):
1244        base_bdevs = []
1245        for u in args.base_bdevs.strip().split(" "):
1246            base_bdevs.append(u)
1247
1248        rpc.bdev.construct_raid_bdev(args.client,
1249                                     name=args.name,
1250                                     strip_size=args.strip_size,
1251                                     strip_size_kb=args.strip_size_kb,
1252                                     raid_level=args.raid_level,
1253                                     base_bdevs=base_bdevs)
1254    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1255    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1256    p.add_argument('-s', '--strip-size', help='strip size in KB (deprecated)', type=int)
1257    p.add_argument('-z', '--strip-size_kb', help='strip size in KB', type=int)
1258    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1259    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1260    p.set_defaults(func=construct_raid_bdev)
1261
1262    def destroy_raid_bdev(args):
1263        rpc.bdev.destroy_raid_bdev(args.client,
1264                                   name=args.name)
1265    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1266    p.add_argument('name', help='raid bdev name')
1267    p.set_defaults(func=destroy_raid_bdev)
1268
1269    # split
1270    def construct_split_vbdev(args):
1271        print_array(rpc.bdev.construct_split_vbdev(args.client,
1272                                                   base_bdev=args.base_bdev,
1273                                                   split_count=args.split_count,
1274                                                   split_size_mb=args.split_size_mb))
1275
1276    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1277    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1278    available (during examination process).""")
1279    p.add_argument('base_bdev', help='base bdev name')
1280    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1281    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1282    exceed the base bdev size.""", type=int)
1283    p.set_defaults(func=construct_split_vbdev)
1284
1285    def destruct_split_vbdev(args):
1286        rpc.bdev.destruct_split_vbdev(args.client,
1287                                      base_bdev=args.base_bdev)
1288
1289    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1290    p.add_argument('base_bdev', help='base bdev name')
1291    p.set_defaults(func=destruct_split_vbdev)
1292
1293    # ftl
1294    def construct_ftl_bdev(args):
1295        print_dict(rpc.bdev.construct_ftl_bdev(args.client,
1296                                               name=args.name,
1297                                               trtype=args.trtype,
1298                                               traddr=args.traddr,
1299                                               punits=args.punits,
1300                                               uuid=args.uuid,
1301                                               cache=args.cache,
1302                                               allow_open_bands=args.allow_open_bands))
1303
1304    p = subparsers.add_parser('construct_ftl_bdev',
1305                              help='Add FTL bdev')
1306    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1307    p.add_argument('-t', '--trtype',
1308                   help='NVMe target trtype: e.g., pcie', default='pcie')
1309    p.add_argument('-a', '--traddr',
1310                   help='NVMe target address: e.g., an ip address or BDF', required=True)
1311    p.add_argument('-l', '--punits', help='Parallel unit range in the form of start-end: e.g. 4-8',
1312                   required=True)
1313    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
1314                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
1315    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache (optional)')
1316    p.add_argument('-o', '--allow_open_bands', help='Restoring after dirty shutdown without cache will'
1317                   ' result in partial data recovery, instead of error', action='store_true')
1318    p.set_defaults(func=construct_ftl_bdev)
1319
1320    def delete_ftl_bdev(args):
1321        print_dict(rpc.bdev.delete_ftl_bdev(args.client, name=args.name))
1322
1323    p = subparsers.add_parser('delete_ftl_bdev', help='Delete FTL bdev')
1324    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1325    p.set_defaults(func=delete_ftl_bdev)
1326
1327    # nbd
1328    def start_nbd_disk(args):
1329        print(rpc.nbd.start_nbd_disk(args.client,
1330                                     bdev_name=args.bdev_name,
1331                                     nbd_device=args.nbd_device))
1332
1333    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1334    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1335    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?')
1336    p.set_defaults(func=start_nbd_disk)
1337
1338    def stop_nbd_disk(args):
1339        rpc.nbd.stop_nbd_disk(args.client,
1340                              nbd_device=args.nbd_device)
1341
1342    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1343    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1344    p.set_defaults(func=stop_nbd_disk)
1345
1346    def get_nbd_disks(args):
1347        print_dict(rpc.nbd.get_nbd_disks(args.client,
1348                                         nbd_device=args.nbd_device))
1349
1350    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1351    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1352    p.set_defaults(func=get_nbd_disks)
1353
1354    # net
1355    def add_ip_address(args):
1356        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1357
1358    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1359    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1360    p.add_argument('ip_addr', help='ip address will be added.')
1361    p.set_defaults(func=add_ip_address)
1362
1363    def delete_ip_address(args):
1364        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1365
1366    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1367    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1368    p.add_argument('ip_addr', help='ip address will be deleted.')
1369    p.set_defaults(func=delete_ip_address)
1370
1371    def get_interfaces(args):
1372        print_dict(rpc.net.get_interfaces(args.client))
1373
1374    p = subparsers.add_parser(
1375        'get_interfaces', help='Display current interface list')
1376    p.set_defaults(func=get_interfaces)
1377
1378    # NVMe-oF
1379    def set_nvmf_target_max_subsystems(args):
1380        rpc.nvmf.set_nvmf_target_max_subsystems(args.client,
1381                                                max_subsystems=args.max_subsystems)
1382
1383    p = subparsers.add_parser('set_nvmf_target_max_subsystems', help='Set the maximum number of NVMf target subsystems')
1384    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1385    p.set_defaults(func=set_nvmf_target_max_subsystems)
1386
1387    def set_nvmf_target_config(args):
1388        rpc.nvmf.set_nvmf_target_config(args.client,
1389                                        acceptor_poll_rate=args.acceptor_poll_rate,
1390                                        conn_sched=args.conn_sched)
1391
1392    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1393    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1394    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1395    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1396    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1397    robin manner""")
1398    p.set_defaults(func=set_nvmf_target_config)
1399
1400    def nvmf_create_transport(args):
1401        rpc.nvmf.nvmf_create_transport(args.client,
1402                                       trtype=args.trtype,
1403                                       max_queue_depth=args.max_queue_depth,
1404                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1405                                       in_capsule_data_size=args.in_capsule_data_size,
1406                                       max_io_size=args.max_io_size,
1407                                       io_unit_size=args.io_unit_size,
1408                                       max_aq_depth=args.max_aq_depth,
1409                                       num_shared_buffers=args.num_shared_buffers,
1410                                       buf_cache_size=args.buf_cache_size,
1411                                       max_srq_depth=args.max_srq_depth,
1412                                       no_srq=args.no_srq)
1413
1414    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1415    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1416    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1417    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1418    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1419    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1420    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1421    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1422    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
1423    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
1424    p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int)
1425    p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport')
1426    p.set_defaults(func=nvmf_create_transport)
1427
1428    def get_nvmf_transports(args):
1429        print_dict(rpc.nvmf.get_nvmf_transports(args.client))
1430
1431    p = subparsers.add_parser('get_nvmf_transports',
1432                              help='Display nvmf transports')
1433    p.set_defaults(func=get_nvmf_transports)
1434
1435    def get_nvmf_subsystems(args):
1436        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1437
1438    p = subparsers.add_parser('get_nvmf_subsystems',
1439                              help='Display nvmf subsystems')
1440    p.set_defaults(func=get_nvmf_subsystems)
1441
1442    def nvmf_subsystem_create(args):
1443        rpc.nvmf.nvmf_subsystem_create(args.client,
1444                                       nqn=args.nqn,
1445                                       serial_number=args.serial_number,
1446                                       model_number=args.model_number,
1447                                       allow_any_host=args.allow_any_host,
1448                                       max_namespaces=args.max_namespaces)
1449
1450    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1451    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1452    p.add_argument("-s", "--serial-number", help="""
1453    Format:  'sn' etc
1454    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1455    p.add_argument("-d", "--model-number", help="""
1456    Format:  'mn' etc
1457    Example: 'SPDK Controller'""", default='SPDK bdev Controller')
1458    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1459    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1460                   type=int, default=0)
1461    p.set_defaults(func=nvmf_subsystem_create)
1462
1463    def delete_nvmf_subsystem(args):
1464        rpc.nvmf.delete_nvmf_subsystem(args.client,
1465                                       nqn=args.subsystem_nqn)
1466
1467    p = subparsers.add_parser('delete_nvmf_subsystem',
1468                              help='Delete a nvmf subsystem')
1469    p.add_argument('subsystem_nqn',
1470                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1471    p.set_defaults(func=delete_nvmf_subsystem)
1472
1473    def nvmf_subsystem_add_listener(args):
1474        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1475                                             nqn=args.nqn,
1476                                             trtype=args.trtype,
1477                                             traddr=args.traddr,
1478                                             adrfam=args.adrfam,
1479                                             trsvcid=args.trsvcid)
1480
1481    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1482    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1483    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1484    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1485    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1486    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1487    p.set_defaults(func=nvmf_subsystem_add_listener)
1488
1489    def nvmf_subsystem_remove_listener(args):
1490        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1491                                                nqn=args.nqn,
1492                                                trtype=args.trtype,
1493                                                traddr=args.traddr,
1494                                                adrfam=args.adrfam,
1495                                                trsvcid=args.trsvcid)
1496
1497    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1498    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1499    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1500    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1501    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1502    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1503    p.set_defaults(func=nvmf_subsystem_remove_listener)
1504
1505    def nvmf_subsystem_add_ns(args):
1506        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1507                                       nqn=args.nqn,
1508                                       bdev_name=args.bdev_name,
1509                                       nsid=args.nsid,
1510                                       nguid=args.nguid,
1511                                       eui64=args.eui64,
1512                                       uuid=args.uuid)
1513
1514    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1515    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1516    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1517    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1518    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1519    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1520    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1521    p.set_defaults(func=nvmf_subsystem_add_ns)
1522
1523    def nvmf_subsystem_remove_ns(args):
1524        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1525                                          nqn=args.nqn,
1526                                          nsid=args.nsid)
1527
1528    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1529    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1530    p.add_argument('nsid', help='The requested NSID', type=int)
1531    p.set_defaults(func=nvmf_subsystem_remove_ns)
1532
1533    def nvmf_subsystem_add_host(args):
1534        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1535                                         nqn=args.nqn,
1536                                         host=args.host)
1537
1538    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1539    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1540    p.add_argument('host', help='Host NQN to allow')
1541    p.set_defaults(func=nvmf_subsystem_add_host)
1542
1543    def nvmf_subsystem_remove_host(args):
1544        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1545                                            nqn=args.nqn,
1546                                            host=args.host)
1547
1548    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1549    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1550    p.add_argument('host', help='Host NQN to remove')
1551    p.set_defaults(func=nvmf_subsystem_remove_host)
1552
1553    def nvmf_subsystem_allow_any_host(args):
1554        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1555                                               nqn=args.nqn,
1556                                               disable=args.disable)
1557
1558    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1559    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1560    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1561    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1562    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1563
1564    # pmem
1565    def create_pmem_pool(args):
1566        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1567        rpc.pmem.create_pmem_pool(args.client,
1568                                  pmem_file=args.pmem_file,
1569                                  num_blocks=num_blocks,
1570                                  block_size=args.block_size)
1571
1572    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1573    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1574    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1575    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1576    p.set_defaults(func=create_pmem_pool)
1577
1578    def pmem_pool_info(args):
1579        print_dict(rpc.pmem.pmem_pool_info(args.client,
1580                                           pmem_file=args.pmem_file))
1581
1582    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1583    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1584    p.set_defaults(func=pmem_pool_info)
1585
1586    def delete_pmem_pool(args):
1587        rpc.pmem.delete_pmem_pool(args.client,
1588                                  pmem_file=args.pmem_file)
1589
1590    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1591    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1592    p.set_defaults(func=delete_pmem_pool)
1593
1594    # subsystem
1595    def get_subsystems(args):
1596        print_dict(rpc.subsystem.get_subsystems(args.client))
1597
1598    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1599    entry contain (unsorted) array of subsystems it depends on.""")
1600    p.set_defaults(func=get_subsystems)
1601
1602    def get_subsystem_config(args):
1603        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1604
1605    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1606    p.add_argument('name', help='Name of subsystem to query')
1607    p.set_defaults(func=get_subsystem_config)
1608
1609    # vhost
1610    def set_vhost_controller_coalescing(args):
1611        rpc.vhost.set_vhost_controller_coalescing(args.client,
1612                                                  ctrlr=args.ctrlr,
1613                                                  delay_base_us=args.delay_base_us,
1614                                                  iops_threshold=args.iops_threshold)
1615
1616    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1617    p.add_argument('ctrlr', help='controller name')
1618    p.add_argument('delay_base_us', help='Base delay time', type=int)
1619    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1620    p.set_defaults(func=set_vhost_controller_coalescing)
1621
1622    def construct_vhost_scsi_controller(args):
1623        rpc.vhost.construct_vhost_scsi_controller(args.client,
1624                                                  ctrlr=args.ctrlr,
1625                                                  cpumask=args.cpumask)
1626
1627    p = subparsers.add_parser(
1628        'construct_vhost_scsi_controller', help='Add new vhost controller')
1629    p.add_argument('ctrlr', help='controller name')
1630    p.add_argument('--cpumask', help='cpu mask for this controller')
1631    p.set_defaults(func=construct_vhost_scsi_controller)
1632
1633    def add_vhost_scsi_lun(args):
1634        print(rpc.vhost.add_vhost_scsi_lun(args.client,
1635                                           ctrlr=args.ctrlr,
1636                                           scsi_target_num=args.scsi_target_num,
1637                                           bdev_name=args.bdev_name))
1638
1639    p = subparsers.add_parser('add_vhost_scsi_lun',
1640                              help='Add lun to vhost controller')
1641    p.add_argument('ctrlr', help='conntroller name where add lun')
1642    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1643    p.add_argument('bdev_name', help='bdev name')
1644    p.set_defaults(func=add_vhost_scsi_lun)
1645
1646    def remove_vhost_scsi_target(args):
1647        rpc.vhost.remove_vhost_scsi_target(args.client,
1648                                           ctrlr=args.ctrlr,
1649                                           scsi_target_num=args.scsi_target_num)
1650
1651    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1652    p.add_argument('ctrlr', help='controller name to remove target from')
1653    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1654    p.set_defaults(func=remove_vhost_scsi_target)
1655
1656    def construct_vhost_blk_controller(args):
1657        rpc.vhost.construct_vhost_blk_controller(args.client,
1658                                                 ctrlr=args.ctrlr,
1659                                                 dev_name=args.dev_name,
1660                                                 cpumask=args.cpumask,
1661                                                 readonly=args.readonly)
1662
1663    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1664    p.add_argument('ctrlr', help='controller name')
1665    p.add_argument('dev_name', help='device name')
1666    p.add_argument('--cpumask', help='cpu mask for this controller')
1667    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1668    p.set_defaults(func=construct_vhost_blk_controller)
1669
1670    def construct_vhost_nvme_controller(args):
1671        rpc.vhost.construct_vhost_nvme_controller(args.client,
1672                                                  ctrlr=args.ctrlr,
1673                                                  io_queues=args.io_queues,
1674                                                  cpumask=args.cpumask)
1675
1676    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1677    p.add_argument('ctrlr', help='controller name')
1678    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1679    p.add_argument('--cpumask', help='cpu mask for this controller')
1680    p.set_defaults(func=construct_vhost_nvme_controller)
1681
1682    def add_vhost_nvme_ns(args):
1683        rpc.vhost.add_vhost_nvme_ns(args.client,
1684                                    ctrlr=args.ctrlr,
1685                                    bdev_name=args.bdev_name)
1686
1687    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1688    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1689    p.add_argument('bdev_name', help='block device name for a new Namespace')
1690    p.set_defaults(func=add_vhost_nvme_ns)
1691
1692    def get_vhost_controllers(args):
1693        print_dict(rpc.vhost.get_vhost_controllers(args.client, args.name))
1694
1695    p = subparsers.add_parser('get_vhost_controllers', help='List all or specific vhost controller(s)')
1696    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
1697    p.set_defaults(func=get_vhost_controllers)
1698
1699    def remove_vhost_controller(args):
1700        rpc.vhost.remove_vhost_controller(args.client,
1701                                          ctrlr=args.ctrlr)
1702
1703    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1704    p.add_argument('ctrlr', help='controller name')
1705    p.set_defaults(func=remove_vhost_controller)
1706
1707    def construct_virtio_dev(args):
1708        print_array(rpc.vhost.construct_virtio_dev(args.client,
1709                                                   name=args.name,
1710                                                   trtype=args.trtype,
1711                                                   traddr=args.traddr,
1712                                                   dev_type=args.dev_type,
1713                                                   vq_count=args.vq_count,
1714                                                   vq_size=args.vq_size))
1715
1716    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1717    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1718    remote side. Result is array of added bdevs.""")
1719    p.add_argument('name', help="Use this name as base for new created bdevs")
1720    p.add_argument('-t', '--trtype',
1721                   help='Virtio target transport type: pci or user', required=True)
1722    p.add_argument('-a', '--traddr',
1723                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1724    p.add_argument('-d', '--dev-type',
1725                   help='Device type: blk or scsi', required=True)
1726    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1727    p.add_argument('--vq-size', help='Size of each queue', type=int)
1728    p.set_defaults(func=construct_virtio_dev)
1729
1730    def get_virtio_scsi_devs(args):
1731        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1732
1733    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1734    p.set_defaults(func=get_virtio_scsi_devs)
1735
1736    def remove_virtio_bdev(args):
1737        rpc.vhost.remove_virtio_bdev(args.client,
1738                                     name=args.name)
1739
1740    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1741    This will delete all bdevs exposed by this device""")
1742    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1743    p.set_defaults(func=remove_virtio_bdev)
1744
1745    # ioat
1746    def scan_ioat_copy_engine(args):
1747        pci_whitelist = []
1748        if args.pci_whitelist:
1749            for w in args.pci_whitelist.strip().split(" "):
1750                pci_whitelist.append(w)
1751        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1752
1753    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1754    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1755    domain:bus:device.function format or domain.bus.device.function format""")
1756    p.set_defaults(func=scan_ioat_copy_engine)
1757
1758    # send_nvme_cmd
1759    def send_nvme_cmd(args):
1760        print_dict(rpc.nvme.send_nvme_cmd(args.client,
1761                                          name=args.nvme_name,
1762                                          cmd_type=args.cmd_type,
1763                                          data_direction=args.data_direction,
1764                                          cmdbuf=args.cmdbuf,
1765                                          data=args.data,
1766                                          metadata=args.metadata,
1767                                          data_len=args.data_length,
1768                                          metadata_len=args.metadata_length,
1769                                          timeout_ms=args.timeout_ms))
1770
1771    p = subparsers.add_parser('send_nvme_cmd', help='NVMe passthrough cmd.')
1772    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
1773    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
1774    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
1775    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
1776    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
1777    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
1778    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
1779    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
1780    p.add_argument('-T', '--timeout-ms',
1781                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
1782    p.set_defaults(func=send_nvme_cmd)
1783
1784    # Notifications
1785    def get_notification_types(args):
1786        print_dict(rpc.notify.get_notification_types(args.client))
1787
1788    p = subparsers.add_parser('get_notification_types', help='List available notifications that user can subscribe to.')
1789    p.set_defaults(func=get_notification_types)
1790
1791    def get_notifications(args):
1792        ret = rpc.notify.get_notifications(args.client,
1793                                           id=args.id,
1794                                           max=args.max)
1795        print_dict(ret)
1796
1797    p = subparsers.add_parser('get_notifications', help='Get notifications')
1798    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
1799    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
1800    p.set_defaults(func=get_notifications)
1801
1802    def check_called_name(name):
1803        if name in deprecated_aliases:
1804            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
1805
1806    def call_rpc_func(args):
1807        args.func(args)
1808        check_called_name(args.called_rpc_name)
1809
1810    def execute_script(parser, client, fd):
1811        executed_rpc = ""
1812        for rpc_call in map(str.rstrip, fd):
1813            if not rpc_call.strip():
1814                continue
1815            executed_rpc = "\n".join([executed_rpc, rpc_call])
1816            args = parser.parse_args(shlex.split(rpc_call))
1817            args.client = client
1818            try:
1819                call_rpc_func(args)
1820            except JSONRPCException as ex:
1821                print("Exception:")
1822                print(executed_rpc.strip() + " <<<")
1823                print(ex.message)
1824                exit(1)
1825
1826    args = parser.parse_args()
1827    args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper()))
1828    if hasattr(args, 'func'):
1829        try:
1830            call_rpc_func(args)
1831        except JSONRPCException as ex:
1832            print(ex)
1833            exit(1)
1834    elif sys.stdin.isatty():
1835        # No arguments and no data piped through stdin
1836        parser.print_help()
1837        exit(1)
1838    else:
1839        execute_script(parser, args.client, sys.stdin)
1840