xref: /spdk/scripts/rpc.py (revision 1914de09202410b6881d8bcff916ce78fb749ad6)
1#!/usr/bin/env python3
2
3from rpc.client import print_dict, print_json, JSONRPCException
4from rpc.helpers import deprecated_aliases
5
6import logging
7import argparse
8import rpc
9import sys
10import shlex
11import json
12
13try:
14    from shlex import quote
15except ImportError:
16    from pipes import quote
17
18
19def print_array(a):
20    print(" ".join((quote(v) for v in a)))
21
22
23if __name__ == "__main__":
24    parser = argparse.ArgumentParser(
25        description='SPDK RPC command line interface')
26    parser.add_argument('-s', dest='server_addr',
27                        help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock')
28    parser.add_argument('-p', dest='port',
29                        help='RPC port number (if server_addr is IP address)',
30                        default=5260, type=int)
31    parser.add_argument('-t', dest='timeout',
32                        help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0',
33                        default=60.0, type=float)
34    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
35                        help='Set verbose mode to INFO', default="ERROR")
36    parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'],
37                        help="""Set verbose level. """)
38    parser.add_argument('--dry_run', dest='dry_run', action='store_true', help="Display request and exit")
39    parser.set_defaults(dry_run=False)
40    subparsers = parser.add_subparsers(help='RPC methods', dest='called_rpc_name')
41
42    def framework_start_init(args):
43        rpc.framework_start_init(args.client)
44
45    p = subparsers.add_parser('framework_start_init', aliases=['start_subsystem_init'],
46                              help='Start initialization of subsystems')
47    p.set_defaults(func=framework_start_init)
48
49    def framework_wait_init(args):
50        rpc.framework_wait_init(args.client)
51
52    p = subparsers.add_parser('framework_wait_init', aliases=['wait_subsystem_init'],
53                              help='Block until subsystems have been initialized')
54    p.set_defaults(func=framework_wait_init)
55
56    def rpc_get_methods(args):
57        print_dict(rpc.rpc_get_methods(args.client,
58                                       current=args.current,
59                                       include_aliases=args.include_aliases))
60
61    p = subparsers.add_parser('rpc_get_methods', aliases=['get_rpc_methods'],
62                              help='Get list of supported RPC methods')
63    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
64    p.add_argument('-i', '--include-aliases', help='include RPC aliases', action='store_true')
65    p.set_defaults(func=rpc_get_methods)
66
67    def spdk_get_version(args):
68        print_json(rpc.spdk_get_version(args.client))
69
70    p = subparsers.add_parser('spdk_get_version', aliases=['get_spdk_version'],
71                              help='Get SPDK version')
72    p.set_defaults(func=spdk_get_version)
73
74    def save_config(args):
75        rpc.save_config(args.client,
76                        sys.stdout,
77                        indent=args.indent)
78
79    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
80    """)
81    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
82    """, type=int, default=2)
83    p.set_defaults(func=save_config)
84
85    def load_config(args):
86        rpc.load_config(args.client, sys.stdin,
87                        include_aliases=args.include_aliases)
88
89    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""")
90    p.add_argument('-i', '--include-aliases', help='include RPC aliases', action='store_true')
91    p.set_defaults(func=load_config)
92
93    def save_subsystem_config(args):
94        rpc.save_subsystem_config(args.client,
95                                  sys.stdout,
96                                  indent=args.indent,
97                                  name=args.name)
98
99    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
100    """)
101    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
102    """, type=int, default=2)
103    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
104    p.set_defaults(func=save_subsystem_config)
105
106    def load_subsystem_config(args):
107        rpc.load_subsystem_config(args.client,
108                                  sys.stdin)
109
110    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""")
111    p.set_defaults(func=load_subsystem_config)
112
113    # app
114    def spdk_kill_instance(args):
115        rpc.app.spdk_kill_instance(args.client,
116                                   sig_name=args.sig_name)
117
118    p = subparsers.add_parser('spdk_kill_instance', aliases=['kill_instance'],
119                              help='Send signal to instance')
120    p.add_argument('sig_name', help='signal will be sent to server.')
121    p.set_defaults(func=spdk_kill_instance)
122
123    def framework_monitor_context_switch(args):
124        enabled = None
125        if args.enable:
126            enabled = True
127        if args.disable:
128            enabled = False
129        print_dict(rpc.app.framework_monitor_context_switch(args.client,
130                                                            enabled=enabled))
131
132    p = subparsers.add_parser('framework_monitor_context_switch', aliases=['context_switch_monitor'],
133                              help='Control whether the context switch monitor is enabled')
134    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
135    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
136    p.set_defaults(func=framework_monitor_context_switch)
137
138    def framework_get_reactors(args):
139        print_dict(rpc.app.framework_get_reactors(args.client))
140
141    p = subparsers.add_parser(
142        'framework_get_reactors', help='Display list of all reactors')
143    p.set_defaults(func=framework_get_reactors)
144
145    # bdev
146    def bdev_set_options(args):
147        rpc.bdev.bdev_set_options(args.client,
148                                  bdev_io_pool_size=args.bdev_io_pool_size,
149                                  bdev_io_cache_size=args.bdev_io_cache_size)
150
151    p = subparsers.add_parser('bdev_set_options', aliases=['set_bdev_options'],
152                              help="""Set options of bdev subsystem""")
153    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
154    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
155    p.set_defaults(func=bdev_set_options)
156
157    def bdev_compress_create(args):
158        print_json(rpc.bdev.bdev_compress_create(args.client,
159                                                 base_bdev_name=args.base_bdev_name,
160                                                 pm_path=args.pm_path))
161
162    p = subparsers.add_parser('bdev_compress_create', aliases=['construct_compress_bdev'],
163                              help='Add a compress vbdev')
164    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
165    p.add_argument('-p', '--pm_path', help="Path to persistent memory")
166    p.set_defaults(func=bdev_compress_create)
167
168    def bdev_compress_delete(args):
169        rpc.bdev.bdev_compress_delete(args.client,
170                                      name=args.name)
171
172    p = subparsers.add_parser('bdev_compress_delete', aliases=['delete_compress_bdev'],
173                              help='Delete a compress disk')
174    p.add_argument('name', help='compress bdev name')
175    p.set_defaults(func=bdev_compress_delete)
176
177    def compress_set_pmd(args):
178        rpc.bdev.compress_set_pmd(args.client,
179                                  pmd=args.pmd)
180    p = subparsers.add_parser('compress_set_pmd', aliases=['set_compress_pmd'],
181                              help='Set pmd option for a compress disk')
182    p.add_argument('-p', '--pmd', type=int, help='0 = auto-select, 1= QAT only, 2 = ISAL only')
183    p.set_defaults(func=compress_set_pmd)
184
185    def bdev_compress_get_orphans(args):
186        print_dict(rpc.bdev.bdev_compress_get_orphans(args.client,
187                                                      name=args.name))
188    p = subparsers.add_parser(
189        'bdev_compress_get_orphans', help='Display list of orphaned compress bdevs.')
190    p.add_argument('-b', '--name', help="Name of a comp bdev. Example: COMP_Nvme0n1", required=False)
191    p.set_defaults(func=bdev_compress_get_orphans)
192
193    def bdev_crypto_create(args):
194        print_json(rpc.bdev.bdev_crypto_create(args.client,
195                                               base_bdev_name=args.base_bdev_name,
196                                               name=args.name,
197                                               crypto_pmd=args.crypto_pmd,
198                                               key=args.key,
199                                               cipher=args.cipher,
200                                               key2=args.key2))
201    p = subparsers.add_parser('bdev_crypto_create', aliases=['construct_crypto_bdev'],
202                              help='Add a crypto vbdev')
203    p.add_argument('base_bdev_name', help="Name of the base bdev")
204    p.add_argument('name', help="Name of the crypto vbdev")
205    p.add_argument('crypto_pmd', help="Name of the crypto device driver")
206    p.add_argument('key', help="Key")
207    p.add_argument('-c', '--cipher', help="cipher to use, AES_CBC or AES_XTS (QAT only)", default="AES_CBC")
208    p.add_argument('-k2', '--key2', help="2nd key for cipher AET_XTS", default=None)
209    p.set_defaults(func=bdev_crypto_create)
210
211    def bdev_crypto_delete(args):
212        rpc.bdev.bdev_crypto_delete(args.client,
213                                    name=args.name)
214
215    p = subparsers.add_parser('bdev_crypto_delete', aliases=['delete_crypto_bdev'],
216                              help='Delete a crypto disk')
217    p.add_argument('name', help='crypto bdev name')
218    p.set_defaults(func=bdev_crypto_delete)
219
220    def bdev_ocf_create(args):
221        print_json(rpc.bdev.bdev_ocf_create(args.client,
222                                            name=args.name,
223                                            mode=args.mode,
224                                            cache_bdev_name=args.cache_bdev_name,
225                                            core_bdev_name=args.core_bdev_name))
226    p = subparsers.add_parser('bdev_ocf_create', aliases=['construct_ocf_bdev'],
227                              help='Add an OCF block device')
228    p.add_argument('name', help='Name of resulting OCF bdev')
229    p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt', 'wa', 'wi', 'wo'])
230    p.add_argument('cache_bdev_name', help='Name of underlying cache bdev')
231    p.add_argument('core_bdev_name', help='Name of unerlying core bdev')
232    p.set_defaults(func=bdev_ocf_create)
233
234    def bdev_ocf_delete(args):
235        rpc.bdev.bdev_ocf_delete(args.client,
236                                 name=args.name)
237
238    p = subparsers.add_parser('bdev_ocf_delete', aliases=['delete_ocf_bdev'],
239                              help='Delete an OCF block device')
240    p.add_argument('name', help='Name of OCF bdev')
241    p.set_defaults(func=bdev_ocf_delete)
242
243    def bdev_ocf_get_stats(args):
244        print_dict(rpc.bdev.bdev_ocf_get_stats(args.client,
245                                               name=args.name))
246    p = subparsers.add_parser('bdev_ocf_get_stats', aliases=['get_ocf_stats'],
247                              help='Get statistics of chosen OCF block device')
248    p.add_argument('name', help='Name of OCF bdev')
249    p.set_defaults(func=bdev_ocf_get_stats)
250
251    def bdev_ocf_get_bdevs(args):
252        print_dict(rpc.bdev.bdev_ocf_get_bdevs(args.client,
253                                               name=args.name))
254    p = subparsers.add_parser('bdev_ocf_get_bdevs', aliases=['get_ocf_bdevs'],
255                              help='Get list of OCF devices including unregistered ones')
256    p.add_argument('name', nargs='?', default=None, help='name of OCF vbdev or name of cache device or name of core device (optional)')
257    p.set_defaults(func=bdev_ocf_get_bdevs)
258
259    def bdev_malloc_create(args):
260        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
261        print_json(rpc.bdev.bdev_malloc_create(args.client,
262                                               num_blocks=int(num_blocks),
263                                               block_size=args.block_size,
264                                               name=args.name,
265                                               uuid=args.uuid))
266    p = subparsers.add_parser('bdev_malloc_create', aliases=['construct_malloc_bdev'],
267                              help='Create a bdev with malloc backend')
268    p.add_argument('-b', '--name', help="Name of the bdev")
269    p.add_argument('-u', '--uuid', help="UUID of the bdev")
270    p.add_argument(
271        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
272    p.add_argument('block_size', help='Block size for this bdev', type=int)
273    p.set_defaults(func=bdev_malloc_create)
274
275    def bdev_malloc_delete(args):
276        rpc.bdev.bdev_malloc_delete(args.client,
277                                    name=args.name)
278
279    p = subparsers.add_parser('bdev_malloc_delete', aliases=['delete_malloc_bdev'],
280                              help='Delete a malloc disk')
281    p.add_argument('name', help='malloc bdev name')
282    p.set_defaults(func=bdev_malloc_delete)
283
284    def bdev_null_create(args):
285        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
286        print_json(rpc.bdev.bdev_null_create(args.client,
287                                             num_blocks=num_blocks,
288                                             block_size=args.block_size,
289                                             name=args.name,
290                                             uuid=args.uuid,
291                                             md_size=args.md_size,
292                                             dif_type=args.dif_type,
293                                             dif_is_head_of_md=args.dif_is_head_of_md))
294
295    p = subparsers.add_parser('bdev_null_create', aliases=['construct_null_bdev'],
296                              help='Add a bdev with null backend')
297    p.add_argument('name', help='Block device name')
298    p.add_argument('-u', '--uuid', help='UUID of the bdev')
299    p.add_argument(
300        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
301    p.add_argument('block_size', help='Block size for this bdev', type=int)
302    p.add_argument('-m', '--md-size', type=int,
303                   help='Metadata size for this bdev. Default 0')
304    p.add_argument('-t', '--dif-type', type=int, choices=[0, 1, 2, 3],
305                   help='Protection information type. Default: 0 - no protection')
306    p.add_argument('-d', '--dif-is-head-of-md', action='store_true',
307                   help='Protection information is in the first 8 bytes of metadata. Default: in the last 8 bytes')
308    p.set_defaults(func=bdev_null_create)
309
310    def bdev_null_delete(args):
311        rpc.bdev.bdev_null_delete(args.client,
312                                  name=args.name)
313
314    p = subparsers.add_parser('bdev_null_delete', aliases=['delete_null_bdev'],
315                              help='Delete a null bdev')
316    p.add_argument('name', help='null bdev name')
317    p.set_defaults(func=bdev_null_delete)
318
319    def bdev_aio_create(args):
320        print_json(rpc.bdev.bdev_aio_create(args.client,
321                                            filename=args.filename,
322                                            name=args.name,
323                                            block_size=args.block_size))
324
325    p = subparsers.add_parser('bdev_aio_create', aliases=['construct_aio_bdev'],
326                              help='Add a bdev with aio backend')
327    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
328    p.add_argument('name', help='Block device name')
329    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
330    p.set_defaults(func=bdev_aio_create)
331
332    def bdev_aio_delete(args):
333        rpc.bdev.bdev_aio_delete(args.client,
334                                 name=args.name)
335
336    p = subparsers.add_parser('bdev_aio_delete', aliases=['delete_aio_bdev'],
337                              help='Delete an aio disk')
338    p.add_argument('name', help='aio bdev name')
339    p.set_defaults(func=bdev_aio_delete)
340
341    def bdev_uring_create(args):
342        print_json(rpc.bdev.bdev_uring_create(args.client,
343                                              filename=args.filename,
344                                              name=args.name,
345                                              block_size=args.block_size))
346
347    p = subparsers.add_parser('bdev_uring_create', help='Create a bdev with io_uring backend')
348    p.add_argument('filename', help='Path to device or file (ex: /dev/nvme0n1)')
349    p.add_argument('name', help='bdev name')
350    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
351    p.set_defaults(func=bdev_uring_create)
352
353    def bdev_uring_delete(args):
354        rpc.bdev.bdev_uring_delete(args.client,
355                                   name=args.name)
356
357    p = subparsers.add_parser('bdev_uring_delete', help='Delete a uring bdev')
358    p.add_argument('name', help='uring bdev name')
359    p.set_defaults(func=bdev_uring_delete)
360
361    def bdev_nvme_set_options(args):
362        rpc.bdev.bdev_nvme_set_options(args.client,
363                                       action_on_timeout=args.action_on_timeout,
364                                       timeout_us=args.timeout_us,
365                                       retry_count=args.retry_count,
366                                       arbitration_burst=args.arbitration_burst,
367                                       low_priority_weight=args.low_priority_weight,
368                                       medium_priority_weight=args.medium_priority_weight,
369                                       high_priority_weight=args.high_priority_weight,
370                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us,
371                                       nvme_ioq_poll_period_us=args.nvme_ioq_poll_period_us,
372                                       io_queue_requests=args.io_queue_requests,
373                                       delay_cmd_submit=args.delay_cmd_submit)
374
375    p = subparsers.add_parser('bdev_nvme_set_options', aliases=['set_bdev_nvme_options'],
376                              help='Set options for the bdev nvme type. This is startup command.')
377    p.add_argument('-a', '--action-on-timeout',
378                   help="Action to take on command time out. Valid valies are: none, reset, abort")
379    p.add_argument('-t', '--timeout-us',
380                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
381    p.add_argument('-n', '--retry-count',
382                   help='the number of attempts per I/O when an I/O fails', type=int)
383    p.add_argument('--arbitration-burst',
384                   help='the value is expressed as a power of two', type=int)
385    p.add_argument('--low-priority-weight',
386                   help='the maximum number of commands that the controller may launch at one time from a low priority queue', type=int)
387    p.add_argument('--medium-priority-weight',
388                   help='the maximum number of commands that the controller may launch at one time from a medium priority queue', type=int)
389    p.add_argument('--high-priority-weight',
390                   help='the maximum number of commands that the controller may launch at one time from a high priority queue', type=int)
391    p.add_argument('-p', '--nvme-adminq-poll-period-us',
392                   help='How often the admin queue is polled for asynchronous events', type=int)
393    p.add_argument('-i', '--nvme-ioq-poll-period-us',
394                   help='How often to poll I/O queues for completions', type=int)
395    p.add_argument('-s', '--io-queue-requests',
396                   help='The number of requests allocated for each NVMe I/O queue. Default: 512', type=int)
397    p.add_argument('-d', '--disable-delay-cmd-submit',
398                   help='Disable delaying NVMe command submission, i.e. no batching of multiple commands',
399                   action='store_false', dest='delay_cmd_submit', default=True)
400    p.set_defaults(func=bdev_nvme_set_options)
401
402    def bdev_nvme_set_hotplug(args):
403        rpc.bdev.bdev_nvme_set_hotplug(args.client, enable=args.enable, period_us=args.period_us)
404
405    p = subparsers.add_parser('bdev_nvme_set_hotplug', aliases=['set_bdev_nvme_hotplug'],
406                              help='Set hotplug options for bdev nvme type.')
407    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
408    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
409    p.add_argument('-r', '--period-us',
410                   help='How often the hotplug is processed for insert and remove events', type=int)
411    p.set_defaults(func=bdev_nvme_set_hotplug)
412
413    def bdev_nvme_attach_controller(args):
414        print_array(rpc.bdev.bdev_nvme_attach_controller(args.client,
415                                                         name=args.name,
416                                                         trtype=args.trtype,
417                                                         traddr=args.traddr,
418                                                         adrfam=args.adrfam,
419                                                         trsvcid=args.trsvcid,
420                                                         subnqn=args.subnqn,
421                                                         hostnqn=args.hostnqn,
422                                                         hostaddr=args.hostaddr,
423                                                         hostsvcid=args.hostsvcid,
424                                                         prchk_reftag=args.prchk_reftag,
425                                                         prchk_guard=args.prchk_guard))
426
427    p = subparsers.add_parser('bdev_nvme_attach_controller', aliases=['construct_nvme_bdev'],
428                              help='Add bdevs with nvme backend')
429    p.add_argument('-b', '--name', help="Name of the NVMe controller, prefix for each bdev name", required=True)
430    p.add_argument('-t', '--trtype',
431                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
432    p.add_argument('-a', '--traddr',
433                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
434    p.add_argument('-f', '--adrfam',
435                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
436    p.add_argument('-s', '--trsvcid',
437                   help='NVMe-oF target trsvcid: e.g., a port number')
438    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
439    p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn')
440    p.add_argument('-i', '--hostaddr',
441                   help='NVMe-oF host address: e.g., an ip address')
442    p.add_argument('-c', '--hostsvcid',
443                   help='NVMe-oF host svcid: e.g., a port number')
444    p.add_argument('-r', '--prchk-reftag',
445                   help='Enable checking of PI reference tag for I/O processing.', action='store_true')
446    p.add_argument('-g', '--prchk-guard',
447                   help='Enable checking of PI guard for I/O processing.', action='store_true')
448    p.set_defaults(func=bdev_nvme_attach_controller)
449
450    def bdev_nvme_get_controllers(args):
451        print_dict(rpc.nvme.bdev_nvme_get_controllers(args.client,
452                                                      name=args.name))
453
454    p = subparsers.add_parser(
455        'bdev_nvme_get_controllers', aliases=['get_nvme_controllers'],
456        help='Display current NVMe controllers list or required NVMe controller')
457    p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False)
458    p.set_defaults(func=bdev_nvme_get_controllers)
459
460    def bdev_nvme_detach_controller(args):
461        rpc.bdev.bdev_nvme_detach_controller(args.client,
462                                             name=args.name)
463
464    p = subparsers.add_parser('bdev_nvme_detach_controller', aliases=['delete_nvme_controller'],
465                              help='Detach an NVMe controller and delete any associated bdevs')
466    p.add_argument('name', help="Name of the controller")
467    p.set_defaults(func=bdev_nvme_detach_controller)
468
469    def bdev_nvme_cuse_register(args):
470        rpc.bdev.bdev_nvme_cuse_register(args.client,
471                                         name=args.name)
472
473    p = subparsers.add_parser('bdev_nvme_cuse_register',
474                              help='Register CUSE devices on NVMe controller')
475    p.add_argument('-n', '--name',
476                   help='Name of the NVMe controller. Example: Nvme0', required=True)
477    p.set_defaults(func=bdev_nvme_cuse_register)
478
479    def bdev_nvme_cuse_unregister(args):
480        rpc.bdev.bdev_nvme_cuse_unregister(args.client,
481                                           name=args.name)
482
483    p = subparsers.add_parser('bdev_nvme_cuse_unregister',
484                              help='Unregister CUSE devices on NVMe controller')
485    p.add_argument('-n', '--name',
486                   help='Name of the NVMe controller. Example: Nvme0', required=True)
487    p.set_defaults(func=bdev_nvme_cuse_unregister)
488
489    def bdev_zone_block_create(args):
490        print_json(rpc.bdev.bdev_zone_block_create(args.client,
491                                                   name=args.name,
492                                                   base_bdev=args.base_bdev,
493                                                   zone_capacity=args.zone_capacity,
494                                                   optimal_open_zones=args.optimal_open_zones))
495
496    p = subparsers.add_parser('bdev_zone_block_create',
497                              help='Create virtual zone namespace device with block device backend')
498    p.add_argument('-b', '--name', help="Name of the zone device", required=True)
499    p.add_argument('-n', '--base-bdev', help='Name of underlying, non-zoned bdev', required=True)
500    p.add_argument('-z', '--zone-capacity', help='Surfaced zone capacity in blocks', type=int, required=True)
501    p.add_argument('-o', '--optimal-open-zones', help='Number of zones required to reach optimal write speed', type=int, required=True)
502    p.set_defaults(func=bdev_zone_block_create)
503
504    def bdev_zone_block_delete(args):
505        rpc.bdev.bdev_zone_block_delete(args.client,
506                                        name=args.name)
507
508    p = subparsers.add_parser('bdev_zone_block_delete', help='Delete a virtual zone namespace device')
509    p.add_argument('name', help='Virtual zone bdev name')
510    p.set_defaults(func=bdev_zone_block_delete)
511
512    def bdev_rbd_create(args):
513        config = None
514        if args.config:
515            config = {}
516            for entry in args.config:
517                parts = entry.split('=', 1)
518                if len(parts) != 2:
519                    raise Exception('--config %s not in key=value form' % entry)
520                config[parts[0]] = parts[1]
521        print_json(rpc.bdev.bdev_rbd_create(args.client,
522                                            name=args.name,
523                                            user=args.user,
524                                            config=config,
525                                            pool_name=args.pool_name,
526                                            rbd_name=args.rbd_name,
527                                            block_size=args.block_size))
528
529    p = subparsers.add_parser('bdev_rbd_create', aliases=['construct_rbd_bdev'],
530                              help='Add a bdev with ceph rbd backend')
531    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
532    p.add_argument('--user', help="Ceph user name (i.e. admin, not client.admin)", required=False)
533    p.add_argument('--config', action='append', metavar='key=value',
534                   help="adds a key=value configuration option for rados_conf_set (default: rely on config file)")
535    p.add_argument('pool_name', help='rbd pool name')
536    p.add_argument('rbd_name', help='rbd image name')
537    p.add_argument('block_size', help='rbd block size', type=int)
538    p.set_defaults(func=bdev_rbd_create)
539
540    def bdev_rbd_delete(args):
541        rpc.bdev.bdev_rbd_delete(args.client,
542                                 name=args.name)
543
544    p = subparsers.add_parser('bdev_rbd_delete', aliases=['delete_rbd_bdev'],
545                              help='Delete a rbd bdev')
546    p.add_argument('name', help='rbd bdev name')
547    p.set_defaults(func=bdev_rbd_delete)
548
549    def bdev_delay_create(args):
550        print_json(rpc.bdev.bdev_delay_create(args.client,
551                                              base_bdev_name=args.base_bdev_name,
552                                              name=args.name,
553                                              avg_read_latency=args.avg_read_latency,
554                                              p99_read_latency=args.nine_nine_read_latency,
555                                              avg_write_latency=args.avg_write_latency,
556                                              p99_write_latency=args.nine_nine_write_latency))
557
558    p = subparsers.add_parser('bdev_delay_create',
559                              help='Add a delay bdev on existing bdev')
560    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
561    p.add_argument('-d', '--name', help="Name of the delay bdev", required=True)
562    p.add_argument('-r', '--avg-read-latency',
563                   help="Average latency to apply before completing read ops (in microseconds)", required=True, type=int)
564    p.add_argument('-t', '--nine-nine-read-latency',
565                   help="latency to apply to 1 in 100 read ops (in microseconds)", required=True, type=int)
566    p.add_argument('-w', '--avg-write-latency',
567                   help="Average latency to apply before completing write ops (in microseconds)", required=True, type=int)
568    p.add_argument('-n', '--nine-nine-write-latency',
569                   help="latency to apply to 1 in 100 write ops (in microseconds)", required=True, type=int)
570    p.set_defaults(func=bdev_delay_create)
571
572    def bdev_delay_delete(args):
573        rpc.bdev.bdev_delay_delete(args.client,
574                                   name=args.name)
575
576    p = subparsers.add_parser('bdev_delay_delete', help='Delete a delay bdev')
577    p.add_argument('name', help='delay bdev name')
578    p.set_defaults(func=bdev_delay_delete)
579
580    def bdev_delay_update_latency(args):
581        print_json(rpc.bdev.bdev_delay_update_latency(args.client,
582                                                      delay_bdev_name=args.delay_bdev_name,
583                                                      latency_type=args.latency_type,
584                                                      latency_us=args.latency_us))
585    p = subparsers.add_parser('bdev_delay_update_latency',
586                              help='Update one of the latency values for a given delay bdev')
587    p.add_argument('delay_bdev_name', help='The name of the given delay bdev')
588    p.add_argument('latency_type', help='one of: avg_read, avg_write, p99_read, p99_write. No other values accepted.')
589    p.add_argument('latency_us', help='new latency value in microseconds.', type=int)
590    p.set_defaults(func=bdev_delay_update_latency)
591
592    def bdev_error_create(args):
593        print_json(rpc.bdev.bdev_error_create(args.client,
594                                              base_name=args.base_name))
595
596    p = subparsers.add_parser('bdev_error_create', aliases=['construct_error_bdev'],
597                              help='Add bdev with error injection backend')
598    p.add_argument('base_name', help='base bdev name')
599    p.set_defaults(func=bdev_error_create)
600
601    def bdev_error_delete(args):
602        rpc.bdev.bdev_error_delete(args.client,
603                                   name=args.name)
604
605    p = subparsers.add_parser('bdev_error_delete', aliases=['delete_error_bdev'],
606                              help='Delete an error bdev')
607    p.add_argument('name', help='error bdev name')
608    p.set_defaults(func=bdev_error_delete)
609
610    def bdev_iscsi_create(args):
611        print_json(rpc.bdev.bdev_iscsi_create(args.client,
612                                              name=args.name,
613                                              url=args.url,
614                                              initiator_iqn=args.initiator_iqn))
615
616    p = subparsers.add_parser('bdev_iscsi_create', aliases=['construct_iscsi_bdev'],
617                              help='Add bdev with iSCSI initiator backend')
618    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
619    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
620    p.add_argument('--url', help="iSCSI Lun URL", required=True)
621    p.set_defaults(func=bdev_iscsi_create)
622
623    def bdev_iscsi_delete(args):
624        rpc.bdev.bdev_iscsi_delete(args.client,
625                                   name=args.name)
626
627    p = subparsers.add_parser('bdev_iscsi_delete', aliases=['delete_iscsi_bdev'],
628                              help='Delete an iSCSI bdev')
629    p.add_argument('name', help='iSCSI bdev name')
630    p.set_defaults(func=bdev_iscsi_delete)
631
632    def bdev_pmem_create(args):
633        print_json(rpc.bdev.bdev_pmem_create(args.client,
634                                             pmem_file=args.pmem_file,
635                                             name=args.name))
636
637    p = subparsers.add_parser('bdev_pmem_create', aliases=['construct_pmem_bdev'],
638                              help='Add a bdev with pmem backend')
639    p.add_argument('pmem_file', help='Path to pmemblk pool file')
640    p.add_argument('-n', '--name', help='Block device name', required=True)
641    p.set_defaults(func=bdev_pmem_create)
642
643    def bdev_pmem_delete(args):
644        rpc.bdev.bdev_pmem_delete(args.client,
645                                  name=args.name)
646
647    p = subparsers.add_parser('bdev_pmem_delete', aliases=['delete_pmem_bdev'],
648                              help='Delete a pmem bdev')
649    p.add_argument('name', help='pmem bdev name')
650    p.set_defaults(func=bdev_pmem_delete)
651
652    def bdev_passthru_create(args):
653        print_json(rpc.bdev.bdev_passthru_create(args.client,
654                                                 base_bdev_name=args.base_bdev_name,
655                                                 name=args.name))
656
657    p = subparsers.add_parser('bdev_passthru_create', aliases=['construct_passthru_bdev'],
658                              help='Add a pass through bdev on existing bdev')
659    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
660    p.add_argument('-p', '--name', help="Name of the pass through bdev", required=True)
661    p.set_defaults(func=bdev_passthru_create)
662
663    def bdev_passthru_delete(args):
664        rpc.bdev.bdev_passthru_delete(args.client,
665                                      name=args.name)
666
667    p = subparsers.add_parser('bdev_passthru_delete', aliases=['delete_passthru_bdev'],
668                              help='Delete a pass through bdev')
669    p.add_argument('name', help='pass through bdev name')
670    p.set_defaults(func=bdev_passthru_delete)
671
672    def bdev_get_bdevs(args):
673        print_dict(rpc.bdev.bdev_get_bdevs(args.client,
674                                           name=args.name))
675
676    p = subparsers.add_parser('bdev_get_bdevs', aliases=['get_bdevs'],
677                              help='Display current blockdev list or required blockdev')
678    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
679    p.set_defaults(func=bdev_get_bdevs)
680
681    def bdev_get_iostat(args):
682        print_dict(rpc.bdev.bdev_get_iostat(args.client,
683                                            name=args.name))
684
685    p = subparsers.add_parser('bdev_get_iostat', aliases=['get_bdevs_iostat'],
686                              help='Display current I/O statistics of all the blockdevs or required blockdev.')
687    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
688    p.set_defaults(func=bdev_get_iostat)
689
690    def bdev_enable_histogram(args):
691        rpc.bdev.bdev_enable_histogram(args.client, name=args.name, enable=args.enable)
692
693    p = subparsers.add_parser('bdev_enable_histogram', aliases=['enable_bdev_histogram'],
694                              help='Enable or disable histogram for specified bdev')
695    p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
696    p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
697    p.add_argument('name', help='bdev name')
698    p.set_defaults(func=bdev_enable_histogram)
699
700    def bdev_get_histogram(args):
701        print_dict(rpc.bdev.bdev_get_histogram(args.client, name=args.name))
702
703    p = subparsers.add_parser('bdev_get_histogram', aliases=['get_bdev_histogram'],
704                              help='Get histogram for specified bdev')
705    p.add_argument('name', help='bdev name')
706    p.set_defaults(func=bdev_get_histogram)
707
708    def bdev_set_qd_sampling_period(args):
709        rpc.bdev.bdev_set_qd_sampling_period(args.client,
710                                             name=args.name,
711                                             period=args.period)
712
713    p = subparsers.add_parser('bdev_set_qd_sampling_period', aliases=['set_bdev_qd_sampling_period'],
714                              help="Enable or disable tracking of a bdev's queue depth.")
715    p.add_argument('name', help='Blockdev name. Example: Malloc0')
716    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
717                   ' If set to 0, polling will be disabled.',
718                   type=int)
719    p.set_defaults(func=bdev_set_qd_sampling_period)
720
721    def bdev_set_qos_limit(args):
722        rpc.bdev.bdev_set_qos_limit(args.client,
723                                    name=args.name,
724                                    rw_ios_per_sec=args.rw_ios_per_sec,
725                                    rw_mbytes_per_sec=args.rw_mbytes_per_sec,
726                                    r_mbytes_per_sec=args.r_mbytes_per_sec,
727                                    w_mbytes_per_sec=args.w_mbytes_per_sec)
728
729    p = subparsers.add_parser('bdev_set_qos_limit', aliases=['set_bdev_qos_limit'],
730                              help='Set QoS rate limit on a blockdev')
731    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
732    p.add_argument('--rw_ios_per_sec',
733                   help='R/W IOs per second limit (>=10000, example: 20000). 0 means unlimited.',
734                   type=int, required=False)
735    p.add_argument('--rw_mbytes_per_sec',
736                   help="R/W megabytes per second limit (>=10, example: 100). 0 means unlimited.",
737                   type=int, required=False)
738    p.add_argument('--r_mbytes_per_sec',
739                   help="Read megabytes per second limit (>=10, example: 100). 0 means unlimited.",
740                   type=int, required=False)
741    p.add_argument('--w_mbytes_per_sec',
742                   help="Write megabytes per second limit (>=10, example: 100). 0 means unlimited.",
743                   type=int, required=False)
744    p.set_defaults(func=bdev_set_qos_limit)
745
746    def bdev_error_inject_error(args):
747        rpc.bdev.bdev_error_inject_error(args.client,
748                                         name=args.name,
749                                         io_type=args.io_type,
750                                         error_type=args.error_type,
751                                         num=args.num)
752
753    p = subparsers.add_parser('bdev_error_inject_error', aliases=['bdev_inject_error'],
754                              help='bdev inject error')
755    p.add_argument('name', help="""the name of the error injection bdev""")
756    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
757    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
758    p.add_argument(
759        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
760    p.set_defaults(func=bdev_error_inject_error)
761
762    def bdev_nvme_apply_firmware(args):
763        print_dict(rpc.bdev.bdev_nvme_apply_firmware(args.client,
764                                                     bdev_name=args.bdev_name,
765                                                     filename=args.filename))
766
767    p = subparsers.add_parser('bdev_nvme_apply_firmware', aliases=['apply_firmware'],
768                              help='Download and commit firmware to NVMe device')
769    p.add_argument('filename', help='filename of the firmware to download')
770    p.add_argument('bdev_name', help='name of the NVMe device')
771    p.set_defaults(func=bdev_nvme_apply_firmware)
772
773    # iSCSI
774    def iscsi_set_options(args):
775        rpc.iscsi.iscsi_set_options(
776            args.client,
777            auth_file=args.auth_file,
778            node_base=args.node_base,
779            nop_timeout=args.nop_timeout,
780            nop_in_interval=args.nop_in_interval,
781            disable_chap=args.disable_chap,
782            require_chap=args.require_chap,
783            mutual_chap=args.mutual_chap,
784            chap_group=args.chap_group,
785            max_sessions=args.max_sessions,
786            max_queue_depth=args.max_queue_depth,
787            max_connections_per_session=args.max_connections_per_session,
788            default_time2wait=args.default_time2wait,
789            default_time2retain=args.default_time2retain,
790            first_burst_length=args.first_burst_length,
791            immediate_data=args.immediate_data,
792            error_recovery_level=args.error_recovery_level,
793            allow_duplicated_isid=args.allow_duplicated_isid)
794
795    p = subparsers.add_parser('iscsi_set_options', aliases=['set_iscsi_options'],
796                              help="""Set options of iSCSI subsystem""")
797    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
798    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
799    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
800    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
801    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
802    *** Mutually exclusive with --require-chap""", action='store_true')
803    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
804    *** Mutually exclusive with --disable-chap""", action='store_true')
805    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
806    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
807    *** Authentication group must be precreated ***""", type=int)
808    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
809    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
810    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
811    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
812    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
813    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
814    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
815    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
816    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
817    p.set_defaults(func=iscsi_set_options)
818
819    def iscsi_set_discovery_auth(args):
820        rpc.iscsi.iscsi_set_discovery_auth(
821            args.client,
822            disable_chap=args.disable_chap,
823            require_chap=args.require_chap,
824            mutual_chap=args.mutual_chap,
825            chap_group=args.chap_group)
826
827    p = subparsers.add_parser('iscsi_set_discovery_auth', aliases=['set_iscsi_discovery_auth'],
828                              help="""Set CHAP authentication for discovery session.""")
829    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
830    *** Mutually exclusive with --require-chap""", action='store_true')
831    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
832    *** Mutually exclusive with --disable-chap""", action='store_true')
833    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
834    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
835    *** Authentication group must be precreated ***""", type=int)
836    p.set_defaults(func=iscsi_set_discovery_auth)
837
838    def iscsi_create_auth_group(args):
839        secrets = None
840        if args.secrets:
841            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
842
843        rpc.iscsi.iscsi_create_auth_group(args.client, tag=args.tag, secrets=secrets)
844
845    p = subparsers.add_parser('iscsi_create_auth_group', aliases=['add_iscsi_auth_group'],
846                              help='Create authentication group for CHAP authentication.')
847    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
848    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
849<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
850Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
851    p.set_defaults(func=iscsi_create_auth_group)
852
853    def iscsi_delete_auth_group(args):
854        rpc.iscsi.iscsi_delete_auth_group(args.client, tag=args.tag)
855
856    p = subparsers.add_parser('iscsi_delete_auth_group', aliases=['delete_iscsi_auth_group'],
857                              help='Delete an authentication group.')
858    p.add_argument('tag', help='Authentication group tag', type=int)
859    p.set_defaults(func=iscsi_delete_auth_group)
860
861    def iscsi_auth_group_add_secret(args):
862        rpc.iscsi.iscsi_auth_group_add_secret(
863            args.client,
864            tag=args.tag,
865            user=args.user,
866            secret=args.secret,
867            muser=args.muser,
868            msecret=args.msecret)
869
870    p = subparsers.add_parser('iscsi_auth_group_add_secret', aliases=['add_secret_to_iscsi_auth_group'],
871                              help='Add a secret to an authentication group.')
872    p.add_argument('tag', help='Authentication group tag', type=int)
873    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
874    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
875    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
876    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
877    p.set_defaults(func=iscsi_auth_group_add_secret)
878
879    def iscsi_auth_group_remove_secret(args):
880        rpc.iscsi.iscsi_auth_group_remove_secret(args.client, tag=args.tag, user=args.user)
881
882    p = subparsers.add_parser('iscsi_auth_group_remove_secret', aliases=['delete_secret_from_iscsi_auth_group'],
883                              help='Remove a secret from an authentication group.')
884    p.add_argument('tag', help='Authentication group tag', type=int)
885    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
886    p.set_defaults(func=iscsi_auth_group_remove_secret)
887
888    def iscsi_get_auth_groups(args):
889        print_dict(rpc.iscsi.iscsi_get_auth_groups(args.client))
890
891    p = subparsers.add_parser('iscsi_get_auth_groups', aliases=['get_iscsi_auth_groups'],
892                              help='Display current authentication group configuration')
893    p.set_defaults(func=iscsi_get_auth_groups)
894
895    def iscsi_get_portal_groups(args):
896        print_dict(rpc.iscsi.iscsi_get_portal_groups(args.client))
897
898    p = subparsers.add_parser(
899        'iscsi_get_portal_groups', aliases=['get_portal_groups'],
900        help='Display current portal group configuration')
901    p.set_defaults(func=iscsi_get_portal_groups)
902
903    def iscsi_get_initiator_groups(args):
904        print_dict(rpc.iscsi.iscsi_get_initiator_groups(args.client))
905
906    p = subparsers.add_parser('iscsi_get_initiator_groups',
907                              aliases=['get_initiator_groups'],
908                              help='Display current initiator group configuration')
909    p.set_defaults(func=iscsi_get_initiator_groups)
910
911    def iscsi_get_target_nodes(args):
912        print_dict(rpc.iscsi.iscsi_get_target_nodes(args.client))
913
914    p = subparsers.add_parser('iscsi_get_target_nodes', aliases=['get_target_nodes'],
915                              help='Display target nodes')
916    p.set_defaults(func=iscsi_get_target_nodes)
917
918    def iscsi_create_target_node(args):
919        luns = []
920        for u in args.bdev_name_id_pairs.strip().split(" "):
921            bdev_name, lun_id = u.split(":")
922            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
923
924        pg_ig_maps = []
925        for u in args.pg_ig_mappings.strip().split(" "):
926            pg, ig = u.split(":")
927            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
928
929        rpc.iscsi.iscsi_create_target_node(
930            args.client,
931            luns=luns,
932            pg_ig_maps=pg_ig_maps,
933            name=args.name,
934            alias_name=args.alias_name,
935            queue_depth=args.queue_depth,
936            chap_group=args.chap_group,
937            disable_chap=args.disable_chap,
938            require_chap=args.require_chap,
939            mutual_chap=args.mutual_chap,
940            header_digest=args.header_digest,
941            data_digest=args.data_digest)
942
943    p = subparsers.add_parser('iscsi_create_target_node', aliases=['construct_target_node'],
944                              help='Add a target node')
945    p.add_argument('name', help='Target node name (ASCII)')
946    p.add_argument('alias_name', help='Target node alias name (ASCII)')
947    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
948    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
949    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
950    *** The bdevs must pre-exist ***
951    *** LUN0 (id = 0) is required ***
952    *** bdevs names cannot contain space or colon characters ***""")
953    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
954    Whitespace separated, quoted, mapping defined with colon
955    separated list of "tags" (int > 0)
956    Example: '1:1 2:2 2:1'
957    *** The Portal/Initiator Groups must be precreated ***""")
958    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
959    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
960    *** Authentication group must be precreated ***""", type=int, default=0)
961    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
962    *** Mutually exclusive with --require-chap ***""", action='store_true')
963    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
964    *** Mutually exclusive with --disable-chap ***""", action='store_true')
965    p.add_argument(
966        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
967    p.add_argument('-H', '--header-digest',
968                   help='Header Digest should be required for this target node.', action='store_true')
969    p.add_argument('-D', '--data-digest',
970                   help='Data Digest should be required for this target node.', action='store_true')
971    p.set_defaults(func=iscsi_create_target_node)
972
973    def iscsi_target_node_add_lun(args):
974        rpc.iscsi.iscsi_target_node_add_lun(
975            args.client,
976            name=args.name,
977            bdev_name=args.bdev_name,
978            lun_id=args.lun_id)
979
980    p = subparsers.add_parser('iscsi_target_node_add_lun', aliases=['target_node_add_lun'],
981                              help='Add LUN to the target node')
982    p.add_argument('name', help='Target node name (ASCII)')
983    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
984    *** bdev name cannot contain space or colon characters ***""")
985    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
986    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
987    p.set_defaults(func=iscsi_target_node_add_lun)
988
989    def iscsi_target_node_set_auth(args):
990        rpc.iscsi.iscsi_target_node_set_auth(
991            args.client,
992            name=args.name,
993            chap_group=args.chap_group,
994            disable_chap=args.disable_chap,
995            require_chap=args.require_chap,
996            mutual_chap=args.mutual_chap)
997
998    p = subparsers.add_parser('iscsi_target_node_set_auth', aliases=['set_iscsi_target_node_auth'],
999                              help='Set CHAP authentication for the target node')
1000    p.add_argument('name', help='Target node name (ASCII)')
1001    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
1002    *** Authentication group must be precreated ***""", type=int, default=0)
1003    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
1004    *** Mutually exclusive with --require-chap ***""", action='store_true')
1005    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
1006    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1007    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1008                   action='store_true')
1009    p.set_defaults(func=iscsi_target_node_set_auth)
1010
1011    def iscsi_target_node_add_pg_ig_maps(args):
1012        pg_ig_maps = []
1013        for u in args.pg_ig_mappings.strip().split(" "):
1014            pg, ig = u.split(":")
1015            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1016        rpc.iscsi.iscsi_target_node_add_pg_ig_maps(
1017            args.client,
1018            pg_ig_maps=pg_ig_maps,
1019            name=args.name)
1020
1021    p = subparsers.add_parser('iscsi_target_node_add_pg_ig_maps',
1022                              aliases=['add_pg_ig_maps'],
1023                              help='Add PG-IG maps to the target node')
1024    p.add_argument('name', help='Target node name (ASCII)')
1025    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1026    Whitespace separated, quoted, mapping defined with colon
1027    separated list of "tags" (int > 0)
1028    Example: '1:1 2:2 2:1'
1029    *** The Portal/Initiator Groups must be precreated ***""")
1030    p.set_defaults(func=iscsi_target_node_add_pg_ig_maps)
1031
1032    def iscsi_target_node_remove_pg_ig_maps(args):
1033        pg_ig_maps = []
1034        for u in args.pg_ig_mappings.strip().split(" "):
1035            pg, ig = u.split(":")
1036            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
1037        rpc.iscsi.iscsi_target_node_remove_pg_ig_maps(
1038            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
1039
1040    p = subparsers.add_parser('iscsi_target_node_remove_pg_ig_maps',
1041                              aliases=['delete_pg_ig_maps'],
1042                              help='Delete PG-IG maps from the target node')
1043    p.add_argument('name', help='Target node name (ASCII)')
1044    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
1045    Whitespace separated, quoted, mapping defined with colon
1046    separated list of "tags" (int > 0)
1047    Example: '1:1 2:2 2:1'
1048    *** The Portal/Initiator Groups must be precreated ***""")
1049    p.set_defaults(func=iscsi_target_node_remove_pg_ig_maps)
1050
1051    def iscsi_create_portal_group(args):
1052        portals = []
1053        for p in args.portal_list.strip().split(' '):
1054            ip, separator, port_cpumask = p.rpartition(':')
1055            split_port_cpumask = port_cpumask.split('@')
1056            if len(split_port_cpumask) == 1:
1057                port = port_cpumask
1058                portals.append({'host': ip, 'port': port})
1059            else:
1060                port = split_port_cpumask[0]
1061                cpumask = split_port_cpumask[1]
1062                portals.append({'host': ip, 'port': port})
1063                print("WARNING: Specifying a portal group with a CPU mask is no longer supported. Ignoring it.")
1064        rpc.iscsi.iscsi_create_portal_group(
1065            args.client,
1066            portals=portals,
1067            tag=args.tag)
1068
1069    p = subparsers.add_parser('iscsi_create_portal_group', aliases=['add_portal_group'],
1070                              help='Add a portal group')
1071    p.add_argument(
1072        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1073    p.add_argument('portal_list', help="""List of portals in host:port format, separated by whitespace
1074    Example: '192.168.100.100:3260 192.168.100.100:3261 192.168.100.100:3262""")
1075    p.set_defaults(func=iscsi_create_portal_group)
1076
1077    def iscsi_create_initiator_group(args):
1078        initiators = []
1079        netmasks = []
1080        for i in args.initiator_list.strip().split(' '):
1081            initiators.append(i)
1082        for n in args.netmask_list.strip().split(' '):
1083            netmasks.append(n)
1084        rpc.iscsi.iscsi_create_initiator_group(
1085            args.client,
1086            tag=args.tag,
1087            initiators=initiators,
1088            netmasks=netmasks)
1089
1090    p = subparsers.add_parser('iscsi_create_initiator_group', aliases=['add_initiator_group'],
1091                              help='Add an initiator group')
1092    p.add_argument(
1093        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1094    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1095    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
1096    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1097    Example: '255.255.0.0 255.248.0.0' etc""")
1098    p.set_defaults(func=iscsi_create_initiator_group)
1099
1100    def iscsi_initiator_group_add_initiators(args):
1101        initiators = None
1102        netmasks = None
1103        if args.initiator_list:
1104            initiators = []
1105            for i in args.initiator_list.strip().split(' '):
1106                initiators.append(i)
1107        if args.netmask_list:
1108            netmasks = []
1109            for n in args.netmask_list.strip().split(' '):
1110                netmasks.append(n)
1111        rpc.iscsi.iscsi_initiator_group_add_initiators(
1112            args.client,
1113            tag=args.tag,
1114            initiators=initiators,
1115            netmasks=netmasks)
1116
1117    p = subparsers.add_parser('iscsi_initiator_group_add_initiators',
1118                              aliases=['add_initiators_to_initiator_group'],
1119                              help='Add initiators to an existing initiator group')
1120    p.add_argument(
1121        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1122    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1123    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
1124    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1125    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1126    p.set_defaults(func=iscsi_initiator_group_add_initiators)
1127
1128    def iscsi_initiator_group_remove_initiators(args):
1129        initiators = None
1130        netmasks = None
1131        if args.initiator_list:
1132            initiators = []
1133            for i in args.initiator_list.strip().split(' '):
1134                initiators.append(i)
1135        if args.netmask_list:
1136            netmasks = []
1137            for n in args.netmask_list.strip().split(' '):
1138                netmasks.append(n)
1139        rpc.iscsi.iscsi_initiator_group_remove_initiators(
1140            args.client,
1141            tag=args.tag,
1142            initiators=initiators,
1143            netmasks=netmasks)
1144
1145    p = subparsers.add_parser('iscsi_initiator_group_remove_initiators',
1146                              aliases=['delete_initiators_from_initiator_group'],
1147                              help='Delete initiators from an existing initiator group')
1148    p.add_argument(
1149        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1150    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
1151    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
1152    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
1153    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
1154    p.set_defaults(func=iscsi_initiator_group_remove_initiators)
1155
1156    def iscsi_delete_target_node(args):
1157        rpc.iscsi.iscsi_delete_target_node(
1158            args.client, target_node_name=args.target_node_name)
1159
1160    p = subparsers.add_parser('iscsi_delete_target_node', aliases=['delete_target_node'],
1161                              help='Delete a target node')
1162    p.add_argument('target_node_name',
1163                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
1164    p.set_defaults(func=iscsi_delete_target_node)
1165
1166    def iscsi_delete_portal_group(args):
1167        rpc.iscsi.iscsi_delete_portal_group(args.client, tag=args.tag)
1168
1169    p = subparsers.add_parser('iscsi_delete_portal_group',
1170                              aliases=['delete_portal_group'],
1171                              help='Delete a portal group')
1172    p.add_argument(
1173        'tag', help='Portal group tag (unique, integer > 0)', type=int)
1174    p.set_defaults(func=iscsi_delete_portal_group)
1175
1176    def iscsi_delete_initiator_group(args):
1177        rpc.iscsi.iscsi_delete_initiator_group(args.client, tag=args.tag)
1178
1179    p = subparsers.add_parser('iscsi_delete_initiator_group',
1180                              aliases=['delete_initiator_group'],
1181                              help='Delete an initiator group')
1182    p.add_argument(
1183        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
1184    p.set_defaults(func=iscsi_delete_initiator_group)
1185
1186    def iscsi_portal_group_set_auth(args):
1187        rpc.iscsi.iscsi_portal_group_set_auth(
1188            args.client,
1189            tag=args.tag,
1190            chap_group=args.chap_group,
1191            disable_chap=args.disable_chap,
1192            require_chap=args.require_chap,
1193            mutual_chap=args.mutual_chap)
1194
1195    p = subparsers.add_parser('iscsi_portal_group_set_auth',
1196                              help='Set CHAP authentication for discovery sessions specific for the portal group')
1197    p.add_argument('tag', help='Portal group tag (unique, integer > 0)', type=int)
1198    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this portal group.
1199    *** Authentication group must be precreated ***""", type=int, default=0)
1200    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this portal group.
1201    *** Mutually exclusive with --require-chap ***""", action='store_true')
1202    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this portal group.
1203    *** Mutually exclusive with --disable-chap ***""", action='store_true')
1204    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
1205                   action='store_true')
1206    p.set_defaults(func=iscsi_portal_group_set_auth)
1207
1208    def iscsi_get_connections(args):
1209        print_dict(rpc.iscsi.iscsi_get_connections(args.client))
1210
1211    p = subparsers.add_parser('iscsi_get_connections', aliases=['get_iscsi_connections'],
1212                              help='Display iSCSI connections')
1213    p.set_defaults(func=iscsi_get_connections)
1214
1215    def iscsi_get_options(args):
1216        print_dict(rpc.iscsi.iscsi_get_options(args.client))
1217
1218    p = subparsers.add_parser('iscsi_get_options', aliases=['get_iscsi_global_params'],
1219                              help='Display iSCSI global parameters')
1220    p.set_defaults(func=iscsi_get_options)
1221
1222    def scsi_get_devices(args):
1223        print_dict(rpc.iscsi.scsi_get_devices(args.client))
1224
1225    p = subparsers.add_parser('scsi_get_devices', aliases=['get_scsi_devices'],
1226                              help='Display SCSI devices')
1227    p.set_defaults(func=scsi_get_devices)
1228
1229    # trace
1230    def trace_enable_tpoint_group(args):
1231        rpc.trace.trace_enable_tpoint_group(args.client, name=args.name)
1232
1233    p = subparsers.add_parser('trace_enable_tpoint_group', aliases=['enable_tpoint_group'],
1234                              help='enable trace on a specific tpoint group')
1235    p.add_argument(
1236        'name', help="""trace group name we want to enable in tpoint_group_mask.
1237        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1238    p.set_defaults(func=trace_enable_tpoint_group)
1239
1240    def trace_disable_tpoint_group(args):
1241        rpc.trace.trace_disable_tpoint_group(args.client, name=args.name)
1242
1243    p = subparsers.add_parser('trace_disable_tpoint_group', aliases=['disable_tpoint_group'],
1244                              help='disable trace on a specific tpoint group')
1245    p.add_argument(
1246        'name', help="""trace group name we want to disable in tpoint_group_mask.
1247        (for example "bdev" for bdev trace group, "all" for all trace groups).""")
1248    p.set_defaults(func=trace_disable_tpoint_group)
1249
1250    def trace_get_tpoint_group_mask(args):
1251        print_dict(rpc.trace.trace_get_tpoint_group_mask(args.client))
1252
1253    p = subparsers.add_parser('trace_get_tpoint_group_mask', aliases=['get_tpoint_group_mask'],
1254                              help='get trace point group mask')
1255    p.set_defaults(func=trace_get_tpoint_group_mask)
1256
1257    # log
1258    def log_set_flag(args):
1259        rpc.log.log_set_flag(args.client, flag=args.flag)
1260
1261    p = subparsers.add_parser('log_set_flag', help='set log flag', aliases=['set_log_flag'])
1262    p.add_argument(
1263        'flag', help='log flag we want to set. (for example "nvme").')
1264    p.set_defaults(func=log_set_flag)
1265
1266    def log_clear_flag(args):
1267        rpc.log.log_clear_flag(args.client, flag=args.flag)
1268
1269    p = subparsers.add_parser('log_clear_flag', help='clear log flag', aliases=['clear_log_flag'])
1270    p.add_argument(
1271        'flag', help='log flag we want to clear. (for example "nvme").')
1272    p.set_defaults(func=log_clear_flag)
1273
1274    def log_get_flags(args):
1275        print_dict(rpc.log.log_get_flags(args.client))
1276
1277    p = subparsers.add_parser('log_get_flags', help='get log flags', aliases=['get_log_flags'])
1278    p.set_defaults(func=log_get_flags)
1279
1280    def log_set_level(args):
1281        rpc.log.log_set_level(args.client, level=args.level)
1282
1283    p = subparsers.add_parser('log_set_level', aliases=['set_log_level'],
1284                              help='set log level')
1285    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
1286    p.set_defaults(func=log_set_level)
1287
1288    def log_get_level(args):
1289        print_dict(rpc.log.log_get_level(args.client))
1290
1291    p = subparsers.add_parser('log_get_level', aliases=['get_log_level'],
1292                              help='get log level')
1293    p.set_defaults(func=log_get_level)
1294
1295    def log_set_print_level(args):
1296        rpc.log.log_set_print_level(args.client, level=args.level)
1297
1298    p = subparsers.add_parser('log_set_print_level', aliases=['set_log_print_level'],
1299                              help='set log print level')
1300    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
1301    p.set_defaults(func=log_set_print_level)
1302
1303    def log_get_print_level(args):
1304        print_dict(rpc.log.log_get_print_level(args.client))
1305
1306    p = subparsers.add_parser('log_get_print_level', aliases=['get_log_print_level'],
1307                              help='get log print level')
1308    p.set_defaults(func=log_get_print_level)
1309
1310    # lvol
1311    def bdev_lvol_create_lvstore(args):
1312        print_json(rpc.lvol.bdev_lvol_create_lvstore(args.client,
1313                                                     bdev_name=args.bdev_name,
1314                                                     lvs_name=args.lvs_name,
1315                                                     cluster_sz=args.cluster_sz,
1316                                                     clear_method=args.clear_method))
1317
1318    p = subparsers.add_parser('bdev_lvol_create_lvstore', aliases=['construct_lvol_store'],
1319                              help='Add logical volume store on base bdev')
1320    p.add_argument('bdev_name', help='base bdev name')
1321    p.add_argument('lvs_name', help='name for lvol store')
1322    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
1323    p.add_argument('--clear-method', help="""Change clear method for data region.
1324        Available: none, unmap, write_zeroes""", required=False)
1325    p.set_defaults(func=bdev_lvol_create_lvstore)
1326
1327    def bdev_lvol_rename_lvstore(args):
1328        rpc.lvol.bdev_lvol_rename_lvstore(args.client,
1329                                          old_name=args.old_name,
1330                                          new_name=args.new_name)
1331
1332    p = subparsers.add_parser('bdev_lvol_rename_lvstore', aliases=['rename_lvol_store'],
1333                              help='Change logical volume store name')
1334    p.add_argument('old_name', help='old name')
1335    p.add_argument('new_name', help='new name')
1336    p.set_defaults(func=bdev_lvol_rename_lvstore)
1337
1338    def bdev_lvol_create(args):
1339        print_json(rpc.lvol.bdev_lvol_create(args.client,
1340                                             lvol_name=args.lvol_name,
1341                                             size=args.size * 1024 * 1024,
1342                                             thin_provision=args.thin_provision,
1343                                             clear_method=args.clear_method,
1344                                             uuid=args.uuid,
1345                                             lvs_name=args.lvs_name))
1346
1347    p = subparsers.add_parser('bdev_lvol_create', aliases=['construct_lvol_bdev'],
1348                              help='Add a bdev with an logical volume backend')
1349    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1350    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1351    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1352    p.add_argument('-c', '--clear-method', help="""Change default data clusters clear method.
1353        Available: none, unmap, write_zeroes""", required=False)
1354    p.add_argument('lvol_name', help='name for this lvol')
1355    p.add_argument('size', help='size in MiB for this bdev', type=int)
1356    p.set_defaults(func=bdev_lvol_create)
1357
1358    def bdev_lvol_snapshot(args):
1359        print_json(rpc.lvol.bdev_lvol_snapshot(args.client,
1360                                               lvol_name=args.lvol_name,
1361                                               snapshot_name=args.snapshot_name))
1362
1363    p = subparsers.add_parser('bdev_lvol_snapshot', aliases=['snapshot_lvol_bdev'],
1364                              help='Create a snapshot of an lvol bdev')
1365    p.add_argument('lvol_name', help='lvol bdev name')
1366    p.add_argument('snapshot_name', help='lvol snapshot name')
1367    p.set_defaults(func=bdev_lvol_snapshot)
1368
1369    def bdev_lvol_clone(args):
1370        print_json(rpc.lvol.bdev_lvol_clone(args.client,
1371                                            snapshot_name=args.snapshot_name,
1372                                            clone_name=args.clone_name))
1373
1374    p = subparsers.add_parser('bdev_lvol_clone', aliases=['clone_lvol_bdev'],
1375                              help='Create a clone of an lvol snapshot')
1376    p.add_argument('snapshot_name', help='lvol snapshot name')
1377    p.add_argument('clone_name', help='lvol clone name')
1378    p.set_defaults(func=bdev_lvol_clone)
1379
1380    def bdev_lvol_rename(args):
1381        rpc.lvol.bdev_lvol_rename(args.client,
1382                                  old_name=args.old_name,
1383                                  new_name=args.new_name)
1384
1385    p = subparsers.add_parser('bdev_lvol_rename', aliases=['rename_lvol_bdev'],
1386                              help='Change lvol bdev name')
1387    p.add_argument('old_name', help='lvol bdev name')
1388    p.add_argument('new_name', help='new lvol name')
1389    p.set_defaults(func=bdev_lvol_rename)
1390
1391    def bdev_lvol_inflate(args):
1392        rpc.lvol.bdev_lvol_inflate(args.client,
1393                                   name=args.name)
1394
1395    p = subparsers.add_parser('bdev_lvol_inflate', aliases=['inflate_lvol_bdev'],
1396                              help='Make thin provisioned lvol a thick provisioned lvol')
1397    p.add_argument('name', help='lvol bdev name')
1398    p.set_defaults(func=bdev_lvol_inflate)
1399
1400    def bdev_lvol_decouple_parent(args):
1401        rpc.lvol.bdev_lvol_decouple_parent(args.client,
1402                                           name=args.name)
1403
1404    p = subparsers.add_parser('bdev_lvol_decouple_parent', aliases=['decouple_parent_lvol_bdev'],
1405                              help='Decouple parent of lvol')
1406    p.add_argument('name', help='lvol bdev name')
1407    p.set_defaults(func=bdev_lvol_decouple_parent)
1408
1409    def bdev_lvol_resize(args):
1410        rpc.lvol.bdev_lvol_resize(args.client,
1411                                  name=args.name,
1412                                  size=args.size * 1024 * 1024)
1413
1414    p = subparsers.add_parser('bdev_lvol_resize', aliases=['resize_lvol_bdev'],
1415                              help='Resize existing lvol bdev')
1416    p.add_argument('name', help='lvol bdev name')
1417    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1418    p.set_defaults(func=bdev_lvol_resize)
1419
1420    def bdev_lvol_set_read_only(args):
1421        rpc.lvol.bdev_lvol_set_read_only(args.client,
1422                                         name=args.name)
1423
1424    p = subparsers.add_parser('bdev_lvol_set_read_only', aliases=['set_read_only_lvol_bdev'],
1425                              help='Mark lvol bdev as read only')
1426    p.add_argument('name', help='lvol bdev name')
1427    p.set_defaults(func=bdev_lvol_set_read_only)
1428
1429    def bdev_lvol_delete(args):
1430        rpc.lvol.bdev_lvol_delete(args.client,
1431                                  name=args.name)
1432
1433    p = subparsers.add_parser('bdev_lvol_delete', aliases=['destroy_lvol_bdev'],
1434                              help='Destroy a logical volume')
1435    p.add_argument('name', help='lvol bdev name')
1436    p.set_defaults(func=bdev_lvol_delete)
1437
1438    def bdev_lvol_delete_lvstore(args):
1439        rpc.lvol.bdev_lvol_delete_lvstore(args.client,
1440                                          uuid=args.uuid,
1441                                          lvs_name=args.lvs_name)
1442
1443    p = subparsers.add_parser('bdev_lvol_delete_lvstore', aliases=['destroy_lvol_store'],
1444                              help='Destroy an logical volume store')
1445    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1446    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1447    p.set_defaults(func=bdev_lvol_delete_lvstore)
1448
1449    def bdev_lvol_get_lvstores(args):
1450        print_dict(rpc.lvol.bdev_lvol_get_lvstores(args.client,
1451                                                   uuid=args.uuid,
1452                                                   lvs_name=args.lvs_name))
1453
1454    p = subparsers.add_parser('bdev_lvol_get_lvstores', aliases=['get_lvol_stores'],
1455                              help='Display current logical volume store list')
1456    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1457    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1458    p.set_defaults(func=bdev_lvol_get_lvstores)
1459
1460    def bdev_raid_get_bdevs(args):
1461        print_array(rpc.bdev.bdev_raid_get_bdevs(args.client,
1462                                                 category=args.category))
1463
1464    p = subparsers.add_parser('bdev_raid_get_bdevs', aliases=['get_raid_bdevs'],
1465                              help="""This is used to list all the raid bdev names based on the input category
1466    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1467    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1468    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1469    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1470    p.add_argument('category', help='all or online or configuring or offline')
1471    p.set_defaults(func=bdev_raid_get_bdevs)
1472
1473    def bdev_raid_create(args):
1474        base_bdevs = []
1475        for u in args.base_bdevs.strip().split(" "):
1476            base_bdevs.append(u)
1477
1478        rpc.bdev.bdev_raid_create(args.client,
1479                                  name=args.name,
1480                                  strip_size=args.strip_size,
1481                                  strip_size_kb=args.strip_size_kb,
1482                                  raid_level=args.raid_level,
1483                                  base_bdevs=base_bdevs)
1484    p = subparsers.add_parser('bdev_raid_create', aliases=['construct_raid_bdev'],
1485                              help='Create new raid bdev')
1486    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1487    p.add_argument('-s', '--strip-size', help='strip size in KB (deprecated)', type=int)
1488    p.add_argument('-z', '--strip-size_kb', help='strip size in KB', type=int)
1489    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', required=True)
1490    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1491    p.set_defaults(func=bdev_raid_create)
1492
1493    def bdev_raid_delete(args):
1494        rpc.bdev.bdev_raid_delete(args.client,
1495                                  name=args.name)
1496    p = subparsers.add_parser('bdev_raid_delete', aliases=['destroy_raid_bdev'],
1497                              help='Delete existing raid bdev')
1498    p.add_argument('name', help='raid bdev name')
1499    p.set_defaults(func=bdev_raid_delete)
1500
1501    # split
1502    def bdev_split_create(args):
1503        print_array(rpc.bdev.bdev_split_create(args.client,
1504                                               base_bdev=args.base_bdev,
1505                                               split_count=args.split_count,
1506                                               split_size_mb=args.split_size_mb))
1507
1508    p = subparsers.add_parser('bdev_split_create', aliases=['construct_split_vbdev'],
1509                              help="""Add given disk name to split config. If bdev with base_name
1510    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1511    available (during examination process).""")
1512    p.add_argument('base_bdev', help='base bdev name')
1513    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1514    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1515    exceed the base bdev size.""", type=int)
1516    p.set_defaults(func=bdev_split_create)
1517
1518    def bdev_split_delete(args):
1519        rpc.bdev.bdev_split_delete(args.client,
1520                                   base_bdev=args.base_bdev)
1521
1522    p = subparsers.add_parser('bdev_split_delete', aliases=['destruct_split_vbdev'],
1523                              help="""Delete split config with all created splits.""")
1524    p.add_argument('base_bdev', help='base bdev name')
1525    p.set_defaults(func=bdev_split_delete)
1526
1527    # ftl
1528    ftl_valid_limits = ('crit', 'high', 'low', 'start')
1529
1530    def bdev_ftl_create(args):
1531        def parse_limits(limits, arg_dict, key_suffix=''):
1532            for limit in limits.split(','):
1533                key, value = limit.split(':', 1)
1534                if key in ftl_valid_limits:
1535                    arg_dict['limit_' + key + key_suffix] = int(value)
1536                else:
1537                    raise ValueError('Limit {} is not supported'.format(key))
1538
1539        arg_limits = {}
1540        if args.limit_threshold:
1541            parse_limits(args.limit_threshold, arg_limits, '_threshold')
1542
1543        if args.limit:
1544            parse_limits(args.limit, arg_limits)
1545
1546        print_dict(rpc.bdev.bdev_ftl_create(args.client,
1547                                            name=args.name,
1548                                            base_bdev=args.base_bdev,
1549                                            uuid=args.uuid,
1550                                            cache=args.cache,
1551                                            allow_open_bands=args.allow_open_bands,
1552                                            overprovisioning=args.overprovisioning,
1553                                            use_append=args.use_append,
1554                                            **arg_limits))
1555
1556    p = subparsers.add_parser('bdev_ftl_create', aliases=['construct_ftl_bdev'], help='Add FTL bdev')
1557    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1558    p.add_argument('-d', '--base_bdev', help='Name of zoned bdev used as underlying device',
1559                   required=True)
1560    p.add_argument('-u', '--uuid', help='UUID of restored bdev (not applicable when creating new '
1561                   'instance): e.g. b286d19a-0059-4709-abcd-9f7732b1567d (optional)')
1562    p.add_argument('-c', '--cache', help='Name of the bdev to be used as a write buffer cache (optional)')
1563    p.add_argument('-o', '--allow_open_bands', help='Restoring after dirty shutdown without cache will'
1564                   ' result in partial data recovery, instead of error', action='store_true')
1565    p.add_argument('--overprovisioning', help='Percentage of device used for relocation, not exposed'
1566                   ' to user (optional)', type=int)
1567    p.add_argument('--use_append', help='Use appends instead of writes', action='store_true')
1568
1569    limits = p.add_argument_group('Defrag limits', 'Configures defrag limits and thresholds for'
1570                                  ' levels ' + str(ftl_valid_limits)[1:-1])
1571    limits.add_argument('--limit', help='Percentage of allowed user versus internal writes at given'
1572                        ' levels, e.g. crit:0,high:20,low:80')
1573    limits.add_argument('--limit-threshold', help='Number of free bands triggering a given level of'
1574                        ' write limiting e.g. crit:1,high:2,low:3,start:4')
1575    p.set_defaults(func=bdev_ftl_create)
1576
1577    def bdev_ftl_delete(args):
1578        print_dict(rpc.bdev.bdev_ftl_delete(args.client, name=args.name))
1579
1580    p = subparsers.add_parser('bdev_ftl_delete', aliases=['delete_ftl_bdev'],
1581                              help='Delete FTL bdev')
1582    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
1583    p.set_defaults(func=bdev_ftl_delete)
1584
1585    # vmd
1586    def enable_vmd(args):
1587        print_dict(rpc.vmd.enable_vmd(args.client))
1588
1589    p = subparsers.add_parser('enable_vmd', help='Enable VMD enumeration')
1590    p.set_defaults(func=enable_vmd)
1591
1592    # nbd
1593    def nbd_start_disk(args):
1594        print(rpc.nbd.nbd_start_disk(args.client,
1595                                     bdev_name=args.bdev_name,
1596                                     nbd_device=args.nbd_device))
1597
1598    p = subparsers.add_parser('nbd_start_disk', aliases=['start_nbd_disk'],
1599                              help='Export a bdev as an nbd disk')
1600    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1601    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.', nargs='?')
1602    p.set_defaults(func=nbd_start_disk)
1603
1604    def nbd_stop_disk(args):
1605        rpc.nbd.nbd_stop_disk(args.client,
1606                              nbd_device=args.nbd_device)
1607
1608    p = subparsers.add_parser('nbd_stop_disk', aliases=['stop_nbd_disk'],
1609                              help='Stop an nbd disk')
1610    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1611    p.set_defaults(func=nbd_stop_disk)
1612
1613    def nbd_get_disks(args):
1614        print_dict(rpc.nbd.nbd_get_disks(args.client,
1615                                         nbd_device=args.nbd_device))
1616
1617    p = subparsers.add_parser('nbd_get_disks', aliases=['get_nbd_disks'],
1618                              help='Display full or specified nbd device list')
1619    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1620    p.set_defaults(func=nbd_get_disks)
1621
1622    # net
1623    def net_interface_add_ip_address(args):
1624        rpc.net.net_interface_add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1625
1626    p = subparsers.add_parser('net_interface_add_ip_address', aliases=['add_ip_address'],
1627                              help='Add IP address')
1628    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1629    p.add_argument('ip_addr', help='ip address will be added.')
1630    p.set_defaults(func=net_interface_add_ip_address)
1631
1632    def net_interface_delete_ip_address(args):
1633        rpc.net.net_interface_delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1634
1635    p = subparsers.add_parser('net_interface_delete_ip_address', aliases=['delete_ip_address'],
1636                              help='Delete IP address')
1637    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1638    p.add_argument('ip_addr', help='ip address will be deleted.')
1639    p.set_defaults(func=net_interface_delete_ip_address)
1640
1641    def net_get_interfaces(args):
1642        print_dict(rpc.net.net_get_interfaces(args.client))
1643
1644    p = subparsers.add_parser(
1645        'net_get_interfaces', aliases=['get_interfaces'], help='Display current interface list')
1646    p.set_defaults(func=net_get_interfaces)
1647
1648    # NVMe-oF
1649    def nvmf_set_max_subsystems(args):
1650        rpc.nvmf.nvmf_set_max_subsystems(args.client,
1651                                         max_subsystems=args.max_subsystems)
1652
1653    p = subparsers.add_parser('nvmf_set_max_subsystems', aliases=['set_nvmf_target_max_subsystems'],
1654                              help='Set the maximum number of NVMf target subsystems')
1655    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True)
1656    p.set_defaults(func=nvmf_set_max_subsystems)
1657
1658    def nvmf_set_config(args):
1659        rpc.nvmf.nvmf_set_config(args.client,
1660                                 acceptor_poll_rate=args.acceptor_poll_rate,
1661                                 conn_sched=args.conn_sched,
1662                                 passthru_identify_ctrlr=args.passthru_identify_ctrlr)
1663
1664    p = subparsers.add_parser('nvmf_set_config', aliases=['set_nvmf_target_config'],
1665                              help='Set NVMf target config')
1666    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1667    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1668    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1669    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1670    robin manner. 'transport' - Schedule the connection according to the transport characteristics.""")
1671    p.add_argument('-i', '--passthru-identify-ctrlr', help="""Passthrough fields like serial number and model number
1672    when the controller has a single namespace that is an NVMe bdev""", action='store_true')
1673    p.set_defaults(func=nvmf_set_config)
1674
1675    def nvmf_create_transport(args):
1676        rpc.nvmf.nvmf_create_transport(args.client,
1677                                       trtype=args.trtype,
1678                                       tgt_name=args.tgt_name,
1679                                       max_queue_depth=args.max_queue_depth,
1680                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1681                                       in_capsule_data_size=args.in_capsule_data_size,
1682                                       max_io_size=args.max_io_size,
1683                                       io_unit_size=args.io_unit_size,
1684                                       max_aq_depth=args.max_aq_depth,
1685                                       num_shared_buffers=args.num_shared_buffers,
1686                                       buf_cache_size=args.buf_cache_size,
1687                                       max_srq_depth=args.max_srq_depth,
1688                                       no_srq=args.no_srq,
1689                                       c2h_success=args.c2h_success,
1690                                       dif_insert_or_strip=args.dif_insert_or_strip,
1691                                       sock_priority=args.sock_priority)
1692
1693    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1694    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1695    p.add_argument('-g', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1696    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1697    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1698    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1699    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1700    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1701    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1702    p.add_argument('-n', '--num-shared-buffers', help='The number of pooled data buffers available to the transport', type=int)
1703    p.add_argument('-b', '--buf-cache-size', help='The number of shared buffers to reserve for each poll group', type=int)
1704    p.add_argument('-s', '--max-srq-depth', help='Max number of outstanding I/O per SRQ. Relevant only for RDMA transport', type=int)
1705    p.add_argument('-r', '--no-srq', action='store_true', help='Disable per-thread shared receive queue. Relevant only for RDMA transport')
1706    p.add_argument('-o', '--c2h-success', action='store_false', help='Disable C2H success optimization. Relevant only for TCP transport')
1707    p.add_argument('-f', '--dif-insert-or-strip', action='store_true', help='Enable DIF insert/strip. Relevant only for TCP transport')
1708    p.add_argument('-y', '--sock-priority', help='The sock priority of the tcp connection. Relevant only for TCP transport', type=int)
1709    p.set_defaults(func=nvmf_create_transport)
1710
1711    def nvmf_get_transports(args):
1712        print_dict(rpc.nvmf.nvmf_get_transports(args.client, tgt_name=args.tgt_name))
1713
1714    p = subparsers.add_parser('nvmf_get_transports', aliases=['get_nvmf_transports'],
1715                              help='Display nvmf transports')
1716    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1717    p.set_defaults(func=nvmf_get_transports)
1718
1719    def nvmf_get_subsystems(args):
1720        print_dict(rpc.nvmf.nvmf_get_subsystems(args.client, tgt_name=args.tgt_name))
1721
1722    p = subparsers.add_parser('nvmf_get_subsystems', aliases=['get_nvmf_subsystems'],
1723                              help='Display nvmf subsystems')
1724    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1725    p.set_defaults(func=nvmf_get_subsystems)
1726
1727    def nvmf_create_subsystem(args):
1728        rpc.nvmf.nvmf_create_subsystem(args.client,
1729                                       nqn=args.nqn,
1730                                       tgt_name=args.tgt_name,
1731                                       serial_number=args.serial_number,
1732                                       model_number=args.model_number,
1733                                       allow_any_host=args.allow_any_host,
1734                                       max_namespaces=args.max_namespaces)
1735
1736    p = subparsers.add_parser('nvmf_create_subsystem', aliases=['nvmf_subsystem_create'],
1737                              help='Create an NVMe-oF subsystem')
1738    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1739    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1740    p.add_argument("-s", "--serial-number", help="""
1741    Format:  'sn' etc
1742    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1743    p.add_argument("-d", "--model-number", help="""
1744    Format:  'mn' etc
1745    Example: 'SPDK Controller'""", default='SPDK bdev Controller')
1746    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1747    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1748                   type=int, default=0)
1749    p.set_defaults(func=nvmf_create_subsystem)
1750
1751    def nvmf_delete_subsystem(args):
1752        rpc.nvmf.nvmf_delete_subsystem(args.client,
1753                                       nqn=args.subsystem_nqn,
1754                                       tgt_name=args.tgt_name)
1755
1756    p = subparsers.add_parser('nvmf_delete_subsystem', aliases=['delete_nvmf_subsystem'],
1757                              help='Delete a nvmf subsystem')
1758    p.add_argument('subsystem_nqn',
1759                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1760    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1761    p.set_defaults(func=nvmf_delete_subsystem)
1762
1763    def nvmf_subsystem_add_listener(args):
1764        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1765                                             nqn=args.nqn,
1766                                             trtype=args.trtype,
1767                                             traddr=args.traddr,
1768                                             tgt_name=args.tgt_name,
1769                                             adrfam=args.adrfam,
1770                                             trsvcid=args.trsvcid)
1771
1772    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1773    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1774    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1775    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1776    p.add_argument('-p', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1777    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1778    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1779    p.set_defaults(func=nvmf_subsystem_add_listener)
1780
1781    def nvmf_subsystem_remove_listener(args):
1782        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1783                                                nqn=args.nqn,
1784                                                trtype=args.trtype,
1785                                                traddr=args.traddr,
1786                                                tgt_name=args.tgt_name,
1787                                                adrfam=args.adrfam,
1788                                                trsvcid=args.trsvcid)
1789
1790    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1791    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1792    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1793    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1794    p.add_argument('-p', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1795    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1796    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1797    p.set_defaults(func=nvmf_subsystem_remove_listener)
1798
1799    def nvmf_subsystem_add_ns(args):
1800        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1801                                       nqn=args.nqn,
1802                                       bdev_name=args.bdev_name,
1803                                       tgt_name=args.tgt_name,
1804                                       ptpl_file=args.ptpl_file,
1805                                       nsid=args.nsid,
1806                                       nguid=args.nguid,
1807                                       eui64=args.eui64,
1808                                       uuid=args.uuid)
1809
1810    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1811    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1812    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1813    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1814    p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str)
1815    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1816    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1817    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1818    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1819    p.set_defaults(func=nvmf_subsystem_add_ns)
1820
1821    def nvmf_subsystem_remove_ns(args):
1822        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1823                                          nqn=args.nqn,
1824                                          nsid=args.nsid,
1825                                          tgt_name=args.tgt_name)
1826
1827    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1828    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1829    p.add_argument('nsid', help='The requested NSID', type=int)
1830    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1831    p.set_defaults(func=nvmf_subsystem_remove_ns)
1832
1833    def nvmf_subsystem_add_host(args):
1834        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1835                                         nqn=args.nqn,
1836                                         host=args.host,
1837                                         tgt_name=args.tgt_name)
1838
1839    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1840    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1841    p.add_argument('host', help='Host NQN to allow')
1842    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1843    p.set_defaults(func=nvmf_subsystem_add_host)
1844
1845    def nvmf_subsystem_remove_host(args):
1846        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1847                                            nqn=args.nqn,
1848                                            host=args.host,
1849                                            tgt_name=args.tgt_name)
1850
1851    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1852    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1853    p.add_argument('host', help='Host NQN to remove')
1854    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1855    p.set_defaults(func=nvmf_subsystem_remove_host)
1856
1857    def nvmf_subsystem_allow_any_host(args):
1858        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1859                                               nqn=args.nqn,
1860                                               disable=args.disable,
1861                                               tgt_name=args.tgt_name)
1862
1863    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1864    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1865    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1866    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1867    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1868    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1869
1870    def nvmf_get_stats(args):
1871        print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))
1872
1873    p = subparsers.add_parser(
1874        'nvmf_get_stats', help='Display current statistics for NVMf subsystem')
1875    p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str)
1876    p.set_defaults(func=nvmf_get_stats)
1877
1878    # pmem
1879    def bdev_pmem_create_pool(args):
1880        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1881        rpc.pmem.bdev_pmem_create_pool(args.client,
1882                                       pmem_file=args.pmem_file,
1883                                       num_blocks=num_blocks,
1884                                       block_size=args.block_size)
1885
1886    p = subparsers.add_parser('bdev_pmem_create_pool', aliases=['create_pmem_pool'],
1887                              help='Create pmem pool')
1888    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1889    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1890    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1891    p.set_defaults(func=bdev_pmem_create_pool)
1892
1893    def bdev_pmem_get_pool_info(args):
1894        print_dict(rpc.pmem.bdev_pmem_get_pool_info(args.client,
1895                                                    pmem_file=args.pmem_file))
1896
1897    p = subparsers.add_parser('bdev_pmem_get_pool_info', aliases=['pmem_pool_info'],
1898                              help='Display pmem pool info and check consistency')
1899    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1900    p.set_defaults(func=bdev_pmem_get_pool_info)
1901
1902    def bdev_pmem_delete_pool(args):
1903        rpc.pmem.bdev_pmem_delete_pool(args.client,
1904                                       pmem_file=args.pmem_file)
1905
1906    p = subparsers.add_parser('bdev_pmem_delete_pool', aliases=['delete_pmem_pool'],
1907                              help='Delete pmem pool')
1908    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1909    p.set_defaults(func=bdev_pmem_delete_pool)
1910
1911    # subsystem
1912    def framework_get_subsystems(args):
1913        print_dict(rpc.subsystem.framework_get_subsystems(args.client))
1914
1915    p = subparsers.add_parser('framework_get_subsystems', aliases=['get_subsystems'],
1916                              help="""Print subsystems array in initialization order. Each subsystem
1917    entry contain (unsorted) array of subsystems it depends on.""")
1918    p.set_defaults(func=framework_get_subsystems)
1919
1920    def framework_get_config(args):
1921        print_dict(rpc.subsystem.framework_get_config(args.client, args.name))
1922
1923    p = subparsers.add_parser('framework_get_config', aliases=['get_subsystem_config'],
1924                              help="""Print subsystem configuration""")
1925    p.add_argument('name', help='Name of subsystem to query')
1926    p.set_defaults(func=framework_get_config)
1927
1928    # vhost
1929    def vhost_controller_set_coalescing(args):
1930        rpc.vhost.vhost_controller_set_coalescing(args.client,
1931                                                  ctrlr=args.ctrlr,
1932                                                  delay_base_us=args.delay_base_us,
1933                                                  iops_threshold=args.iops_threshold)
1934
1935    p = subparsers.add_parser('vhost_controller_set_coalescing', aliases=['set_vhost_controller_coalescing'],
1936                              help='Set vhost controller coalescing')
1937    p.add_argument('ctrlr', help='controller name')
1938    p.add_argument('delay_base_us', help='Base delay time', type=int)
1939    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1940    p.set_defaults(func=vhost_controller_set_coalescing)
1941
1942    def vhost_create_scsi_controller(args):
1943        rpc.vhost.vhost_create_scsi_controller(args.client,
1944                                               ctrlr=args.ctrlr,
1945                                               cpumask=args.cpumask)
1946
1947    p = subparsers.add_parser(
1948        'vhost_create_scsi_controller', aliases=['construct_vhost_scsi_controller'],
1949        help='Add new vhost controller')
1950    p.add_argument('ctrlr', help='controller name')
1951    p.add_argument('--cpumask', help='cpu mask for this controller')
1952    p.set_defaults(func=vhost_create_scsi_controller)
1953
1954    def vhost_scsi_controller_add_target(args):
1955        print_json(rpc.vhost.vhost_scsi_controller_add_target(args.client,
1956                                                              ctrlr=args.ctrlr,
1957                                                              scsi_target_num=args.scsi_target_num,
1958                                                              bdev_name=args.bdev_name))
1959
1960    p = subparsers.add_parser('vhost_scsi_controller_add_target',
1961                              aliases=['add_vhost_scsi_lun'],
1962                              help='Add lun to vhost controller')
1963    p.add_argument('ctrlr', help='conntroller name where add lun')
1964    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1965    p.add_argument('bdev_name', help='bdev name')
1966    p.set_defaults(func=vhost_scsi_controller_add_target)
1967
1968    def vhost_scsi_controller_remove_target(args):
1969        rpc.vhost.vhost_scsi_controller_remove_target(args.client,
1970                                                      ctrlr=args.ctrlr,
1971                                                      scsi_target_num=args.scsi_target_num)
1972
1973    p = subparsers.add_parser('vhost_scsi_controller_remove_target',
1974                              aliases=['remove_vhost_scsi_target'],
1975                              help='Remove target from vhost controller')
1976    p.add_argument('ctrlr', help='controller name to remove target from')
1977    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1978    p.set_defaults(func=vhost_scsi_controller_remove_target)
1979
1980    def vhost_create_blk_controller(args):
1981        rpc.vhost.vhost_create_blk_controller(args.client,
1982                                              ctrlr=args.ctrlr,
1983                                              dev_name=args.dev_name,
1984                                              cpumask=args.cpumask,
1985                                              readonly=args.readonly)
1986
1987    p = subparsers.add_parser('vhost_create_blk_controller',
1988                              aliases=['construct_vhost_blk_controller'],
1989                              help='Add a new vhost block controller')
1990    p.add_argument('ctrlr', help='controller name')
1991    p.add_argument('dev_name', help='device name')
1992    p.add_argument('--cpumask', help='cpu mask for this controller')
1993    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1994    p.set_defaults(func=vhost_create_blk_controller)
1995
1996    def vhost_create_nvme_controller(args):
1997        rpc.vhost.vhost_create_nvme_controller(args.client,
1998                                               ctrlr=args.ctrlr,
1999                                               io_queues=args.io_queues,
2000                                               cpumask=args.cpumask)
2001
2002    p = subparsers.add_parser('vhost_create_nvme_controller', aliases=['vhost_create_nvme_controller'],
2003                              help='Add new vhost controller')
2004    p.add_argument('ctrlr', help='controller name')
2005    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
2006    p.add_argument('--cpumask', help='cpu mask for this controller')
2007    p.set_defaults(func=vhost_create_nvme_controller)
2008
2009    def vhost_nvme_controller_add_ns(args):
2010        rpc.vhost.vhost_nvme_controller_add_ns(args.client,
2011                                               ctrlr=args.ctrlr,
2012                                               bdev_name=args.bdev_name)
2013
2014    p = subparsers.add_parser('vhost_nvme_controller_add_ns', aliases=['add_vhost_nvme_ns'],
2015                              help='Add a Namespace to vhost controller')
2016    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
2017    p.add_argument('bdev_name', help='block device name for a new Namespace')
2018    p.set_defaults(func=vhost_nvme_controller_add_ns)
2019
2020    def vhost_get_controllers(args):
2021        print_dict(rpc.vhost.vhost_get_controllers(args.client, args.name))
2022
2023    p = subparsers.add_parser('vhost_get_controllers', aliases=['get_vhost_controllers'],
2024                              help='List all or specific vhost controller(s)')
2025    p.add_argument('-n', '--name', help="Name of vhost controller", required=False)
2026    p.set_defaults(func=vhost_get_controllers)
2027
2028    def vhost_delete_controller(args):
2029        rpc.vhost.vhost_delete_controller(args.client,
2030                                          ctrlr=args.ctrlr)
2031
2032    p = subparsers.add_parser('vhost_delete_controller', aliases=['remove_vhost_controller'],
2033                              help='Delete a vhost controller')
2034    p.add_argument('ctrlr', help='controller name')
2035    p.set_defaults(func=vhost_delete_controller)
2036
2037    def bdev_virtio_attach_controller(args):
2038        print_array(rpc.vhost.bdev_virtio_attach_controller(args.client,
2039                                                            name=args.name,
2040                                                            trtype=args.trtype,
2041                                                            traddr=args.traddr,
2042                                                            dev_type=args.dev_type,
2043                                                            vq_count=args.vq_count,
2044                                                            vq_size=args.vq_size))
2045
2046    p = subparsers.add_parser('bdev_virtio_attach_controller', aliases=['construct_virtio_dev'],
2047                              help="""Attach virtio controller using provided
2048    transport type and device type. This will also create bdevs for any block devices connected to the
2049    controller (for example, SCSI devices for a virtio-scsi controller).
2050    Result is array of added bdevs.""")
2051    p.add_argument('name', help="Use this name as base for new created bdevs")
2052    p.add_argument('-t', '--trtype',
2053                   help='Virtio target transport type: pci or user', required=True)
2054    p.add_argument('-a', '--traddr',
2055                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
2056    p.add_argument('-d', '--dev-type',
2057                   help='Device type: blk or scsi', required=True)
2058    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
2059    p.add_argument('--vq-size', help='Size of each queue', type=int)
2060    p.set_defaults(func=bdev_virtio_attach_controller)
2061
2062    def bdev_virtio_scsi_get_devices(args):
2063        print_dict(rpc.vhost.bdev_virtio_scsi_get_devices(args.client))
2064
2065    p = subparsers.add_parser('bdev_virtio_scsi_get_devices', aliases=['get_virtio_scsi_devs'],
2066                              help='List all Virtio-SCSI devices.')
2067    p.set_defaults(func=bdev_virtio_scsi_get_devices)
2068
2069    def bdev_virtio_detach_controller(args):
2070        rpc.vhost.bdev_virtio_detach_controller(args.client,
2071                                                name=args.name)
2072
2073    p = subparsers.add_parser('bdev_virtio_detach_controller', aliases=['remove_virtio_bdev'],
2074                              help="""Remove a Virtio device
2075    This will delete all bdevs exposed by this device""")
2076    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
2077    p.set_defaults(func=bdev_virtio_detach_controller)
2078
2079    # OCSSD
2080    def bdev_ocssd_create(args):
2081        nsid = int(args.nsid) if args.nsid is not None else None
2082        print_json(rpc.bdev.bdev_ocssd_create(args.client,
2083                                              ctrlr_name=args.ctrlr_name,
2084                                              bdev_name=args.name,
2085                                              nsid=nsid,
2086                                              range=args.range))
2087
2088    p = subparsers.add_parser('bdev_ocssd_create',
2089                              help='Creates zoned bdev on specified Open Channel controller')
2090    p.add_argument('-c', '--ctrlr_name', help='Name of the OC NVMe controller', required=True)
2091    p.add_argument('-b', '--name', help='Name of the bdev to create', required=True)
2092    p.add_argument('-n', '--nsid', help='Namespace ID', required=False)
2093    p.add_argument('-r', '--range', help='Parallel unit range (in the form of BEGIN-END (inclusive))',
2094                   required=False)
2095    p.set_defaults(func=bdev_ocssd_create)
2096
2097    def bdev_ocssd_delete(args):
2098        print_json(rpc.bdev.bdev_ocssd_delete(args.client,
2099                                              name=args.name))
2100
2101    p = subparsers.add_parser('bdev_ocssd_delete',
2102                              help='Deletes Open Channel bdev')
2103    p.add_argument('name', help='Name of the Open Channel bdev')
2104    p.set_defaults(func=bdev_ocssd_delete)
2105
2106    # accel framework
2107    def accel_set_module(args):
2108        rpc.accel.accel_set_module(args.client,
2109                                   module=args.module)
2110
2111    p = subparsers.add_parser('accel_set_module',
2112                              help='Set module option for the accelerator framework')
2113    p.add_argument('-m', '--module', type=int, help='0 = auto-select, 1= Software, 2 = CBDMA')
2114    p.set_defaults(func=accel_set_module)
2115
2116    # ioat
2117    def ioat_scan_accel_engine(args):
2118        pci_whitelist = []
2119        if args.pci_whitelist:
2120            for w in args.pci_whitelist.strip().split(" "):
2121                pci_whitelist.append(w)
2122        rpc.ioat.ioat_scan_accel_engine(args.client, pci_whitelist)
2123
2124    p = subparsers.add_parser('ioat_scan_accel_engine',
2125                              aliases=['ioat_scan_copy_engine', 'scan_ioat_copy_engine'],
2126                              help='Set scan and enable IOAT accel engine offload.')
2127    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
2128    domain:bus:device.function format or domain.bus.device.function format""")
2129    p.set_defaults(func=ioat_scan_accel_engine)
2130
2131    # opal
2132    def bdev_nvme_opal_init(args):
2133        rpc.nvme.bdev_nvme_opal_init(args.client,
2134                                     nvme_ctrlr_name=args.nvme_ctrlr_name,
2135                                     password=args.password)
2136
2137    p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
2138    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2139    p.add_argument('-p', '--password', help='password for admin')
2140    p.set_defaults(func=bdev_nvme_opal_init)
2141
2142    def bdev_nvme_opal_revert(args):
2143        rpc.nvme.bdev_nvme_opal_revert(args.client,
2144                                       nvme_ctrlr_name=args.nvme_ctrlr_name,
2145                                       password=args.password)
2146    p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
2147    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
2148    p.add_argument('-p', '--password', help='password')
2149    p.set_defaults(func=bdev_nvme_opal_revert)
2150
2151    def bdev_opal_create(args):
2152        print_json(rpc.bdev.bdev_opal_create(args.client,
2153                                             nvme_ctrlr_name=args.nvme_ctrlr_name,
2154                                             nsid=args.nsid,
2155                                             locking_range_id=args.locking_range_id,
2156                                             range_start=args.range_start,
2157                                             range_length=args.range_length,
2158                                             password=args.password))
2159
2160    p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""")
2161    p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True)
2162    p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True)
2163    p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True)
2164    p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True)
2165    p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True)
2166    p.add_argument('-p', '--password', help='admin password', required=True)
2167    p.set_defaults(func=bdev_opal_create)
2168
2169    def bdev_opal_get_info(args):
2170        print_dict(rpc.bdev.bdev_opal_get_info(args.client,
2171                                               bdev_name=args.bdev_name,
2172                                               password=args.password))
2173
2174    p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
2175    p.add_argument('-b', '--bdev-name', help='opal bdev')
2176    p.add_argument('-p', '--password', help='password')
2177    p.set_defaults(func=bdev_opal_get_info)
2178
2179    def bdev_opal_delete(args):
2180        rpc.bdev.bdev_opal_delete(args.client,
2181                                  bdev_name=args.bdev_name,
2182                                  password=args.password)
2183
2184    p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""")
2185    p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True)
2186    p.add_argument('-p', '--password', help='admin password', required=True)
2187    p.set_defaults(func=bdev_opal_delete)
2188
2189    def bdev_opal_new_user(args):
2190        rpc.bdev.bdev_opal_new_user(args.client,
2191                                    bdev_name=args.bdev_name,
2192                                    admin_password=args.admin_password,
2193                                    user_id=args.user_id,
2194                                    user_password=args.user_password)
2195
2196    p = subparsers.add_parser('bdev_opal_new_user', help="""Add a user to opal bdev who can set lock state for this bdev""")
2197    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
2198    p.add_argument('-p', '--admin-password', help='admin password', required=True)
2199    p.add_argument('-i', '--user-id', help='ID for new user', type=int, required=True)
2200    p.add_argument('-u', '--user-password', help='password set for this user', required=True)
2201    p.set_defaults(func=bdev_opal_new_user)
2202
2203    def bdev_opal_set_lock_state(args):
2204        rpc.bdev.bdev_opal_set_lock_state(args.client,
2205                                          bdev_name=args.bdev_name,
2206                                          user_id=args.user_id,
2207                                          password=args.password,
2208                                          lock_state=args.lock_state)
2209
2210    p = subparsers.add_parser('bdev_opal_set_lock_state', help="""set lock state for an opal bdev""")
2211    p.add_argument('-b', '--bdev-name', help='opal bdev', required=True)
2212    p.add_argument('-i', '--user-id', help='ID of the user who want to set lock state, either admin or a user assigned to this bdev',
2213                   type=int, required=True)
2214    p.add_argument('-p', '--password', help='password of this user', required=True)
2215    p.add_argument('-l', '--lock-state', help='lock state to set, choose from {readwrite, readonly, rwlock}', required=True)
2216    p.set_defaults(func=bdev_opal_set_lock_state)
2217
2218    # bdev_nvme_send_cmd
2219    def bdev_nvme_send_cmd(args):
2220        print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client,
2221                                               name=args.nvme_name,
2222                                               cmd_type=args.cmd_type,
2223                                               data_direction=args.data_direction,
2224                                               cmdbuf=args.cmdbuf,
2225                                               data=args.data,
2226                                               metadata=args.metadata,
2227                                               data_len=args.data_length,
2228                                               metadata_len=args.metadata_length,
2229                                               timeout_ms=args.timeout_ms))
2230
2231    p = subparsers.add_parser('bdev_nvme_send_cmd', aliases=['send_nvme_cmd'],
2232                              help='NVMe passthrough cmd.')
2233    p.add_argument('-n', '--nvme-name', help="""Name of the operating NVMe controller""")
2234    p.add_argument('-t', '--cmd-type', help="""Type of nvme cmd. Valid values are: admin, io""")
2235    p.add_argument('-r', '--data-direction', help="""Direction of data transfer. Valid values are: c2h, h2c""")
2236    p.add_argument('-c', '--cmdbuf', help="""NVMe command encoded by base64 urlsafe""")
2237    p.add_argument('-d', '--data', help="""Data transferring to controller from host, encoded by base64 urlsafe""")
2238    p.add_argument('-m', '--metadata', help="""Metadata transferring to controller from host, encoded by base64 urlsafe""")
2239    p.add_argument('-D', '--data-length', help="""Data length required to transfer from controller to host""", type=int)
2240    p.add_argument('-M', '--metadata-length', help="""Metadata length required to transfer from controller to host""", type=int)
2241    p.add_argument('-T', '--timeout-ms',
2242                   help="""Command execution timeout value, in milliseconds,  if 0, don't track timeout""", type=int, default=0)
2243    p.set_defaults(func=bdev_nvme_send_cmd)
2244
2245    # Notifications
2246    def notify_get_types(args):
2247        print_dict(rpc.notify.notify_get_types(args.client))
2248
2249    p = subparsers.add_parser('notify_get_types', aliases=['get_notification_types'],
2250                              help='List available notifications that user can subscribe to.')
2251    p.set_defaults(func=notify_get_types)
2252
2253    def notify_get_notifications(args):
2254        ret = rpc.notify.notify_get_notifications(args.client,
2255                                                  id=args.id,
2256                                                  max=args.max)
2257        print_dict(ret)
2258
2259    p = subparsers.add_parser('notify_get_notifications', aliases=['get_notifications'],
2260                              help='Get notifications')
2261    p.add_argument('-i', '--id', help="""First ID to start fetching from""", type=int)
2262    p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int)
2263    p.set_defaults(func=notify_get_notifications)
2264
2265    def thread_get_stats(args):
2266        print_dict(rpc.app.thread_get_stats(args.client))
2267
2268    p = subparsers.add_parser(
2269        'thread_get_stats', help='Display current statistics of all the threads')
2270    p.set_defaults(func=thread_get_stats)
2271
2272    def thread_set_cpumask(args):
2273        ret = rpc.app.thread_set_cpumask(args.client,
2274                                         id=args.id,
2275                                         cpumask=args.cpumask)
2276    p = subparsers.add_parser('thread_set_cpumask',
2277                              help="""set the cpumask of the thread whose ID matches to the
2278    specified value. The thread may be migrated to one of the specified CPUs.""")
2279    p.add_argument('-i', '--id', type=int, help='thread ID')
2280    p.add_argument('-m', '--cpumask', help='cpumask for this thread')
2281    p.set_defaults(func=thread_set_cpumask)
2282
2283    def env_dpdk_get_mem_stats(args):
2284        print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client))
2285
2286    p = subparsers.add_parser(
2287        'env_dpdk_get_mem_stats', help='write the dpdk memory stats to a file.')
2288    p.set_defaults(func=env_dpdk_get_mem_stats)
2289
2290    # blobfs
2291    def blobfs_detect(args):
2292        print(rpc.blobfs.blobfs_detect(args.client,
2293                                       bdev_name=args.bdev_name))
2294
2295    p = subparsers.add_parser('blobfs_detect', help='Detect whether a blobfs exists on bdev')
2296    p.add_argument('bdev_name', help='Blockdev name to detect blobfs. Example: Malloc0.')
2297    p.set_defaults(func=blobfs_detect)
2298
2299    def blobfs_create(args):
2300        print(rpc.blobfs.blobfs_create(args.client,
2301                                       bdev_name=args.bdev_name,
2302                                       cluster_sz=args.cluster_sz))
2303
2304    p = subparsers.add_parser('blobfs_create', help='Build a blobfs on bdev')
2305    p.add_argument('bdev_name', help='Blockdev name to build blobfs. Example: Malloc0.')
2306    p.add_argument('-c', '--cluster_sz',
2307                   help="""Size of cluster in bytes (Optional). Must be multiple of 4KB page size. Default and minimal value is 1M.""")
2308    p.set_defaults(func=blobfs_create)
2309
2310    def blobfs_mount(args):
2311        print(rpc.blobfs.blobfs_mount(args.client,
2312                                      bdev_name=args.bdev_name,
2313                                      mountpoint=args.mountpoint))
2314
2315    p = subparsers.add_parser('blobfs_mount', help='Mount a blobfs on bdev to host path by FUSE')
2316    p.add_argument('bdev_name', help='Blockdev name where the blobfs is. Example: Malloc0.')
2317    p.add_argument('mountpoint', help='Mountpoint path in host to mount blobfs. Example: /mnt/.')
2318    p.set_defaults(func=blobfs_mount)
2319
2320    def blobfs_set_cache_size(args):
2321        print(rpc.blobfs.blobfs_set_cache_size(args.client,
2322                                               size_in_mb=args.size_in_mb))
2323
2324    p = subparsers.add_parser('blobfs_set_cache_size', help='Set cache size for blobfs')
2325    p.add_argument('size_in_mb', help='Cache size for blobfs in megabytes.', type=int)
2326    p.set_defaults(func=blobfs_set_cache_size)
2327
2328    def check_called_name(name):
2329        if name in deprecated_aliases:
2330            print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr)
2331
2332    class dry_run_client:
2333        def call(self, method, params=None):
2334            print("Request:\n" + json.dumps({"method": method, "params": params}, indent=2))
2335
2336    def null_print(arg):
2337        pass
2338
2339    def call_rpc_func(args):
2340        args.func(args)
2341        check_called_name(args.called_rpc_name)
2342
2343    def execute_script(parser, client, fd):
2344        executed_rpc = ""
2345        for rpc_call in map(str.rstrip, fd):
2346            if not rpc_call.strip():
2347                continue
2348            executed_rpc = "\n".join([executed_rpc, rpc_call])
2349            args = parser.parse_args(shlex.split(rpc_call))
2350            args.client = client
2351            try:
2352                call_rpc_func(args)
2353            except JSONRPCException as ex:
2354                print("Exception:")
2355                print(executed_rpc.strip() + " <<<")
2356                print(ex.message)
2357                exit(1)
2358
2359    args = parser.parse_args()
2360    if args.dry_run:
2361        args.client = dry_run_client()
2362        print_dict = null_print
2363        print_json = null_print
2364        print_array = null_print
2365    else:
2366        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper()))
2367    if hasattr(args, 'func'):
2368        try:
2369            call_rpc_func(args)
2370        except JSONRPCException as ex:
2371            print(ex.message)
2372            exit(1)
2373    elif sys.stdin.isatty():
2374        # No arguments and no data piped through stdin
2375        parser.print_help()
2376        exit(1)
2377    else:
2378        execute_script(parser, args.client, sys.stdin)
2379