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