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