xref: /spdk/scripts/rpc.py (revision 7d030ef7fc9ec09d7e66a966eac0fcec5c1bd8bb)
1#!/usr/bin/env python3
2
3from rpc.client import print_dict, JSONRPCException
4
5import argparse
6import rpc
7
8try:
9    from shlex import quote
10except ImportError:
11    from pipes import quote
12
13
14def print_array(a):
15    print(" ".join((quote(v) for v in a)))
16
17
18def call_cmd(func):
19    def rpc_cmd(*args, **kwargs):
20        try:
21            func(*args, **kwargs)
22        except JSONRPCException as ex:
23            print(ex.message)
24            exit(1)
25    return rpc_cmd
26
27
28if __name__ == "__main__":
29    parser = argparse.ArgumentParser(
30        description='SPDK RPC command line interface')
31    parser.add_argument('-s', dest='server_addr',
32                        help='RPC server address', default='/var/tmp/spdk.sock')
33    parser.add_argument('-p', dest='port',
34                        help='RPC port number (if server_addr is IP address)',
35                        default=5260, type=int)
36    parser.add_argument('-t', dest='timeout',
37                        help='Timout as a floating point number expressed in seconds waiting for reponse. Default: 60.0',
38                        default=60.0, type=float)
39    parser.add_argument('-v', dest='verbose',
40                        help='Verbose mode', action='store_true')
41    subparsers = parser.add_subparsers(help='RPC methods')
42
43    @call_cmd
44    def start_subsystem_init(args):
45        rpc.start_subsystem_init(args.client)
46
47    p = subparsers.add_parser('start_subsystem_init', help='Start initialization of subsystems')
48    p.set_defaults(func=start_subsystem_init)
49
50    @call_cmd
51    def get_rpc_methods(args):
52        print_dict(rpc.get_rpc_methods(args.client,
53                                       current=args.current))
54
55    p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods')
56    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
57    p.set_defaults(func=get_rpc_methods)
58
59    @call_cmd
60    def save_config(args):
61        rpc.save_config(args.client,
62                        indent=args.indent)
63
64    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets to stdout.
65    """)
66    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
67    """, type=int, default=2)
68    p.set_defaults(func=save_config)
69
70    @call_cmd
71    def load_config(args):
72        rpc.load_config(args.client)
73
74    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and targets using JSON RPC read from stdin.""")
75    p.set_defaults(func=load_config)
76
77    @call_cmd
78    def save_subsystem_config(args):
79        rpc.save_subsystem_config(args.client,
80                                  indent=args.indent,
81                                  name=args.name)
82
83    p = subparsers.add_parser('save_subsystem_config', help="""Write current (live) configuration of SPDK subsystem to stdout.
84    """)
85    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. Default indent level is 2.
86    """, type=int, default=2)
87    p.add_argument('-n', '--name', help='Name of subsystem', required=True)
88    p.set_defaults(func=save_subsystem_config)
89
90    @call_cmd
91    def load_subsystem_config(args):
92        rpc.load_subsystem_config(args.client)
93
94    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC read from stdin.""")
95    p.set_defaults(func=load_subsystem_config)
96
97    # app
98    @call_cmd
99    def kill_instance(args):
100        rpc.app.kill_instance(args.client,
101                              sig_name=args.sig_name)
102
103    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
104    p.add_argument('sig_name', help='signal will be sent to server.')
105    p.set_defaults(func=kill_instance)
106
107    @call_cmd
108    def context_switch_monitor(args):
109        enabled = None
110        if args.enable:
111            enabled = True
112        if args.disable:
113            enabled = False
114        print_dict(rpc.app.context_switch_monitor(args.client,
115                                                  enabled=enabled))
116
117    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
118    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
119    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
120    p.set_defaults(func=context_switch_monitor)
121
122    # bdev
123    @call_cmd
124    def set_bdev_options(args):
125        rpc.bdev.set_bdev_options(args.client,
126                                  bdev_io_pool_size=args.bdev_io_pool_size,
127                                  bdev_io_cache_size=args.bdev_io_cache_size)
128
129    p = subparsers.add_parser('set_bdev_options', help="""Set options of bdev subsystem""")
130    p.add_argument('-p', '--bdev-io-pool-size', help='Number of bdev_io structures in shared buffer pool', type=int)
131    p.add_argument('-c', '--bdev-io-cache-size', help='Maximum number of bdev_io structures cached per thread', type=int)
132    p.set_defaults(func=set_bdev_options)
133
134    @call_cmd
135    def construct_crypto_bdev(args):
136        print(rpc.bdev.construct_crypto_bdev(args.client,
137                                             base_bdev_name=args.base_bdev_name,
138                                             name=args.name,
139                                             crypto_pmd=args.crypto_pmd,
140                                             key=args.key))
141    p = subparsers.add_parser('construct_crypto_bdev',
142                              help='Add a crypto vbdev')
143    p.add_argument('-b', '--base_bdev_name', help="Name of the base bdev")
144    p.add_argument('-c', '--name', help="Name of the crypto vbdev")
145    p.add_argument('-d', '--crypto_pmd', help="Name of the crypto device driver")
146    p.add_argument('-k', '--key', help="Key")
147    p.set_defaults(func=construct_crypto_bdev)
148
149    @call_cmd
150    def delete_crypto_bdev(args):
151        rpc.bdev.delete_crypto_bdev(args.client,
152                                    name=args.name)
153
154    p = subparsers.add_parser('delete_crypto_bdev', help='Delete a crypto disk')
155    p.add_argument('name', help='crypto bdev name')
156    p.set_defaults(func=delete_crypto_bdev)
157
158    @call_cmd
159    def construct_malloc_bdev(args):
160        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
161        print(rpc.bdev.construct_malloc_bdev(args.client,
162                                             num_blocks=int(num_blocks),
163                                             block_size=args.block_size,
164                                             name=args.name,
165                                             uuid=args.uuid))
166    p = subparsers.add_parser('construct_malloc_bdev',
167                              help='Add a bdev with malloc backend')
168    p.add_argument('-b', '--name', help="Name of the bdev")
169    p.add_argument('-u', '--uuid', help="UUID of the bdev")
170    p.add_argument(
171        'total_size', help='Size of malloc bdev in MB (float > 0)', type=float)
172    p.add_argument('block_size', help='Block size for this bdev', type=int)
173    p.set_defaults(func=construct_malloc_bdev)
174
175    @call_cmd
176    def delete_malloc_bdev(args):
177        rpc.bdev.delete_malloc_bdev(args.client,
178                                    name=args.name)
179
180    p = subparsers.add_parser('delete_malloc_bdev', help='Delete a malloc disk')
181    p.add_argument('name', help='malloc bdev name')
182    p.set_defaults(func=delete_malloc_bdev)
183
184    @call_cmd
185    def construct_null_bdev(args):
186        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
187        print(rpc.bdev.construct_null_bdev(args.client,
188                                           num_blocks=num_blocks,
189                                           block_size=args.block_size,
190                                           name=args.name,
191                                           uuid=args.uuid))
192
193    p = subparsers.add_parser('construct_null_bdev',
194                              help='Add a bdev with null backend')
195    p.add_argument('name', help='Block device name')
196    p.add_argument('-u', '--uuid', help='UUID of the bdev')
197    p.add_argument(
198        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
199    p.add_argument('block_size', help='Block size for this bdev', type=int)
200    p.set_defaults(func=construct_null_bdev)
201
202    @call_cmd
203    def delete_null_bdev(args):
204        rpc.bdev.delete_null_bdev(args.client,
205                                  name=args.name)
206
207    p = subparsers.add_parser('delete_null_bdev', help='Delete a null bdev')
208    p.add_argument('name', help='null bdev name')
209    p.set_defaults(func=delete_null_bdev)
210
211    @call_cmd
212    def construct_aio_bdev(args):
213        print(rpc.bdev.construct_aio_bdev(args.client,
214                                          filename=args.filename,
215                                          name=args.name,
216                                          block_size=args.block_size))
217
218    p = subparsers.add_parser('construct_aio_bdev',
219                              help='Add a bdev with aio backend')
220    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
221    p.add_argument('name', help='Block device name')
222    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
223    p.set_defaults(func=construct_aio_bdev)
224
225    @call_cmd
226    def delete_aio_bdev(args):
227        rpc.bdev.delete_aio_bdev(args.client,
228                                 name=args.name)
229
230    p = subparsers.add_parser('delete_aio_bdev', help='Delete an aio disk')
231    p.add_argument('name', help='aio bdev name')
232    p.set_defaults(func=delete_aio_bdev)
233
234    @call_cmd
235    def set_bdev_nvme_options(args):
236        rpc.bdev.set_bdev_nvme_options(args.client,
237                                       action_on_timeout=args.action_on_timeout,
238                                       timeout_us=args.timeout_us,
239                                       retry_count=args.retry_count,
240                                       nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us)
241
242    p = subparsers.add_parser('set_bdev_nvme_options',
243                              help='Set options for the bdev nvme type. This is startup command.')
244    p.add_argument('-a', '--action-on-timeout',
245                   help="Action to take on command time out. Valid valies are: none, reset, abort")
246    p.add_argument('-t', '--timeout-us',
247                   help="Timeout for each command, in microseconds. If 0, don't track timeouts.", type=int)
248    p.add_argument('-n', '--retry-count',
249                   help='the number of attempts per I/O when an I/O fails', type=int)
250    p.add_argument('-p', '--nvme-adminq-poll-period-us',
251                   help='How often the admin queue is polled for asynchronous events', type=int)
252    p.set_defaults(func=set_bdev_nvme_options)
253
254    @call_cmd
255    def set_bdev_nvme_hotplug(args):
256        rpc.bdev.set_bdev_nvme_hotplug(args.client, enable=args.enable, period_us=args.period_us)
257
258    p = subparsers.add_parser('set_bdev_nvme_hotplug',
259                              help='Set hotplug options for bdev nvme type.')
260    p.add_argument('-d', '--disable', dest='enable', default=False, action='store_false', help="Disable hotplug (default)")
261    p.add_argument('-e', '--enable', dest='enable', action='store_true', help="Enable hotplug")
262    p.add_argument('-r', '--period-us',
263                   help='How often the hotplug is processed for insert and remove events', type=int)
264    p.set_defaults(func=set_bdev_nvme_hotplug)
265
266    @call_cmd
267    def construct_nvme_bdev(args):
268        print_array(rpc.bdev.construct_nvme_bdev(args.client,
269                                                 name=args.name,
270                                                 trtype=args.trtype,
271                                                 traddr=args.traddr,
272                                                 adrfam=args.adrfam,
273                                                 trsvcid=args.trsvcid,
274                                                 subnqn=args.subnqn))
275
276    p = subparsers.add_parser('construct_nvme_bdev',
277                              help='Add bdev with nvme backend')
278    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
279    p.add_argument('-t', '--trtype',
280                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
281    p.add_argument('-a', '--traddr',
282                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
283    p.add_argument('-f', '--adrfam',
284                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
285    p.add_argument('-s', '--trsvcid',
286                   help='NVMe-oF target trsvcid: e.g., a port number')
287    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
288    p.set_defaults(func=construct_nvme_bdev)
289
290    @call_cmd
291    def delete_nvme_controller(args):
292        rpc.bdev.delete_nvme_controller(args.client,
293                                        name=args.name)
294
295    p = subparsers.add_parser('delete_nvme_controller',
296                              help='Delete a NVMe controller using controller name')
297    p.add_argument('name', help="Name of the controller")
298    p.set_defaults(func=delete_nvme_controller)
299
300    @call_cmd
301    def construct_rbd_bdev(args):
302        print(rpc.bdev.construct_rbd_bdev(args.client,
303                                          name=args.name,
304                                          pool_name=args.pool_name,
305                                          rbd_name=args.rbd_name,
306                                          block_size=args.block_size))
307
308    p = subparsers.add_parser('construct_rbd_bdev',
309                              help='Add a bdev with ceph rbd backend')
310    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
311    p.add_argument('pool_name', help='rbd pool name')
312    p.add_argument('rbd_name', help='rbd image name')
313    p.add_argument('block_size', help='rbd block size', type=int)
314    p.set_defaults(func=construct_rbd_bdev)
315
316    @call_cmd
317    def delete_rbd_bdev(args):
318        rpc.bdev.delete_rbd_bdev(args.client,
319                                 name=args.name)
320
321    p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev')
322    p.add_argument('name', help='rbd bdev name')
323    p.set_defaults(func=delete_rbd_bdev)
324
325    @call_cmd
326    def construct_error_bdev(args):
327        print(rpc.bdev.construct_error_bdev(args.client,
328                                            base_name=args.base_name))
329
330    p = subparsers.add_parser('construct_error_bdev',
331                              help='Add bdev with error injection backend')
332    p.add_argument('base_name', help='base bdev name')
333    p.set_defaults(func=construct_error_bdev)
334
335    @call_cmd
336    def delete_error_bdev(args):
337        rpc.bdev.delete_error_bdev(args.client,
338                                   name=args.name)
339
340    p = subparsers.add_parser('delete_error_bdev', help='Delete an error bdev')
341    p.add_argument('name', help='error bdev name')
342    p.set_defaults(func=delete_error_bdev)
343
344    @call_cmd
345    def construct_iscsi_bdev(args):
346        print(rpc.bdev.construct_iscsi_bdev(args.client,
347                                            name=args.name,
348                                            url=args.url,
349                                            initiator_iqn=args.initiator_iqn))
350
351    p = subparsers.add_parser('construct_iscsi_bdev',
352                              help='Add bdev with iSCSI initiator backend')
353    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
354    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
355    p.add_argument('--url', help="iSCSI Lun URL", required=True)
356    p.set_defaults(func=construct_iscsi_bdev)
357
358    @call_cmd
359    def delete_iscsi_bdev(args):
360        rpc.bdev.delete_iscsi_bdev(args.client,
361                                   name=args.name)
362
363    p = subparsers.add_parser('delete_iscsi_bdev', help='Delete an iSCSI bdev')
364    p.add_argument('name', help='iSCSI bdev name')
365    p.set_defaults(func=delete_iscsi_bdev)
366
367    @call_cmd
368    def construct_pmem_bdev(args):
369        print(rpc.bdev.construct_pmem_bdev(args.client,
370                                           pmem_file=args.pmem_file,
371                                           name=args.name))
372
373    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
374    p.add_argument('pmem_file', help='Path to pmemblk pool file')
375    p.add_argument('-n', '--name', help='Block device name', required=True)
376    p.set_defaults(func=construct_pmem_bdev)
377
378    @call_cmd
379    def delete_pmem_bdev(args):
380        rpc.bdev.delete_pmem_bdev(args.client,
381                                  name=args.name)
382
383    p = subparsers.add_parser('delete_pmem_bdev', help='Delete a pmem bdev')
384    p.add_argument('name', help='pmem bdev name')
385    p.set_defaults(func=delete_pmem_bdev)
386
387    @call_cmd
388    def construct_passthru_bdev(args):
389        print(rpc.bdev.construct_passthru_bdev(args.client,
390                                               base_bdev_name=args.base_bdev_name,
391                                               passthru_bdev_name=args.passthru_bdev_name))
392
393    p = subparsers.add_parser('construct_passthru_bdev',
394                              help='Add a pass through bdev on existing bdev')
395    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
396    p.add_argument('-p', '--passthru-bdev-name', help="Name of the pass through bdev", required=True)
397    p.set_defaults(func=construct_passthru_bdev)
398
399    @call_cmd
400    def delete_passthru_bdev(args):
401        rpc.bdev.delete_passthru_bdev(args.client,
402                                      name=args.name)
403
404    p = subparsers.add_parser('delete_passthru_bdev', help='Delete a pass through bdev')
405    p.add_argument('name', help='pass through bdev name')
406    p.set_defaults(func=delete_passthru_bdev)
407
408    @call_cmd
409    def get_bdevs(args):
410        print_dict(rpc.bdev.get_bdevs(args.client,
411                                      name=args.name))
412
413    p = subparsers.add_parser(
414        'get_bdevs', help='Display current blockdev list or required blockdev')
415    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
416    p.set_defaults(func=get_bdevs)
417
418    @call_cmd
419    def get_bdevs_iostat(args):
420        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
421                                             name=args.name))
422
423    p = subparsers.add_parser(
424        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
425    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
426    p.set_defaults(func=get_bdevs_iostat)
427
428    @call_cmd
429    def delete_bdev(args):
430        rpc.bdev.delete_bdev(args.client,
431                             bdev_name=args.bdev_name)
432
433    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
434    p.add_argument(
435        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
436    p.set_defaults(func=delete_bdev)
437
438    @call_cmd
439    def set_bdev_qd_sampling_period(args):
440        rpc.bdev.set_bdev_qd_sampling_period(args.client,
441                                             name=args.name,
442                                             period=args.period)
443
444    p = subparsers.add_parser('set_bdev_qd_sampling_period', help="Enable or disable tracking of a bdev's queue depth.")
445    p.add_argument('name', help='Blockdev name. Example: Malloc0')
446    p.add_argument('period', help='Period with which to poll the block device queue depth in microseconds.'
447                   ' If set to 0, polling will be disabled.',
448                   type=int)
449    p.set_defaults(func=set_bdev_qd_sampling_period)
450
451    @call_cmd
452    def set_bdev_qos_limit_iops(args):
453        rpc.bdev.set_bdev_qos_limit_iops(args.client,
454                                         name=args.name,
455                                         ios_per_sec=args.ios_per_sec)
456
457    p = subparsers.add_parser('set_bdev_qos_limit_iops', help='Set QoS IOPS limit on a blockdev')
458    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
459    p.add_argument('ios_per_sec',
460                   help='IOs per second limit (>=10000, example: 20000). 0 means unlimited.', type=int)
461    p.set_defaults(func=set_bdev_qos_limit_iops)
462
463    @call_cmd
464    def bdev_inject_error(args):
465        rpc.bdev.bdev_inject_error(args.client,
466                                   name=args.name,
467                                   io_type=args.io_type,
468                                   error_type=args.error_type,
469                                   num=args.num)
470
471    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
472    p.add_argument('name', help="""the name of the error injection bdev""")
473    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
474    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
475    p.add_argument(
476        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
477    p.set_defaults(func=bdev_inject_error)
478
479    @call_cmd
480    def apply_firmware(args):
481        print_dict(rpc.bdev.apply_firmware(args.client,
482                                           bdev_name=args.bdev_name,
483                                           filename=args.filename))
484
485    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
486    p.add_argument('filename', help='filename of the firmware to download')
487    p.add_argument('bdev_name', help='name of the NVMe device')
488    p.set_defaults(func=apply_firmware)
489
490    # iSCSI
491    @call_cmd
492    def set_iscsi_options(args):
493        rpc.iscsi.set_iscsi_options(
494            args.client,
495            auth_file=args.auth_file,
496            node_base=args.node_base,
497            nop_timeout=args.nop_timeout,
498            nop_in_interval=args.nop_in_interval,
499            disable_chap=args.disable_chap,
500            require_chap=args.require_chap,
501            mutual_chap=args.mutual_chap,
502            chap_group=args.chap_group,
503            max_sessions=args.max_sessions,
504            max_queue_depth=args.max_queue_depth,
505            max_connections_per_session=args.max_connections_per_session,
506            default_time2wait=args.default_time2wait,
507            default_time2retain=args.default_time2retain,
508            first_burst_length=args.first_burst_length,
509            immediate_data=args.immediate_data,
510            error_recovery_level=args.error_recovery_level,
511            allow_duplicated_isid=args.allow_duplicated_isid,
512            min_connections_per_core=args.min_connections_per_core)
513
514    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
515    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file')
516    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
517    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
518    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
519    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
520    *** Mutually exclusive with --require-chap""", action='store_true')
521    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
522    *** Mutually exclusive with --disable-chap""", action='store_true')
523    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
524    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
525    *** Authentication group must be precreated ***""", type=int)
526    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
527    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/Os per queue.', type=int)
528    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
529    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
530    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
531    p.add_argument('-s', '--first-burst-length', help='Negotiated parameter, FirstBurstLength.', type=int)
532    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
533    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
534    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
535    p.add_argument('-u', '--min-connections-per-core', help='Allocation unit of connections per core', type=int)
536    p.set_defaults(func=set_iscsi_options)
537
538    @call_cmd
539    def set_iscsi_discovery_auth(args):
540        rpc.iscsi.set_iscsi_discovery_auth(
541            args.client,
542            disable_chap=args.disable_chap,
543            require_chap=args.require_chap,
544            mutual_chap=args.mutual_chap,
545            chap_group=args.chap_group)
546
547    p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""")
548    p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled.
549    *** Mutually exclusive with --require-chap""", action='store_true')
550    p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required.
551    *** Mutually exclusive with --disable-chap""", action='store_true')
552    p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true')
553    p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session.
554    *** Authentication group must be precreated ***""", type=int)
555    p.set_defaults(func=set_iscsi_discovery_auth)
556
557    def add_iscsi_auth_group(args):
558        secrets = None
559        if args.secrets:
560            secrets = [dict(u.split(":") for u in a.split(" ")) for a in args.secrets.split(",")]
561
562        rpc.iscsi.add_iscsi_auth_group(args.client, tag=args.tag, secrets=secrets)
563
564    p = subparsers.add_parser('add_iscsi_auth_group', help='Add authentication group for CHAP authentication.')
565    p.add_argument('tag', help='Authentication group tag (unique, integer > 0).', type=int)
566    p.add_argument('-c', '--secrets', help="""Comma-separated list of CHAP secrets
567<user:user_name secret:chap_secret muser:mutual_user_name msecret:mutual_chap_secret> enclosed in quotes.
568Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 msecret:ms2'""", required=False)
569    p.set_defaults(func=add_iscsi_auth_group)
570
571    @call_cmd
572    def delete_iscsi_auth_group(args):
573        rpc.iscsi.delete_iscsi_auth_group(args.client, tag=args.tag)
574
575    p = subparsers.add_parser('delete_iscsi_auth_group', help='Delete an authentication group.')
576    p.add_argument('tag', help='Authentication group tag', type=int)
577    p.set_defaults(func=delete_iscsi_auth_group)
578
579    @call_cmd
580    def add_secret_to_iscsi_auth_group(args):
581        rpc.iscsi.add_secret_to_iscsi_auth_group(
582            args.client,
583            tag=args.tag,
584            user=args.user,
585            secret=args.secret,
586            muser=args.muser,
587            msecret=args.msecret)
588
589    p = subparsers.add_parser('add_secret_to_iscsi_auth_group', help='Add a secret to an authentication group.')
590    p.add_argument('tag', help='Authentication group tag', type=int)
591    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
592    p.add_argument('-s', '--secret', help='Secret for one-way CHAP authentication', required=True)
593    p.add_argument('-m', '--muser', help='User name for mutual CHAP authentication')
594    p.add_argument('-r', '--msecret', help='Secret for mutual CHAP authentication')
595    p.set_defaults(func=add_secret_to_iscsi_auth_group)
596
597    @call_cmd
598    def delete_secret_from_iscsi_auth_group(args):
599        rpc.iscsi.delete_secret_from_iscsi_auth_group(args.client, tag=args.tag, user=args.user)
600
601    p = subparsers.add_parser('delete_secret_from_iscsi_auth_group', help='Delete a secret from an authentication group.')
602    p.add_argument('tag', help='Authentication group tag', type=int)
603    p.add_argument('-u', '--user', help='User name for one-way CHAP authentication', required=True)
604    p.set_defaults(func=delete_secret_from_iscsi_auth_group)
605
606    @call_cmd
607    def get_iscsi_auth_groups(args):
608        print_dict(rpc.iscsi.get_iscsi_auth_groups(args.client))
609
610    p = subparsers.add_parser('get_iscsi_auth_groups',
611                              help='Display current authentication group configuration')
612    p.set_defaults(func=get_iscsi_auth_groups)
613
614    @call_cmd
615    def get_portal_groups(args):
616        print_dict(rpc.iscsi.get_portal_groups(args.client))
617
618    p = subparsers.add_parser(
619        'get_portal_groups', help='Display current portal group configuration')
620    p.set_defaults(func=get_portal_groups)
621
622    @call_cmd
623    def get_initiator_groups(args):
624        print_dict(rpc.iscsi.get_initiator_groups(args.client))
625
626    p = subparsers.add_parser('get_initiator_groups',
627                              help='Display current initiator group configuration')
628    p.set_defaults(func=get_initiator_groups)
629
630    @call_cmd
631    def get_target_nodes(args):
632        print_dict(rpc.iscsi.get_target_nodes(args.client))
633
634    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
635    p.set_defaults(func=get_target_nodes)
636
637    @call_cmd
638    def construct_target_node(args):
639        luns = []
640        for u in args.bdev_name_id_pairs.strip().split(" "):
641            bdev_name, lun_id = u.split(":")
642            luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)})
643
644        pg_ig_maps = []
645        for u in args.pg_ig_mappings.strip().split(" "):
646            pg, ig = u.split(":")
647            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
648
649        rpc.iscsi.construct_target_node(
650            args.client,
651            luns=luns,
652            pg_ig_maps=pg_ig_maps,
653            name=args.name,
654            alias_name=args.alias_name,
655            queue_depth=args.queue_depth,
656            chap_group=args.chap_group,
657            disable_chap=args.disable_chap,
658            require_chap=args.require_chap,
659            mutual_chap=args.mutual_chap,
660            header_digest=args.header_digest,
661            data_digest=args.data_digest)
662
663    p = subparsers.add_parser('construct_target_node',
664                              help='Add a target node')
665    p.add_argument('name', help='Target node name (ASCII)')
666    p.add_argument('alias_name', help='Target node alias name (ASCII)')
667    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
668    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
669    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
670    *** The bdevs must pre-exist ***
671    *** LUN0 (id = 0) is required ***
672    *** bdevs names cannot contain space or colon characters ***""")
673    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
674    Whitespace separated, quoted, mapping defined with colon
675    separated list of "tags" (int > 0)
676    Example: '1:1 2:2 2:1'
677    *** The Portal/Initiator Groups must be precreated ***""")
678    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
679    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
680    *** Authentication group must be precreated ***""", type=int, default=0)
681    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
682    *** Mutually exclusive with --require-chap ***""", action='store_true')
683    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
684    *** Mutually exclusive with --disable-chap ***""", action='store_true')
685    p.add_argument(
686        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
687    p.add_argument('-H', '--header-digest',
688                   help='Header Digest should be required for this target node.', action='store_true')
689    p.add_argument('-D', '--data-digest',
690                   help='Data Digest should be required for this target node.', action='store_true')
691    p.set_defaults(func=construct_target_node)
692
693    @call_cmd
694    def target_node_add_lun(args):
695        rpc.iscsi.target_node_add_lun(
696            args.client,
697            name=args.name,
698            bdev_name=args.bdev_name,
699            lun_id=args.lun_id)
700
701    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
702    p.add_argument('name', help='Target node name (ASCII)')
703    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
704    *** bdev name cannot contain space or colon characters ***""")
705    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
706    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
707    p.set_defaults(func=target_node_add_lun)
708
709    @call_cmd
710    def set_iscsi_target_node_auth(args):
711        rpc.iscsi.set_iscsi_target_node_auth(
712            args.client,
713            name=args.name,
714            chap_group=args.chap_group,
715            disable_chap=args.disable_chap,
716            require_chap=args.require_chap,
717            mutual_chap=args.mutual_chap)
718
719    p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node')
720    p.add_argument('name', help='Target node name (ASCII)')
721    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
722    *** Authentication group must be precreated ***""", type=int, default=0)
723    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
724    *** Mutually exclusive with --require-chap ***""", action='store_true')
725    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
726    *** Mutually exclusive with --disable-chap ***""", action='store_true')
727    p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.',
728                   action='store_true')
729    p.set_defaults(func=set_iscsi_target_node_auth)
730
731    @call_cmd
732    def add_pg_ig_maps(args):
733        pg_ig_maps = []
734        for u in args.pg_ig_mappings.strip().split(" "):
735            pg, ig = u.split(":")
736            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
737        rpc.iscsi.add_pg_ig_maps(
738            args.client,
739            pg_ig_maps=pg_ig_maps,
740            name=args.name)
741
742    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
743    p.add_argument('name', help='Target node name (ASCII)')
744    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
745    Whitespace separated, quoted, mapping defined with colon
746    separated list of "tags" (int > 0)
747    Example: '1:1 2:2 2:1'
748    *** The Portal/Initiator Groups must be precreated ***""")
749    p.set_defaults(func=add_pg_ig_maps)
750
751    @call_cmd
752    def delete_pg_ig_maps(args):
753        pg_ig_maps = []
754        for u in args.pg_ig_mappings.strip().split(" "):
755            pg, ig = u.split(":")
756            pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)})
757        rpc.iscsi.delete_pg_ig_maps(
758            args.client, pg_ig_maps=pg_ig_maps, name=args.name)
759
760    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
761    p.add_argument('name', help='Target node name (ASCII)')
762    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
763    Whitespace separated, quoted, mapping defined with colon
764    separated list of "tags" (int > 0)
765    Example: '1:1 2:2 2:1'
766    *** The Portal/Initiator Groups must be precreated ***""")
767    p.set_defaults(func=delete_pg_ig_maps)
768
769    @call_cmd
770    def add_portal_group(args):
771        portals = []
772        for p in args.portal_list:
773            ip, separator, port_cpumask = p.rpartition(':')
774            split_port_cpumask = port_cpumask.split('@')
775            if len(split_port_cpumask) == 1:
776                port = port_cpumask
777                portals.append({'host': ip, 'port': port})
778            else:
779                port = split_port_cpumask[0]
780                cpumask = split_port_cpumask[1]
781                portals.append({'host': ip, 'port': port, 'cpumask': cpumask})
782        rpc.iscsi.add_portal_group(
783            args.client,
784            portals=portals,
785            tag=args.tag)
786
787    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
788    p.add_argument(
789        'tag', help='Portal group tag (unique, integer > 0)', type=int)
790    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
791    (cpumask is optional and can be skipped)
792    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
793    p.set_defaults(func=add_portal_group)
794
795    @call_cmd
796    def add_initiator_group(args):
797        initiators = []
798        netmasks = []
799        for i in args.initiator_list.strip().split(' '):
800            initiators.append(i)
801        for n in args.netmask_list.strip().split(' '):
802            netmasks.append(n)
803        rpc.iscsi.add_initiator_group(
804            args.client,
805            tag=args.tag,
806            initiators=initiators,
807            netmasks=netmasks)
808
809    p = subparsers.add_parser('add_initiator_group',
810                              help='Add an initiator group')
811    p.add_argument(
812        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
813    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
814    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
815    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
816    Example: '255.255.0.0 255.248.0.0' etc""")
817    p.set_defaults(func=add_initiator_group)
818
819    @call_cmd
820    def add_initiators_to_initiator_group(args):
821        initiators = None
822        netmasks = None
823        if args.initiator_list:
824            initiators = []
825            for i in args.initiator_list.strip().split(' '):
826                initiators.append(i)
827        if args.netmask_list:
828            netmasks = []
829            for n in args.netmask_list.strip().split(' '):
830                netmasks.append(n)
831        rpc.iscsi.add_initiators_to_initiator_group(
832            args.client,
833            tag=args.tag,
834            initiators=initiators,
835            netmasks=netmasks)
836
837    p = subparsers.add_parser('add_initiators_to_initiator_group',
838                              help='Add initiators to an existing initiator group')
839    p.add_argument(
840        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
841    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
842    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
843    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
844    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
845    p.set_defaults(func=add_initiators_to_initiator_group)
846
847    @call_cmd
848    def delete_initiators_from_initiator_group(args):
849        initiators = None
850        netmasks = None
851        if args.initiator_list:
852            initiators = []
853            for i in args.initiator_list.strip().split(' '):
854                initiators.append(i)
855        if args.netmask_list:
856            netmasks = []
857            for n in args.netmask_list.strip().split(' '):
858                netmasks.append(n)
859        rpc.iscsi.delete_initiators_from_initiator_group(
860            args.client,
861            tag=args.tag,
862            initiators=initiators,
863            netmasks=netmasks)
864
865    p = subparsers.add_parser('delete_initiators_from_initiator_group',
866                              help='Delete initiators from an existing initiator group')
867    p.add_argument(
868        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
869    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
870    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
871    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
872    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
873    p.set_defaults(func=delete_initiators_from_initiator_group)
874
875    @call_cmd
876    def delete_target_node(args):
877        rpc.iscsi.delete_target_node(
878            args.client, target_node_name=args.target_node_name)
879
880    p = subparsers.add_parser('delete_target_node',
881                              help='Delete a target node')
882    p.add_argument('target_node_name',
883                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
884    p.set_defaults(func=delete_target_node)
885
886    @call_cmd
887    def delete_portal_group(args):
888        rpc.iscsi.delete_portal_group(args.client, tag=args.tag)
889
890    p = subparsers.add_parser('delete_portal_group',
891                              help='Delete a portal group')
892    p.add_argument(
893        'tag', help='Portal group tag (unique, integer > 0)', type=int)
894    p.set_defaults(func=delete_portal_group)
895
896    @call_cmd
897    def delete_initiator_group(args):
898        rpc.iscsi.delete_initiator_group(args.client, tag=args.tag)
899
900    p = subparsers.add_parser('delete_initiator_group',
901                              help='Delete an initiator group')
902    p.add_argument(
903        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
904    p.set_defaults(func=delete_initiator_group)
905
906    @call_cmd
907    def get_iscsi_connections(args):
908        print_dict(rpc.iscsi.get_iscsi_connections(args.client))
909
910    p = subparsers.add_parser('get_iscsi_connections',
911                              help='Display iSCSI connections')
912    p.set_defaults(func=get_iscsi_connections)
913
914    @call_cmd
915    def get_iscsi_global_params(args):
916        print_dict(rpc.iscsi.get_iscsi_global_params(args.client))
917
918    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
919    p.set_defaults(func=get_iscsi_global_params)
920
921    @call_cmd
922    def get_scsi_devices(args):
923        print_dict(rpc.iscsi.get_scsi_devices(args.client))
924
925    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
926    p.set_defaults(func=get_scsi_devices)
927
928    # log
929    @call_cmd
930    def set_trace_flag(args):
931        rpc.log.set_trace_flag(args.client, flag=args.flag)
932
933    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
934    p.add_argument(
935        'flag', help='trace mask we want to set. (for example "nvme").')
936    p.set_defaults(func=set_trace_flag)
937
938    @call_cmd
939    def clear_trace_flag(args):
940        rpc.log.clear_trace_flag(args.client, flag=args.flag)
941
942    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
943    p.add_argument(
944        'flag', help='trace mask we want to clear. (for example "nvme").')
945    p.set_defaults(func=clear_trace_flag)
946
947    @call_cmd
948    def get_trace_flags(args):
949        print_dict(rpc.log.get_trace_flags(args.client))
950
951    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
952    p.set_defaults(func=get_trace_flags)
953
954    @call_cmd
955    def set_log_level(args):
956        rpc.log.set_log_level(args.client, level=args.level)
957
958    p = subparsers.add_parser('set_log_level', help='set log level')
959    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
960    p.set_defaults(func=set_log_level)
961
962    @call_cmd
963    def get_log_level(args):
964        print_dict(rpc.log.get_log_level(args.client))
965
966    p = subparsers.add_parser('get_log_level', help='get log level')
967    p.set_defaults(func=get_log_level)
968
969    @call_cmd
970    def set_log_print_level(args):
971        rpc.log.set_log_print_level(args.client, level=args.level)
972
973    p = subparsers.add_parser('set_log_print_level', help='set log print level')
974    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
975    p.set_defaults(func=set_log_print_level)
976
977    @call_cmd
978    def get_log_print_level(args):
979        print_dict(rpc.log.get_log_print_level(args.client))
980
981    p = subparsers.add_parser('get_log_print_level', help='get log print level')
982    p.set_defaults(func=get_log_print_level)
983
984    # lvol
985    @call_cmd
986    def construct_lvol_store(args):
987        print(rpc.lvol.construct_lvol_store(args.client,
988                                            bdev_name=args.bdev_name,
989                                            lvs_name=args.lvs_name,
990                                            cluster_sz=args.cluster_sz))
991
992    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
993    p.add_argument('bdev_name', help='base bdev name')
994    p.add_argument('lvs_name', help='name for lvol store')
995    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
996    p.set_defaults(func=construct_lvol_store)
997
998    @call_cmd
999    def rename_lvol_store(args):
1000        rpc.lvol.rename_lvol_store(args.client,
1001                                   old_name=args.old_name,
1002                                   new_name=args.new_name)
1003
1004    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
1005    p.add_argument('old_name', help='old name')
1006    p.add_argument('new_name', help='new name')
1007    p.set_defaults(func=rename_lvol_store)
1008
1009    @call_cmd
1010    def construct_lvol_bdev(args):
1011        print(rpc.lvol.construct_lvol_bdev(args.client,
1012                                           lvol_name=args.lvol_name,
1013                                           size=args.size * 1024 * 1024,
1014                                           thin_provision=args.thin_provision,
1015                                           uuid=args.uuid,
1016                                           lvs_name=args.lvs_name))
1017
1018    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
1019    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1020    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1021    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
1022    p.add_argument('lvol_name', help='name for this lvol')
1023    p.add_argument('size', help='size in MiB for this bdev', type=int)
1024    p.set_defaults(func=construct_lvol_bdev)
1025
1026    @call_cmd
1027    def snapshot_lvol_bdev(args):
1028        print(rpc.lvol.snapshot_lvol_bdev(args.client,
1029                                          lvol_name=args.lvol_name,
1030                                          snapshot_name=args.snapshot_name))
1031
1032    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
1033    p.add_argument('lvol_name', help='lvol bdev name')
1034    p.add_argument('snapshot_name', help='lvol snapshot name')
1035    p.set_defaults(func=snapshot_lvol_bdev)
1036
1037    @call_cmd
1038    def clone_lvol_bdev(args):
1039        print(rpc.lvol.clone_lvol_bdev(args.client,
1040                                       snapshot_name=args.snapshot_name,
1041                                       clone_name=args.clone_name))
1042
1043    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
1044    p.add_argument('snapshot_name', help='lvol snapshot name')
1045    p.add_argument('clone_name', help='lvol clone name')
1046    p.set_defaults(func=clone_lvol_bdev)
1047
1048    @call_cmd
1049    def rename_lvol_bdev(args):
1050        rpc.lvol.rename_lvol_bdev(args.client,
1051                                  old_name=args.old_name,
1052                                  new_name=args.new_name)
1053
1054    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
1055    p.add_argument('old_name', help='lvol bdev name')
1056    p.add_argument('new_name', help='new lvol name')
1057    p.set_defaults(func=rename_lvol_bdev)
1058
1059    @call_cmd
1060    def inflate_lvol_bdev(args):
1061        rpc.lvol.inflate_lvol_bdev(args.client,
1062                                   name=args.name)
1063
1064    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
1065    p.add_argument('name', help='lvol bdev name')
1066    p.set_defaults(func=inflate_lvol_bdev)
1067
1068    @call_cmd
1069    def decouple_parent_lvol_bdev(args):
1070        rpc.lvol.decouple_parent_lvol_bdev(args.client,
1071                                           name=args.name)
1072
1073    p = subparsers.add_parser('decouple_parent_lvol_bdev', help='Decouple parent of lvol')
1074    p.add_argument('name', help='lvol bdev name')
1075    p.set_defaults(func=decouple_parent_lvol_bdev)
1076
1077    @call_cmd
1078    def resize_lvol_bdev(args):
1079        rpc.lvol.resize_lvol_bdev(args.client,
1080                                  name=args.name,
1081                                  size=args.size * 1024 * 1024)
1082
1083    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
1084    p.add_argument('name', help='lvol bdev name')
1085    p.add_argument('size', help='new size in MiB for this bdev', type=int)
1086    p.set_defaults(func=resize_lvol_bdev)
1087
1088    @call_cmd
1089    def destroy_lvol_bdev(args):
1090        rpc.lvol.destroy_lvol_bdev(args.client,
1091                                   name=args.name)
1092
1093    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
1094    p.add_argument('name', help='lvol bdev name')
1095    p.set_defaults(func=destroy_lvol_bdev)
1096
1097    @call_cmd
1098    def destroy_lvol_store(args):
1099        rpc.lvol.destroy_lvol_store(args.client,
1100                                    uuid=args.uuid,
1101                                    lvs_name=args.lvs_name)
1102
1103    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
1104    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1105    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1106    p.set_defaults(func=destroy_lvol_store)
1107
1108    @call_cmd
1109    def get_lvol_stores(args):
1110        print_dict(rpc.lvol.get_lvol_stores(args.client,
1111                                            uuid=args.uuid,
1112                                            lvs_name=args.lvs_name))
1113
1114    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
1115    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
1116    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
1117    p.set_defaults(func=get_lvol_stores)
1118
1119    @call_cmd
1120    def get_raid_bdevs(args):
1121        print_array(rpc.bdev.get_raid_bdevs(args.client,
1122                                            category=args.category))
1123
1124    p = subparsers.add_parser('get_raid_bdevs', help="""This is used to list all the raid bdev names based on the input category
1125    requested. Category should be one of 'all', 'online', 'configuring' or 'offline'. 'all' means all the raid bdevs whether
1126    they are online or configuring or offline. 'online' is the raid bdev which is registered with bdev layer. 'configuring'
1127    is the raid bdev which does not have full configuration discovered yet. 'offline' is the raid bdev which is not registered
1128    with bdev as of now and it has encountered any error or user has requested to offline the raid bdev""")
1129    p.add_argument('category', help='all or online or configuring or offline')
1130    p.set_defaults(func=get_raid_bdevs)
1131
1132    @call_cmd
1133    def construct_raid_bdev(args):
1134        base_bdevs = []
1135        for u in args.base_bdevs.strip().split(" "):
1136            base_bdevs.append(u)
1137
1138        rpc.bdev.construct_raid_bdev(args.client,
1139                                     name=args.name,
1140                                     strip_size=args.strip_size,
1141                                     raid_level=args.raid_level,
1142                                     base_bdevs=base_bdevs)
1143    p = subparsers.add_parser('construct_raid_bdev', help='Construct new raid bdev')
1144    p.add_argument('-n', '--name', help='raid bdev name', required=True)
1145    p.add_argument('-s', '--strip-size', help='strip size in KB', type=int, required=True)
1146    p.add_argument('-r', '--raid-level', help='raid level, only raid level 0 is supported', type=int, required=True)
1147    p.add_argument('-b', '--base-bdevs', help='base bdevs name, whitespace separated list in quotes', required=True)
1148    p.set_defaults(func=construct_raid_bdev)
1149
1150    @call_cmd
1151    def destroy_raid_bdev(args):
1152        rpc.bdev.destroy_raid_bdev(args.client,
1153                                   name=args.name)
1154    p = subparsers.add_parser('destroy_raid_bdev', help='Destroy existing raid bdev')
1155    p.add_argument('name', help='raid bdev name')
1156    p.set_defaults(func=destroy_raid_bdev)
1157
1158    # split
1159    @call_cmd
1160    def construct_split_vbdev(args):
1161        print_array(rpc.bdev.construct_split_vbdev(args.client,
1162                                                   base_bdev=args.base_bdev,
1163                                                   split_count=args.split_count,
1164                                                   split_size_mb=args.split_size_mb))
1165
1166    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
1167    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
1168    available (during examination process).""")
1169    p.add_argument('base_bdev', help='base bdev name')
1170    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
1171    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
1172    exceed the base bdev size.""", type=int)
1173    p.set_defaults(func=construct_split_vbdev)
1174
1175    @call_cmd
1176    def destruct_split_vbdev(args):
1177        rpc.bdev.destruct_split_vbdev(args.client,
1178                                      base_bdev=args.base_bdev)
1179
1180    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
1181    p.add_argument('base_bdev', help='base bdev name')
1182    p.set_defaults(func=destruct_split_vbdev)
1183
1184    # nbd
1185    @call_cmd
1186    def start_nbd_disk(args):
1187        print(rpc.nbd.start_nbd_disk(args.client,
1188                                     bdev_name=args.bdev_name,
1189                                     nbd_device=args.nbd_device))
1190
1191    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
1192    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
1193    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
1194    p.set_defaults(func=start_nbd_disk)
1195
1196    @call_cmd
1197    def stop_nbd_disk(args):
1198        rpc.nbd.stop_nbd_disk(args.client,
1199                              nbd_device=args.nbd_device)
1200
1201    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
1202    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
1203    p.set_defaults(func=stop_nbd_disk)
1204
1205    @call_cmd
1206    def get_nbd_disks(args):
1207        print_dict(rpc.nbd.get_nbd_disks(args.client,
1208                                         nbd_device=args.nbd_device))
1209
1210    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
1211    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
1212    p.set_defaults(func=get_nbd_disks)
1213
1214    # net
1215    @call_cmd
1216    def add_ip_address(args):
1217        rpc.net.add_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1218
1219    p = subparsers.add_parser('add_ip_address', help='Add IP address')
1220    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1221    p.add_argument('ip_addr', help='ip address will be added.')
1222    p.set_defaults(func=add_ip_address)
1223
1224    @call_cmd
1225    def delete_ip_address(args):
1226        rpc.net.delete_ip_address(args.client, ifc_index=args.ifc_index, ip_addr=args.ip_addr)
1227
1228    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
1229    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
1230    p.add_argument('ip_addr', help='ip address will be deleted.')
1231    p.set_defaults(func=delete_ip_address)
1232
1233    @call_cmd
1234    def get_interfaces(args):
1235        print_dict(rpc.net.get_interfaces(args.client))
1236
1237    p = subparsers.add_parser(
1238        'get_interfaces', help='Display current interface list')
1239    p.set_defaults(func=get_interfaces)
1240
1241    # NVMe-oF
1242    @call_cmd
1243    def set_nvmf_target_options(args):
1244        rpc.nvmf.set_nvmf_target_options(args.client,
1245                                         max_queue_depth=args.max_queue_depth,
1246                                         max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1247                                         in_capsule_data_size=args.in_capsule_data_size,
1248                                         max_io_size=args.max_io_size,
1249                                         max_subsystems=args.max_subsystems,
1250                                         io_unit_size=args.io_unit_size)
1251
1252    p = subparsers.add_parser('set_nvmf_target_options', help='Set NVMf target options')
1253    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1254    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1255    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1256    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1257    p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int)
1258    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1259    p.set_defaults(func=set_nvmf_target_options)
1260
1261    @call_cmd
1262    def set_nvmf_target_config(args):
1263        rpc.nvmf.set_nvmf_target_config(args.client,
1264                                        acceptor_poll_rate=args.acceptor_poll_rate,
1265                                        conn_sched=args.conn_sched)
1266
1267    p = subparsers.add_parser('set_nvmf_target_config', help='Set NVMf target config')
1268    p.add_argument('-r', '--acceptor-poll-rate', help='Polling interval of the acceptor for incoming connections (usec)', type=int)
1269    p.add_argument('-s', '--conn-sched', help="""'roundrobin' - Schedule the incoming connections from any host
1270    on the cores in a round robin manner (Default). 'hostip' - Schedule all the incoming connections from a
1271    specific host IP on to the same core. Connections from different IP will be assigned to cores in a round
1272    robin manner""")
1273    p.set_defaults(func=set_nvmf_target_config)
1274
1275    @call_cmd
1276    def nvmf_create_transport(args):
1277        rpc.nvmf.nvmf_create_transport(args.client,
1278                                       trtype=args.trtype,
1279                                       max_queue_depth=args.max_queue_depth,
1280                                       max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr,
1281                                       in_capsule_data_size=args.in_capsule_data_size,
1282                                       max_io_size=args.max_io_size,
1283                                       io_unit_size=args.io_unit_size,
1284                                       max_aq_depth=args.max_aq_depth)
1285
1286    p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport')
1287    p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True)
1288    p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int)
1289    p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int)
1290    p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int)
1291    p.add_argument('-i', '--max-io-size', help='Max I/O size (bytes)', type=int)
1292    p.add_argument('-u', '--io-unit-size', help='I/O unit size (bytes)', type=int)
1293    p.add_argument('-a', '--max-aq-depth', help='Max number of admin cmds per AQ', type=int)
1294    p.set_defaults(func=nvmf_create_transport)
1295
1296    @call_cmd
1297    def get_nvmf_subsystems(args):
1298        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client))
1299
1300    p = subparsers.add_parser('get_nvmf_subsystems',
1301                              help='Display nvmf subsystems')
1302    p.set_defaults(func=get_nvmf_subsystems)
1303
1304    @call_cmd
1305    def construct_nvmf_subsystem(args):
1306        listen_addresses = None
1307        hosts = None
1308        namespaces = None
1309        if args.listen:
1310            listen_addresses = [
1311                dict(
1312                    u.split(
1313                        ":",
1314                        1) for u in a.split(" ")) for a in args.listen.split(",")]
1315
1316        if args.hosts:
1317            hosts = []
1318            for u in args.hosts.strip().split(" "):
1319                hosts.append(u)
1320
1321        if args.namespaces:
1322            namespaces = []
1323            for u in args.namespaces.strip().split(" "):
1324                bdev_name = u
1325                nsid = 0
1326                if ':' in u:
1327                    (bdev_name, nsid) = u.split(":")
1328
1329                ns_params = {'bdev_name': bdev_name}
1330
1331                nsid = int(nsid)
1332                if nsid != 0:
1333                    ns_params['nsid'] = nsid
1334
1335                namespaces.append(ns_params)
1336
1337        rpc.nvmf.construct_nvmf_subsystem(args.client,
1338                                          nqn=args.nqn,
1339                                          listen_addresses=listen_addresses,
1340                                          hosts=hosts,
1341                                          allow_any_host=args.allow_any_host,
1342                                          serial_number=args.serial_number,
1343                                          namespaces=namespaces,
1344                                          max_namespaces=args.max_namespaces)
1345
1346    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
1347    p.add_argument('nqn', help='Target nqn(ASCII)')
1348    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
1349    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
1350    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
1351    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
1352    Format:  'nqn1 nqn2' etc
1353    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
1354    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1355    p.add_argument("-s", "--serial-number", help="""
1356    Format:  'sn' etc
1357    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1358    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
1359    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
1360    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
1361    *** The devices must pre-exist ***""")
1362    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
1363                   type=int, default=0)
1364    p.set_defaults(func=construct_nvmf_subsystem)
1365
1366    @call_cmd
1367    def nvmf_subsystem_create(args):
1368        rpc.nvmf.nvmf_subsystem_create(args.client,
1369                                       nqn=args.nqn,
1370                                       serial_number=args.serial_number,
1371                                       allow_any_host=args.allow_any_host,
1372                                       max_namespaces=args.max_namespaces)
1373
1374    p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem')
1375    p.add_argument('nqn', help='Subsystem NQN (ASCII)')
1376    p.add_argument("-s", "--serial-number", help="""
1377    Format:  'sn' etc
1378    Example: 'SPDK00000000000001'""", default='00000000000000000000')
1379    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
1380    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed",
1381                   type=int, default=0)
1382    p.set_defaults(func=nvmf_subsystem_create)
1383
1384    @call_cmd
1385    def delete_nvmf_subsystem(args):
1386        rpc.nvmf.delete_nvmf_subsystem(args.client,
1387                                       nqn=args.subsystem_nqn)
1388
1389    p = subparsers.add_parser('delete_nvmf_subsystem',
1390                              help='Delete a nvmf subsystem')
1391    p.add_argument('subsystem_nqn',
1392                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
1393    p.set_defaults(func=delete_nvmf_subsystem)
1394
1395    @call_cmd
1396    def nvmf_subsystem_add_listener(args):
1397        rpc.nvmf.nvmf_subsystem_add_listener(args.client,
1398                                             nqn=args.nqn,
1399                                             trtype=args.trtype,
1400                                             traddr=args.traddr,
1401                                             adrfam=args.adrfam,
1402                                             trsvcid=args.trsvcid)
1403
1404    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
1405    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1406    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1407    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1408    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1409    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1410    p.set_defaults(func=nvmf_subsystem_add_listener)
1411
1412    @call_cmd
1413    def nvmf_subsystem_remove_listener(args):
1414        rpc.nvmf.nvmf_subsystem_remove_listener(args.client,
1415                                                nqn=args.nqn,
1416                                                trtype=args.trtype,
1417                                                traddr=args.traddr,
1418                                                adrfam=args.adrfam,
1419                                                trsvcid=args.trsvcid)
1420
1421    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
1422    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1423    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
1424    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
1425    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
1426    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
1427    p.set_defaults(func=nvmf_subsystem_remove_listener)
1428
1429    @call_cmd
1430    def nvmf_subsystem_add_ns(args):
1431        rpc.nvmf.nvmf_subsystem_add_ns(args.client,
1432                                       nqn=args.nqn,
1433                                       bdev_name=args.bdev_name,
1434                                       nsid=args.nsid,
1435                                       nguid=args.nguid,
1436                                       eui64=args.eui64,
1437                                       uuid=args.uuid)
1438
1439    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
1440    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1441    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
1442    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
1443    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
1444    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
1445    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
1446    p.set_defaults(func=nvmf_subsystem_add_ns)
1447
1448    @call_cmd
1449    def nvmf_subsystem_remove_ns(args):
1450        rpc.nvmf.nvmf_subsystem_remove_ns(args.client,
1451                                          nqn=args.nqn,
1452                                          nsid=args.nsid)
1453
1454    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
1455    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1456    p.add_argument('nsid', help='The requested NSID', type=int)
1457    p.set_defaults(func=nvmf_subsystem_remove_ns)
1458
1459    @call_cmd
1460    def nvmf_subsystem_add_host(args):
1461        rpc.nvmf.nvmf_subsystem_add_host(args.client,
1462                                         nqn=args.nqn,
1463                                         host=args.host)
1464
1465    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
1466    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1467    p.add_argument('host', help='Host NQN to allow')
1468    p.set_defaults(func=nvmf_subsystem_add_host)
1469
1470    @call_cmd
1471    def nvmf_subsystem_remove_host(args):
1472        rpc.nvmf.nvmf_subsystem_remove_host(args.client,
1473                                            nqn=args.nqn,
1474                                            host=args.host)
1475
1476    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
1477    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1478    p.add_argument('host', help='Host NQN to remove')
1479    p.set_defaults(func=nvmf_subsystem_remove_host)
1480
1481    @call_cmd
1482    def nvmf_subsystem_allow_any_host(args):
1483        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client,
1484                                               nqn=args.nqn,
1485                                               disable=args.disable)
1486
1487    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
1488    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
1489    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
1490    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
1491    p.set_defaults(func=nvmf_subsystem_allow_any_host)
1492
1493    # pmem
1494    @call_cmd
1495    def create_pmem_pool(args):
1496        num_blocks = int((args.total_size * 1024 * 1024) / args.block_size)
1497        rpc.pmem.create_pmem_pool(args.client,
1498                                  pmem_file=args.pmem_file,
1499                                  num_blocks=num_blocks,
1500                                  block_size=args.block_size)
1501
1502    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
1503    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1504    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
1505    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
1506    p.set_defaults(func=create_pmem_pool)
1507
1508    @call_cmd
1509    def pmem_pool_info(args):
1510        print_dict(rpc.pmem.pmem_pool_info(args.client,
1511                                           pmem_file=args.pmem_file))
1512
1513    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
1514    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1515    p.set_defaults(func=pmem_pool_info)
1516
1517    @call_cmd
1518    def delete_pmem_pool(args):
1519        rpc.pmem.delete_pmem_pool(args.client,
1520                                  pmem_file=args.pmem_file)
1521
1522    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
1523    p.add_argument('pmem_file', help='Path to pmemblk pool file')
1524    p.set_defaults(func=delete_pmem_pool)
1525
1526    # subsystem
1527    @call_cmd
1528    def get_subsystems(args):
1529        print_dict(rpc.subsystem.get_subsystems(args.client))
1530
1531    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
1532    entry contain (unsorted) array of subsystems it depends on.""")
1533    p.set_defaults(func=get_subsystems)
1534
1535    @call_cmd
1536    def get_subsystem_config(args):
1537        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
1538
1539    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
1540    p.add_argument('name', help='Name of subsystem to query')
1541    p.set_defaults(func=get_subsystem_config)
1542
1543    # vhost
1544    @call_cmd
1545    def set_vhost_controller_coalescing(args):
1546        rpc.vhost.set_vhost_controller_coalescing(args.client,
1547                                                  ctrlr=args.ctrlr,
1548                                                  delay_base_us=args.delay_base_us,
1549                                                  iops_threshold=args.iops_threshold)
1550
1551    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
1552    p.add_argument('ctrlr', help='controller name')
1553    p.add_argument('delay_base_us', help='Base delay time', type=int)
1554    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
1555    p.set_defaults(func=set_vhost_controller_coalescing)
1556
1557    @call_cmd
1558    def construct_vhost_scsi_controller(args):
1559        rpc.vhost.construct_vhost_scsi_controller(args.client,
1560                                                  ctrlr=args.ctrlr,
1561                                                  cpumask=args.cpumask)
1562
1563    p = subparsers.add_parser(
1564        'construct_vhost_scsi_controller', help='Add new vhost controller')
1565    p.add_argument('ctrlr', help='controller name')
1566    p.add_argument('--cpumask', help='cpu mask for this controller')
1567    p.set_defaults(func=construct_vhost_scsi_controller)
1568
1569    @call_cmd
1570    def add_vhost_scsi_lun(args):
1571        rpc.vhost.add_vhost_scsi_lun(args.client,
1572                                     ctrlr=args.ctrlr,
1573                                     scsi_target_num=args.scsi_target_num,
1574                                     bdev_name=args.bdev_name)
1575
1576    p = subparsers.add_parser('add_vhost_scsi_lun',
1577                              help='Add lun to vhost controller')
1578    p.add_argument('ctrlr', help='conntroller name where add lun')
1579    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1580    p.add_argument('bdev_name', help='bdev name')
1581    p.set_defaults(func=add_vhost_scsi_lun)
1582
1583    @call_cmd
1584    def remove_vhost_scsi_target(args):
1585        rpc.vhost.remove_vhost_scsi_target(args.client,
1586                                           ctrlr=args.ctrlr,
1587                                           scsi_target_num=args.scsi_target_num)
1588
1589    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1590    p.add_argument('ctrlr', help='controller name to remove target from')
1591    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1592    p.set_defaults(func=remove_vhost_scsi_target)
1593
1594    @call_cmd
1595    def construct_vhost_blk_controller(args):
1596        rpc.vhost.construct_vhost_blk_controller(args.client,
1597                                                 ctrlr=args.ctrlr,
1598                                                 dev_name=args.dev_name,
1599                                                 cpumask=args.cpumask,
1600                                                 readonly=args.readonly)
1601
1602    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1603    p.add_argument('ctrlr', help='controller name')
1604    p.add_argument('dev_name', help='device name')
1605    p.add_argument('--cpumask', help='cpu mask for this controller')
1606    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1607    p.set_defaults(func=construct_vhost_blk_controller)
1608
1609    @call_cmd
1610    def construct_vhost_nvme_controller(args):
1611        rpc.vhost.construct_vhost_nvme_controller(args.client,
1612                                                  ctrlr=args.ctrlr,
1613                                                  io_queues=args.io_queues,
1614                                                  cpumask=args.cpumask)
1615
1616    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1617    p.add_argument('ctrlr', help='controller name')
1618    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1619    p.add_argument('--cpumask', help='cpu mask for this controller')
1620    p.set_defaults(func=construct_vhost_nvme_controller)
1621
1622    @call_cmd
1623    def add_vhost_nvme_ns(args):
1624        rpc.vhost.add_vhost_nvme_ns(args.client,
1625                                    ctrlr=args.ctrlr,
1626                                    bdev_name=args.bdev_name)
1627
1628    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1629    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1630    p.add_argument('bdev_name', help='block device name for a new Namespace')
1631    p.set_defaults(func=add_vhost_nvme_ns)
1632
1633    @call_cmd
1634    def get_vhost_controllers(args):
1635        print_dict(rpc.vhost.get_vhost_controllers(args.client))
1636
1637    p = subparsers.add_parser('get_vhost_controllers', help='List vhost controllers')
1638    p.set_defaults(func=get_vhost_controllers)
1639
1640    @call_cmd
1641    def remove_vhost_controller(args):
1642        rpc.vhost.remove_vhost_controller(args.client,
1643                                          ctrlr=args.ctrlr)
1644
1645    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1646    p.add_argument('ctrlr', help='controller name')
1647    p.set_defaults(func=remove_vhost_controller)
1648
1649    @call_cmd
1650    def construct_virtio_dev(args):
1651        print_array(rpc.vhost.construct_virtio_dev(args.client,
1652                                                   name=args.name,
1653                                                   trtype=args.trtype,
1654                                                   traddr=args.traddr,
1655                                                   dev_type=args.dev_type,
1656                                                   vq_count=args.vq_count,
1657                                                   vq_size=args.vq_size))
1658
1659    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1660    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1661    remote side. Result is array of added bdevs.""")
1662    p.add_argument('name', help="Use this name as base for new created bdevs")
1663    p.add_argument('-t', '--trtype',
1664                   help='Virtio target transport type: pci or user', required=True)
1665    p.add_argument('-a', '--traddr',
1666                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1667    p.add_argument('-d', '--dev-type',
1668                   help='Device type: blk or scsi', required=True)
1669    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1670    p.add_argument('--vq-size', help='Size of each queue', type=int)
1671    p.set_defaults(func=construct_virtio_dev)
1672
1673    @call_cmd
1674    def construct_virtio_user_scsi_bdev(args):
1675        print_array(rpc.vhost.construct_virtio_user_scsi_bdev(args.client,
1676                                                              path=args.path,
1677                                                              name=args.name,
1678                                                              vq_count=args.vq_count,
1679                                                              vq_size=args.vq_size))
1680
1681    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1682    This imply scan and add bdevs offered by remote side.
1683    Result is array of added bdevs.""")
1684    p.add_argument('path', help='Path to Virtio SCSI socket')
1685    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1686    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1687    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1688    p.add_argument('--vq-size', help='Size of each queue', type=int)
1689    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1690
1691    @call_cmd
1692    def construct_virtio_pci_scsi_bdev(args):
1693        print_array(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client,
1694                                                             pci_address=args.pci_address,
1695                                                             name=args.name))
1696
1697    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1698    SCSI device from a virtio-pci device.""")
1699    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1700    domain.bus.device.function format""")
1701    p.add_argument('name', help="""Name for the virtio device.
1702    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1703    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1704
1705    @call_cmd
1706    def get_virtio_scsi_devs(args):
1707        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client))
1708
1709    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1710    p.set_defaults(func=get_virtio_scsi_devs)
1711
1712    @call_cmd
1713    def remove_virtio_scsi_bdev(args):
1714        rpc.vhost.remove_virtio_scsi_bdev(args.client,
1715                                          name=args.name)
1716
1717    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1718    This will delete all bdevs exposed by this device (this call is deprecated - please use remove_virtio_bdev call instead).""")
1719    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1720    p.set_defaults(func=remove_virtio_scsi_bdev)
1721
1722    @call_cmd
1723    def remove_virtio_bdev(args):
1724        rpc.vhost.remove_virtio_bdev(args.client,
1725                                     name=args.name)
1726
1727    p = subparsers.add_parser('remove_virtio_bdev', help="""Remove a Virtio device
1728    This will delete all bdevs exposed by this device""")
1729    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1730    p.set_defaults(func=remove_virtio_bdev)
1731
1732    @call_cmd
1733    def construct_virtio_user_blk_bdev(args):
1734        print(rpc.vhost.construct_virtio_user_blk_bdev(args.client,
1735                                                       path=args.path,
1736                                                       name=args.name,
1737                                                       vq_count=args.vq_count,
1738                                                       vq_size=args.vq_size))
1739
1740    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1741    p.add_argument('path', help='Path to Virtio BLK socket')
1742    p.add_argument('name', help='Name for the bdev')
1743    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1744    p.add_argument('--vq-size', help='Size of each queue', type=int)
1745    p.set_defaults(func=construct_virtio_user_blk_bdev)
1746
1747    @call_cmd
1748    def construct_virtio_pci_blk_bdev(args):
1749        print(rpc.vhost.construct_virtio_pci_blk_bdev(args.client,
1750                                                      pci_address=args.pci_address,
1751                                                      name=args.name))
1752
1753    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1754    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1755    domain.bus.device.function format""")
1756    p.add_argument('name', help='Name for the bdev')
1757    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1758
1759    # ioat
1760    @call_cmd
1761    def scan_ioat_copy_engine(args):
1762        pci_whitelist = []
1763        if args.pci_whitelist:
1764            for w in args.pci_whitelist.strip().split(" "):
1765                pci_whitelist.append(w)
1766        rpc.ioat.scan_ioat_copy_engine(args.client, pci_whitelist)
1767
1768    p = subparsers.add_parser('scan_ioat_copy_engine', help='Set scan and enable IOAT copy engine offload.')
1769    p.add_argument('-w', '--pci-whitelist', help="""Whitespace-separated list of PCI addresses in
1770    domain:bus:device.function format or domain.bus.device.function format""")
1771    p.set_defaults(func=scan_ioat_copy_engine)
1772
1773    args = parser.parse_args()
1774
1775    try:
1776        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1777    except JSONRPCException as ex:
1778        print(ex.message)
1779        exit(1)
1780    args.func(args)
1781