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