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