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