xref: /spdk/scripts/rpc.py (revision 8da7772a7d6daab09e0e7e58ab08eff5c4b7ba92)
1#!/usr/bin/env python
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, args))
53
54    p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods')
55    p.add_argument('-c', '--current', help='Get list of RPC methods only callable in the current state.', action='store_true')
56    p.set_defaults(func=get_rpc_methods)
57
58    @call_cmd
59    def save_config(args):
60        rpc.save_config(args.client, args)
61
62    p = subparsers.add_parser('save_config', help="""Write current (live) configuration of SPDK subsystems and targets.
63    If no filename is given write configuration to stdout.""")
64    p.add_argument('-f', '--filename', help="""File where to save JSON configuration to.""")
65    p.add_argument('-i', '--indent', help="""Indent level. Value less than 0 mean compact mode. If filename is not given default
66    indent level is 2. If writing to file of filename is '-' then default is compact mode.""", type=int, default=2)
67    p.set_defaults(func=save_config)
68
69    @call_cmd
70    def load_config(args):
71        rpc.load_config(args.client, args)
72
73    p = subparsers.add_parser('load_config', help="""Configure SPDK subsystems and tagets using JSON RPC. If no file is
74    provided or file is '-' read configuration from stdin.""")
75    p.add_argument('-f', '--filename', help="""JSON Configuration file.""")
76    p.set_defaults(func=load_config)
77
78    @call_cmd
79    def load_subsystem_config(args):
80        rpc.load_subsystem_config(args.client, args)
81
82    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC. If no file is
83    provided or file is '-' read configuration from stdin.""")
84    p.add_argument('--filename', help="""JSON Configuration file.""")
85    p.set_defaults(func=load_subsystem_config)
86
87    # app
88    @call_cmd
89    def kill_instance(args):
90        rpc.app.kill_instance(args.client,
91                              sig_name=args.sig_name)
92
93    p = subparsers.add_parser('kill_instance', help='Send signal to instance')
94    p.add_argument('sig_name', help='signal will be sent to server.')
95    p.set_defaults(func=kill_instance)
96
97    @call_cmd
98    def context_switch_monitor(args):
99        enabled = None
100        if args.enable:
101            enabled = True
102        if args.disable:
103            enabled = False
104        print_dict(rpc.app.context_switch_monitor(args.client,
105                                                  enabled=enabled))
106
107    p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled')
108    p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring')
109    p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring')
110    p.set_defaults(func=context_switch_monitor)
111
112    # bdev
113    @call_cmd
114    def construct_malloc_bdev(args):
115        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
116        print_array(rpc.bdev.construct_malloc_bdev(args.client,
117                                                   num_blocks=num_blocks,
118                                                   block_size=args.block_size,
119                                                   name=args.name,
120                                                   uuid=args.uuid))
121
122    p = subparsers.add_parser('construct_malloc_bdev',
123                              help='Add a bdev with malloc backend')
124    p.add_argument('-b', '--name', help="Name of the bdev")
125    p.add_argument('-u', '--uuid', help="UUID of the bdev")
126    p.add_argument(
127        'total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
128    p.add_argument('block_size', help='Block size for this bdev', type=int)
129    p.set_defaults(func=construct_malloc_bdev)
130
131    @call_cmd
132    def construct_null_bdev(args):
133        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
134        print_array(rpc.bdev.construct_null_bdev(args.client,
135                                                 num_blocks=num_blocks,
136                                                 block_size=args.block_size,
137                                                 name=args.name,
138                                                 uuid=args.uuid))
139
140    p = subparsers.add_parser('construct_null_bdev',
141                              help='Add a bdev with null backend')
142    p.add_argument('name', help='Block device name')
143    p.add_argument('-u', '--uuid', help='UUID of the bdev')
144    p.add_argument(
145        'total_size', help='Size of null bdev in MB (int > 0)', type=int)
146    p.add_argument('block_size', help='Block size for this bdev', type=int)
147    p.set_defaults(func=construct_null_bdev)
148
149    @call_cmd
150    def construct_aio_bdev(args):
151        print_array(rpc.bdev.construct_aio_bdev(args.client,
152                                                filename=args.filename,
153                                                name=args.name,
154                                                block_size=args.block_size))
155
156    p = subparsers.add_parser('construct_aio_bdev',
157                              help='Add a bdev with aio backend')
158    p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
159    p.add_argument('name', help='Block device name')
160    p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?', default=0)
161    p.set_defaults(func=construct_aio_bdev)
162
163    @call_cmd
164    def construct_nvme_bdev(args):
165        print_array(rpc.bdev.construct_nvme_bdev(args.client,
166                                                 name=args.name,
167                                                 trtype=args.trtype,
168                                                 traddr=args.traddr,
169                                                 adrfam=args.adrfam,
170                                                 trsvcid=args.trsvcid,
171                                                 subnqn=args.subnqn))
172
173    p = subparsers.add_parser('construct_nvme_bdev',
174                              help='Add bdev with nvme backend')
175    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
176    p.add_argument('-t', '--trtype',
177                   help='NVMe-oF target trtype: e.g., rdma, pcie', required=True)
178    p.add_argument('-a', '--traddr',
179                   help='NVMe-oF target address: e.g., an ip address or BDF', required=True)
180    p.add_argument('-f', '--adrfam',
181                   help='NVMe-oF target adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
182    p.add_argument('-s', '--trsvcid',
183                   help='NVMe-oF target trsvcid: e.g., a port number')
184    p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn')
185    p.set_defaults(func=construct_nvme_bdev)
186
187    @call_cmd
188    def construct_rbd_bdev(args):
189        print_array(rpc.bdev.construct_rbd_bdev(args.client,
190                                                name=args.name,
191                                                pool_name=args.pool_name,
192                                                rbd_name=args.rbd_name,
193                                                block_size=args.block_size))
194
195    p = subparsers.add_parser('construct_rbd_bdev',
196                              help='Add a bdev with ceph rbd backend')
197    p.add_argument('-b', '--name', help="Name of the bdev", required=False)
198    p.add_argument('pool_name', help='rbd pool name')
199    p.add_argument('rbd_name', help='rbd image name')
200    p.add_argument('block_size', help='rbd block size', type=int)
201    p.set_defaults(func=construct_rbd_bdev)
202
203    @call_cmd
204    def construct_error_bdev(args):
205        rpc.bdev.construct_error_bdev(args.client,
206                                      base_name=args.base_name)
207
208    p = subparsers.add_parser('construct_error_bdev',
209                              help='Add bdev with error injection backend')
210    p.add_argument('base_name', help='base bdev name')
211    p.set_defaults(func=construct_error_bdev)
212
213    @call_cmd
214    def construct_iscsi_bdev(args):
215        rpc.bdev.construct_iscsi_bdev(args.client,
216                                      name=args.name,
217                                      url=args.url,
218                                      initiator_iqn=args.initiator_iqn)
219
220    p = subparsers.add_parser('construct_iscsi_bdev',
221                              help='Add bdev with iSCSI initiator backend')
222    p.add_argument('-b', '--name', help="Name of the bdev", required=True)
223    p.add_argument('-i', '--initiator-iqn', help="Initiator IQN", required=True)
224    p.add_argument('--url', help="iSCSI Lun URL", required=True)
225    p.set_defaults(func=construct_iscsi_bdev)
226
227    @call_cmd
228    def construct_pmem_bdev(args):
229        print_array(rpc.bdev.construct_pmem_bdev(args.client,
230                                                 pmem_file=args.pmem_file,
231                                                 name=args.name))
232
233    p = subparsers.add_parser('construct_pmem_bdev', help='Add a bdev with pmem backend')
234    p.add_argument('pmem_file', help='Path to pmemblk pool file')
235    p.add_argument('-n', '--name', help='Block device name', required=True)
236    p.set_defaults(func=construct_pmem_bdev)
237
238    @call_cmd
239    def construct_passthru_bdev(args):
240        print_array(rpc.bdev.construct_passthru_bdev(args.client,
241                                                     base_bdev_name=args.base_bdev_name,
242                                                     passthru_bdev_name=args.passthru_bdev_name))
243
244    p = subparsers.add_parser('construct_passthru_bdev',
245                              help='Add a pass through bdev on existing bdev')
246    p.add_argument('-b', '--base-bdev-name', help="Name of the existing bdev", required=True)
247    p.add_argument('-p', '--passthru-bdev-name', help="Name of the passthru bdev", required=True)
248    p.set_defaults(func=construct_passthru_bdev)
249
250    @call_cmd
251    def get_bdevs(args):
252        print_dict(rpc.bdev.get_bdevs(args.client,
253                                      name=args.name))
254
255    p = subparsers.add_parser(
256        'get_bdevs', help='Display current blockdev list or required blockdev')
257    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
258    p.set_defaults(func=get_bdevs)
259
260    @call_cmd
261    def get_bdevs_config(args):
262        print_dict(rpc.bdev.get_bdevs_config(args.client,
263                                             name=args.name))
264
265    p = subparsers.add_parser(
266        'get_bdevs_config', help='Display current (live) blockdev configuration list or required blockdev')
267    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
268    p.set_defaults(func=get_bdevs_config)
269
270    @call_cmd
271    def get_bdevs_iostat(args):
272        print_dict(rpc.bdev.get_bdevs_iostat(args.client,
273                                             name=args.name))
274
275    p = subparsers.add_parser(
276        'get_bdevs_iostat', help='Display current I/O statistics of all the blockdevs or required blockdev.')
277    p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
278    p.set_defaults(func=get_bdevs_iostat)
279
280    @call_cmd
281    def delete_bdev(args):
282        rpc.bdev.delete_bdev(args.client,
283                             bdev_name=args.bdev_name)
284
285    p = subparsers.add_parser('delete_bdev', help='Delete a blockdev')
286    p.add_argument(
287        'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
288    p.set_defaults(func=delete_bdev)
289
290    @call_cmd
291    def set_bdev_qos_limit_iops(args):
292        rpc.bdev.set_bdev_qos_limit_iops(args.client,
293                                         name=args.name,
294                                         ios_per_sec=args.ios_per_sec)
295
296    p = subparsers.add_parser('set_bdev_qos_limit_iops', help='Set QoS IOPS limit on a blockdev')
297    p.add_argument('name', help='Blockdev name to set QoS. Example: Malloc0')
298    p.add_argument('ios_per_sec',
299                   help='IOs per second limit (>=10000, example: 20000). 0 means unlimited.', type=int)
300    p.set_defaults(func=set_bdev_qos_limit_iops)
301
302    @call_cmd
303    def bdev_inject_error(args):
304        rpc.bdev.bdev_inject_error(args.client,
305                                   name=args.name,
306                                   io_type=args.io_type,
307                                   error_type=args.error_type,
308                                   num=args.num)
309
310    p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
311    p.add_argument('name', help="""the name of the error injection bdev""")
312    p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
313    p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
314    p.add_argument(
315        '-n', '--num', help='the number of commands you want to fail', type=int, default=1)
316    p.set_defaults(func=bdev_inject_error)
317
318    @call_cmd
319    def apply_firmware(args):
320        print_dict(rpc.bdev.apply_firmware(args.client,
321                                           bdev_name=args.bdev_name,
322                                           filename=args.filename))
323
324    p = subparsers.add_parser('apply_firmware', help='Download and commit firmware to NVMe device')
325    p.add_argument('filename', help='filename of the firmware to download')
326    p.add_argument('bdev_name', help='name of the NVMe device')
327    p.set_defaults(func=apply_firmware)
328
329    # iSCSI
330    def set_iscsi_options(args):
331        rpc.iscsi.set_iscsi_options(args.client, args)
332
333    p = subparsers.add_parser('set_iscsi_options', help="""Set options of iSCSI subsystem""")
334    p.add_argument('-f', '--auth-file', help='Path to CHAP shared secret file for discovery session')
335    p.add_argument('-b', '--node-base', help='Prefix of the name of iSCSI target node')
336    p.add_argument('-o', '--nop-timeout', help='Timeout in seconds to nop-in request to the initiator', type=int)
337    p.add_argument('-n', '--nop-in-interval', help='Time interval in secs between nop-in requests by the target', type=int)
338    p.add_argument('-d', '--no-discovery-auth', help="""CHAP for discovery session should be disabled.
339    *** Mutually exclusive with --req-discovery-auth""", action='store_true')
340    p.add_argument('-r', '--req-discovery-auth', help="""CHAP for discovery session should be required.
341    *** Mutually exclusive with --no-discovery-auth""", action='store_true')
342    p.add_argument('-m', '--req-discovery-auth-mutual', help='CHAP for discovery session should be mutual', action='store_true')
343    p.add_argument('-g', '--discovery-auth-group', help="""Authentication group ID for discovery session.
344    *** Authentication group must be precreated ***""", type=int)
345    p.add_argument('-a', '--max-sessions', help='Maximum number of sessions in the host.', type=int)
346    p.add_argument('-c', '--max-connections-per-session', help='Negotiated parameter, MaxConnections.', type=int)
347    p.add_argument('-w', '--default-time2wait', help='Negotiated parameter, DefaultTime2Wait.', type=int)
348    p.add_argument('-v', '--default-time2retain', help='Negotiated parameter, DefaultTime2Retain.', type=int)
349    p.add_argument('-i', '--immediate-data', help='Negotiated parameter, ImmediateData.', action='store_true')
350    p.add_argument('-l', '--error-recovery-level', help='Negotiated parameter, ErrorRecoveryLevel', type=int)
351    p.add_argument('-p', '--allow-duplicated-isid', help='Allow duplicated initiator session ID.', action='store_true')
352    p.add_argument('-u', '--min-connections-per-session', help='Allocation unit of connections per core', type=int)
353    p.set_defaults(func=set_iscsi_options)
354
355    @call_cmd
356    def get_portal_groups(args):
357        print_dict(rpc.iscsi.get_portal_groups(args.client, args))
358
359    p = subparsers.add_parser(
360        'get_portal_groups', help='Display current portal group configuration')
361    p.set_defaults(func=get_portal_groups)
362
363    @call_cmd
364    def get_initiator_groups(args):
365        print_dict(rpc.iscsi.get_initiator_groups(args.client, args))
366
367    p = subparsers.add_parser('get_initiator_groups',
368                              help='Display current initiator group configuration')
369    p.set_defaults(func=get_initiator_groups)
370
371    @call_cmd
372    def get_target_nodes(args):
373        print_dict(rpc.iscsi.get_target_nodes(args.client, args))
374
375    p = subparsers.add_parser('get_target_nodes', help='Display target nodes')
376    p.set_defaults(func=get_target_nodes)
377
378    @call_cmd
379    def construct_target_node(args):
380        rpc.iscsi.construct_target_node(args.client, args)
381
382    p = subparsers.add_parser('construct_target_node',
383                              help='Add a target node')
384    p.add_argument('name', help='Target node name (ASCII)')
385    p.add_argument('alias_name', help='Target node alias name (ASCII)')
386    p.add_argument('bdev_name_id_pairs', help="""Whitespace-separated list of <bdev name:LUN ID> pairs enclosed
387    in quotes.  Format:  'bdev_name0:id0 bdev_name1:id1' etc
388    Example: 'Malloc0:0 Malloc1:1 Malloc5:2'
389    *** The bdevs must pre-exist ***
390    *** LUN0 (id = 0) is required ***
391    *** bdevs names cannot contain space or colon characters ***""")
392    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
393    Whitespace separated, quoted, mapping defined with colon
394    separated list of "tags" (int > 0)
395    Example: '1:1 2:2 2:1'
396    *** The Portal/Initiator Groups must be precreated ***""")
397    p.add_argument('queue_depth', help='Desired target queue depth', type=int)
398    p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node.
399    *** Authentication group must be precreated ***""", type=int, default=0)
400    p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node.
401    *** Mutually exclusive with --require-chap ***""", action='store_true')
402    p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node.
403    *** Mutually exclusive with --disable-chap ***""", action='store_true')
404    p.add_argument(
405        '-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', action='store_true')
406    p.add_argument('-H', '--header-digest',
407                   help='Header Digest should be required for this target node.', action='store_true')
408    p.add_argument('-D', '--data-digest',
409                   help='Data Digest should be required for this target node.', action='store_true')
410    p.set_defaults(func=construct_target_node)
411
412    @call_cmd
413    def target_node_add_lun(args):
414        rpc.iscsi.target_node_add_lun(args.client, args)
415
416    p = subparsers.add_parser('target_node_add_lun', help='Add LUN to the target node')
417    p.add_argument('name', help='Target node name (ASCII)')
418    p.add_argument('bdev_name', help="""bdev name enclosed in quotes.
419    *** bdev name cannot contain space or colon characters ***""")
420    p.add_argument('-i', dest='lun_id', help="""LUN ID (integer >= 0)
421    *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False)
422    p.set_defaults(func=target_node_add_lun)
423
424    @call_cmd
425    def add_pg_ig_maps(args):
426        rpc.iscsi.add_pg_ig_maps(args.client, args)
427
428    p = subparsers.add_parser('add_pg_ig_maps', help='Add PG-IG maps to the target node')
429    p.add_argument('name', help='Target node name (ASCII)')
430    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
431    Whitespace separated, quoted, mapping defined with colon
432    separated list of "tags" (int > 0)
433    Example: '1:1 2:2 2:1'
434    *** The Portal/Initiator Groups must be precreated ***""")
435    p.set_defaults(func=add_pg_ig_maps)
436
437    @call_cmd
438    def delete_pg_ig_maps(args):
439        rpc.iscsi.delete_pg_ig_maps(args.client, args)
440
441    p = subparsers.add_parser('delete_pg_ig_maps', help='Delete PG-IG maps from the target node')
442    p.add_argument('name', help='Target node name (ASCII)')
443    p.add_argument('pg_ig_mappings', help="""List of (Portal_Group_Tag:Initiator_Group_Tag) mappings
444    Whitespace separated, quoted, mapping defined with colon
445    separated list of "tags" (int > 0)
446    Example: '1:1 2:2 2:1'
447    *** The Portal/Initiator Groups must be precreated ***""")
448    p.set_defaults(func=delete_pg_ig_maps)
449
450    @call_cmd
451    def add_portal_group(args):
452        rpc.iscsi.add_portal_group(args.client, args)
453
454    p = subparsers.add_parser('add_portal_group', help='Add a portal group')
455    p.add_argument(
456        'tag', help='Portal group tag (unique, integer > 0)', type=int)
457    p.add_argument('portal_list', nargs=argparse.REMAINDER, help="""List of portals in 'host:port@cpumask' format, separated by whitespace
458    (cpumask is optional and can be skipped)
459    Example: '192.168.100.100:3260' '192.168.100.100:3261' '192.168.100.100:3262@0x1""")
460    p.set_defaults(func=add_portal_group)
461
462    @call_cmd
463    def add_initiator_group(args):
464        rpc.iscsi.add_initiator_group(args.client, args)
465
466    p = subparsers.add_parser('add_initiator_group',
467                              help='Add an initiator group')
468    p.add_argument(
469        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
470    p.add_argument('initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
471    enclosed in quotes.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""")
472    p.add_argument('netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
473    Example: '255.255.0.0 255.248.0.0' etc""")
474    p.set_defaults(func=add_initiator_group)
475
476    @call_cmd
477    def add_initiators_to_initiator_group(args):
478        rpc.iscsi.add_initiators_to_initiator_group(args.client, args)
479
480    p = subparsers.add_parser('add_initiators_to_initiator_group',
481                              help='Add initiators to an existing initiator group')
482    p.add_argument(
483        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
484    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
485    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
486    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
487    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
488    p.set_defaults(func=add_initiators_to_initiator_group)
489
490    @call_cmd
491    def delete_initiators_from_initiator_group(args):
492        rpc.iscsi.delete_initiators_from_initiator_group(args.client, args)
493
494    p = subparsers.add_parser('delete_initiators_from_initiator_group',
495                              help='Delete initiators from an existing initiator group')
496    p.add_argument(
497        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
498    p.add_argument('-n', dest='initiator_list', help="""Whitespace-separated list of initiator hostnames or IP addresses,
499    enclosed in quotes.  This parameter can be omitted.  Example: 'ANY' or '127.0.0.1 192.168.200.100'""", required=False)
500    p.add_argument('-m', dest='netmask_list', help="""Whitespace-separated list of initiator netmasks enclosed in quotes.
501    This parameter can be omitted.  Example: '255.255.0.0 255.248.0.0' etc""", required=False)
502    p.set_defaults(func=delete_initiators_from_initiator_group)
503
504    @call_cmd
505    def delete_target_node(args):
506        rpc.iscsi.delete_target_node(args.client, args)
507
508    p = subparsers.add_parser('delete_target_node',
509                              help='Delete a target node')
510    p.add_argument('target_node_name',
511                   help='Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.')
512    p.set_defaults(func=delete_target_node)
513
514    @call_cmd
515    def delete_portal_group(args):
516        rpc.iscsi.delete_portal_group(args.client, args)
517
518    p = subparsers.add_parser('delete_portal_group',
519                              help='Delete a portal group')
520    p.add_argument(
521        'tag', help='Portal group tag (unique, integer > 0)', type=int)
522    p.set_defaults(func=delete_portal_group)
523
524    @call_cmd
525    def delete_initiator_group(args):
526        rpc.iscsi.delete_initiator_group(args.client, args)
527
528    p = subparsers.add_parser('delete_initiator_group',
529                              help='Delete an initiator group')
530    p.add_argument(
531        'tag', help='Initiator group tag (unique, integer > 0)', type=int)
532    p.set_defaults(func=delete_initiator_group)
533
534    @call_cmd
535    def get_iscsi_connections(args):
536        print_dict(rpc.iscsi.get_iscsi_connections(args.client, args))
537
538    p = subparsers.add_parser('get_iscsi_connections',
539                              help='Display iSCSI connections')
540    p.set_defaults(func=get_iscsi_connections)
541
542    @call_cmd
543    def get_iscsi_global_params(args):
544        print_dict(rpc.iscsi.get_iscsi_global_params(args.client, args))
545
546    p = subparsers.add_parser('get_iscsi_global_params', help='Display iSCSI global parameters')
547    p.set_defaults(func=get_iscsi_global_params)
548
549    @call_cmd
550    def get_scsi_devices(args):
551        print_dict(rpc.iscsi.get_scsi_devices(args.client, args))
552
553    p = subparsers.add_parser('get_scsi_devices', help='Display SCSI devices')
554    p.set_defaults(func=get_scsi_devices)
555
556    # log
557    @call_cmd
558    def set_trace_flag(args):
559        rpc.log.set_trace_flag(args.client, args)
560
561    p = subparsers.add_parser('set_trace_flag', help='set trace flag')
562    p.add_argument(
563        'flag', help='trace mask we want to set. (for example "nvme").')
564    p.set_defaults(func=set_trace_flag)
565
566    @call_cmd
567    def clear_trace_flag(args):
568        rpc.log.clear_trace_flag(args.client, args)
569
570    p = subparsers.add_parser('clear_trace_flag', help='clear trace flag')
571    p.add_argument(
572        'flag', help='trace mask we want to clear. (for example "nvme").')
573    p.set_defaults(func=clear_trace_flag)
574
575    @call_cmd
576    def get_trace_flags(args):
577        print_dict(rpc.log.get_trace_flags(args.client, args))
578
579    p = subparsers.add_parser('get_trace_flags', help='get trace flags')
580    p.set_defaults(func=get_trace_flags)
581
582    @call_cmd
583    def set_log_level(args):
584        rpc.log.set_log_level(args.client, args)
585
586    p = subparsers.add_parser('set_log_level', help='set log level')
587    p.add_argument('level', help='log level we want to set. (for example "DEBUG").')
588    p.set_defaults(func=set_log_level)
589
590    @call_cmd
591    def get_log_level(args):
592        print_dict(rpc.log.get_log_level(args.client, args))
593
594    p = subparsers.add_parser('get_log_level', help='get log level')
595    p.set_defaults(func=get_log_level)
596
597    @call_cmd
598    def set_log_print_level(args):
599        rpc.log.set_log_print_level(args.client, args)
600
601    p = subparsers.add_parser('set_log_print_level', help='set log print level')
602    p.add_argument('level', help='log print level we want to set. (for example "DEBUG").')
603    p.set_defaults(func=set_log_print_level)
604
605    @call_cmd
606    def get_log_print_level(args):
607        print_dict(rpc.log.get_log_print_level(args.client, args))
608
609    p = subparsers.add_parser('get_log_print_level', help='get log print level')
610    p.set_defaults(func=get_log_print_level)
611
612    # lvol
613    @call_cmd
614    def construct_lvol_store(args):
615        print_array(rpc.lvol.construct_lvol_store(args.client,
616                                                  bdev_name=args.bdev_name,
617                                                  lvs_name=args.lvs_name,
618                                                  cluster_sz=args.cluster_sz))
619
620    p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev')
621    p.add_argument('bdev_name', help='base bdev name')
622    p.add_argument('lvs_name', help='name for lvol store')
623    p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
624    p.set_defaults(func=construct_lvol_store)
625
626    @call_cmd
627    def rename_lvol_store(args):
628        rpc.lvol.rename_lvol_store(args.client,
629                                   old_name=args.old_name,
630                                   new_name=args.new_name)
631
632    p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
633    p.add_argument('old_name', help='old name')
634    p.add_argument('new_name', help='new name')
635    p.set_defaults(func=rename_lvol_store)
636
637    @call_cmd
638    def construct_lvol_bdev(args):
639        print_array(rpc.lvol.construct_lvol_bdev(args.client,
640                                                 lvol_name=args.lvol_name,
641                                                 size=args.size * 1024 * 1024,
642                                                 thin_provision=args.thin_provision,
643                                                 uuid=args.uuid,
644                                                 lvs_name=args.lvs_name))
645
646    p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
647    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
648    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
649    p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned')
650    p.add_argument('lvol_name', help='name for this lvol')
651    p.add_argument('size', help='size in MiB for this bdev', type=int)
652    p.set_defaults(func=construct_lvol_bdev)
653
654    @call_cmd
655    def snapshot_lvol_bdev(args):
656        rpc.lvol.snapshot_lvol_bdev(args.client,
657                                    lvol_name=args.lvol_name,
658                                    snapshot_name=args.snapshot_name)
659
660    p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
661    p.add_argument('lvol_name', help='lvol bdev name')
662    p.add_argument('snapshot_name', help='lvol snapshot name')
663    p.set_defaults(func=snapshot_lvol_bdev)
664
665    @call_cmd
666    def clone_lvol_bdev(args):
667        rpc.lvol.clone_lvol_bdev(args.client,
668                                 snapshot_name=args.snapshot_name,
669                                 clone_name=args.clone_name)
670
671    p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
672    p.add_argument('snapshot_name', help='lvol snapshot name')
673    p.add_argument('clone_name', help='lvol clone name')
674    p.set_defaults(func=clone_lvol_bdev)
675
676    @call_cmd
677    def rename_lvol_bdev(args):
678        rpc.lvol.rename_lvol_bdev(args.client,
679                                  old_name=args.old_name,
680                                  new_name=args.new_name)
681
682    p = subparsers.add_parser('rename_lvol_bdev', help='Change lvol bdev name')
683    p.add_argument('old_name', help='lvol bdev name')
684    p.add_argument('new_name', help='new lvol name')
685    p.set_defaults(func=rename_lvol_bdev)
686
687    @call_cmd
688    def inflate_lvol_bdev(args):
689        rpc.lvol.inflate_lvol_bdev(args.client,
690                                   name=args.name)
691
692    p = subparsers.add_parser('inflate_lvol_bdev', help='Make thin provisioned lvol a thick provisioned lvol')
693    p.add_argument('name', help='lvol bdev name')
694    p.set_defaults(func=inflate_lvol_bdev)
695
696    @call_cmd
697    def resize_lvol_bdev(args):
698        rpc.lvol.resize_lvol_bdev(args.client,
699                                  name=args.name,
700                                  size=args.size * 1024 * 1024)
701
702    p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev')
703    p.add_argument('name', help='lvol bdev name')
704    p.add_argument('size', help='new size in MiB for this bdev', type=int)
705    p.set_defaults(func=resize_lvol_bdev)
706
707    @call_cmd
708    def destroy_lvol_bdev(args):
709        rpc.lvol.destroy_lvol_bdev(args.client,
710                                   name=args.name)
711
712    p = subparsers.add_parser('destroy_lvol_bdev', help='Destroy a logical volume')
713    p.add_argument('name', help='lvol bdev name')
714    p.set_defaults(func=destroy_lvol_bdev)
715
716    @call_cmd
717    def destroy_lvol_store(args):
718        rpc.lvol.destroy_lvol_store(args.client,
719                                    uuid=args.uuid,
720                                    lvs_name=args.lvs_name)
721
722    p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store')
723    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
724    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
725    p.set_defaults(func=destroy_lvol_store)
726
727    @call_cmd
728    def get_lvol_stores(args):
729        print_dict(rpc.lvol.get_lvol_stores(args.client,
730                                            uuid=args.uuid,
731                                            lvs_name=args.lvs_name))
732
733    p = subparsers.add_parser('get_lvol_stores', help='Display current logical volume store list')
734    p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
735    p.add_argument('-l', '--lvs-name', help='lvol store name', required=False)
736    p.set_defaults(func=get_lvol_stores)
737
738    # split
739    @call_cmd
740    def construct_split_vbdev(args):
741        print_dict(rpc.bdev.construct_split_vbdev(args.client,
742                                                  base_bdev=args.base_bdev,
743                                                  split_count=args.split_count,
744                                                  split_size_mb=args.split_size_mb))
745
746    p = subparsers.add_parser('construct_split_vbdev', help="""Add given disk name to split config. If bdev with base_name
747    name exist the split bdevs will be created right away, if not split bdevs will be created when base bdev became
748    available (during examination process).""")
749    p.add_argument('base_bdev', help='base bdev name')
750    p.add_argument('-s', '--split-size-mb', help='size in MiB for each bdev', type=int, default=0)
751    p.add_argument('split_count', help="""Optional - number of split bdevs to create. Total size * split_count must not
752    exceed the base bdev size.""", type=int)
753    p.set_defaults(func=construct_split_vbdev)
754
755    @call_cmd
756    def destruct_split_vbdev(args):
757        rpc.bdev.destruct_split_vbdev(args.client,
758                                      base_bdev=args.base_bdev)
759
760    p = subparsers.add_parser('destruct_split_vbdev', help="""Delete split config with all created splits.""")
761    p.add_argument('base_bdev', help='base bdev name')
762    p.set_defaults(func=destruct_split_vbdev)
763
764    # nbd
765    @call_cmd
766    def start_nbd_disk(args):
767        print(rpc.nbd.start_nbd_disk(args.client,
768                                     bdev_name=args.bdev_name,
769                                     nbd_device=args.nbd_device))
770
771    p = subparsers.add_parser('start_nbd_disk', help='Export a bdev as a nbd disk')
772    p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
773    p.add_argument('nbd_device', help='Nbd device name to be assigned. Example: /dev/nbd0.')
774    p.set_defaults(func=start_nbd_disk)
775
776    @call_cmd
777    def stop_nbd_disk(args):
778        rpc.nbd.stop_nbd_disk(args.client,
779                              nbd_device=args.nbd_device)
780
781    p = subparsers.add_parser('stop_nbd_disk', help='Stop a nbd disk')
782    p.add_argument('nbd_device', help='Nbd device name to be stopped. Example: /dev/nbd0.')
783    p.set_defaults(func=stop_nbd_disk)
784
785    @call_cmd
786    def get_nbd_disks(args):
787        print_dict(rpc.nbd.get_nbd_disks(args.client,
788                                         nbd_device=args.nbd_device))
789
790    p = subparsers.add_parser('get_nbd_disks', help='Display full or specified nbd device list')
791    p.add_argument('-n', '--nbd-device', help="Path of the nbd device. Example: /dev/nbd0", required=False)
792    p.set_defaults(func=get_nbd_disks)
793
794    # net
795    @call_cmd
796    def add_ip_address(args):
797        rpc.net.add_ip_address(args.client, args)
798
799    p = subparsers.add_parser('add_ip_address', help='Add IP address')
800    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
801    p.add_argument('ip_addr', help='ip address will be added.')
802    p.set_defaults(func=add_ip_address)
803
804    @call_cmd
805    def delete_ip_address(args):
806        rpc.net.delete_ip_address(args.client, args)
807
808    p = subparsers.add_parser('delete_ip_address', help='Delete IP address')
809    p.add_argument('ifc_index', help='ifc index of the nic device.', type=int)
810    p.add_argument('ip_addr', help='ip address will be deleted.')
811    p.set_defaults(func=delete_ip_address)
812
813    @call_cmd
814    def get_interfaces(args):
815        print_dict(rpc.net.get_interfaces(args.client, args))
816
817    p = subparsers.add_parser(
818        'get_interfaces', help='Display current interface list')
819    p.set_defaults(func=get_interfaces)
820
821    # NVMe-oF
822    @call_cmd
823    def get_nvmf_subsystems(args):
824        print_dict(rpc.nvmf.get_nvmf_subsystems(args.client, args))
825
826    p = subparsers.add_parser('get_nvmf_subsystems',
827                              help='Display nvmf subsystems')
828    p.set_defaults(func=get_nvmf_subsystems)
829
830    @call_cmd
831    def construct_nvmf_subsystem(args):
832        rpc.nvmf.construct_nvmf_subsystem(args.client, args)
833
834    p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
835    p.add_argument('nqn', help='Target nqn(ASCII)')
836    p.add_argument('listen', help="""comma-separated list of Listen <trtype:transport_name traddr:address trsvcid:port_id> pairs enclosed
837    in quotes.  Format:  'trtype:transport0 traddr:traddr0 trsvcid:trsvcid0,trtype:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
838    Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.168.100.9 trsvcid:4420'""")
839    p.add_argument('hosts', help="""Whitespace-separated list of host nqn list.
840    Format:  'nqn1 nqn2' etc
841    Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""")
842    p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)")
843    p.add_argument("-s", "--serial-number", help="""
844    Format:  'sn' etc
845    Example: 'SPDK00000000000001'""", default='0000:00:01.0')
846    p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces
847    Format:  'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc
848    Example: '1:Malloc0 2:Malloc1 3:Malloc2'
849    *** The devices must pre-exist ***""")
850    p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection",
851                   type=int, default=0)
852    p.set_defaults(func=construct_nvmf_subsystem)
853
854    @call_cmd
855    def delete_nvmf_subsystem(args):
856        rpc.nvmf.delete_nvmf_subsystem(args.client, args)
857
858    p = subparsers.add_parser('delete_nvmf_subsystem',
859                              help='Delete a nvmf subsystem')
860    p.add_argument('subsystem_nqn',
861                   help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
862    p.set_defaults(func=delete_nvmf_subsystem)
863
864    @call_cmd
865    def nvmf_subsystem_add_listener(args):
866        rpc.nvmf.nvmf_subsystem_add_listener(args.client, args)
867
868    p = subparsers.add_parser('nvmf_subsystem_add_listener', help='Add a listener to an NVMe-oF subsystem')
869    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
870    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
871    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
872    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
873    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
874    p.set_defaults(func=nvmf_subsystem_add_listener)
875
876    @call_cmd
877    def nvmf_subsystem_remove_listener(args):
878        rpc.nvmf.nvmf_subsystem_remove_listener(args.client, args)
879
880    p = subparsers.add_parser('nvmf_subsystem_remove_listener', help='Remove a listener from an NVMe-oF subsystem')
881    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
882    p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True)
883    p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True)
884    p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host')
885    p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
886    p.set_defaults(func=nvmf_subsystem_remove_listener)
887
888    @call_cmd
889    def nvmf_subsystem_add_ns(args):
890        rpc.nvmf.nvmf_subsystem_add_ns(args.client, args)
891
892    p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem')
893    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
894    p.add_argument('bdev_name', help='The name of the bdev that will back this namespace')
895    p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int)
896    p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)')
897    p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)')
898    p.add_argument('-u', '--uuid', help='Namespace UUID (optional)')
899    p.set_defaults(func=nvmf_subsystem_add_ns)
900
901    @call_cmd
902    def nvmf_subsystem_remove_ns(args):
903        rpc.nvmf.nvmf_subsystem_remove_ns(args.client, args)
904
905    p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem')
906    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
907    p.add_argument('nsid', help='The requested NSID', type=int)
908    p.set_defaults(func=nvmf_subsystem_remove_ns)
909
910    @call_cmd
911    def nvmf_subsystem_add_host(args):
912        rpc.nvmf.nvmf_subsystem_add_host(args.client, args)
913
914    p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem')
915    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
916    p.add_argument('host', help='Host NQN to allow')
917    p.set_defaults(func=nvmf_subsystem_add_host)
918
919    @call_cmd
920    def nvmf_subsystem_remove_host(args):
921        rpc.nvmf.nvmf_subsystem_remove_host(args.client, args)
922
923    p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem')
924    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
925    p.add_argument('host', help='Host NQN to remove')
926    p.set_defaults(func=nvmf_subsystem_remove_host)
927
928    @call_cmd
929    def nvmf_subsystem_allow_any_host(args):
930        rpc.nvmf.nvmf_subsystem_allow_any_host(args.client, args)
931
932    p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem')
933    p.add_argument('nqn', help='NVMe-oF subsystem NQN')
934    p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host')
935    p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host')
936    p.set_defaults(func=nvmf_subsystem_allow_any_host)
937
938    # pmem
939    @call_cmd
940    def create_pmem_pool(args):
941        rpc.pmem.create_pmem_pool(args.client, args)
942
943    p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool')
944    p.add_argument('pmem_file', help='Path to pmemblk pool file')
945    p.add_argument('total_size', help='Size of malloc bdev in MB (int > 0)', type=int)
946    p.add_argument('block_size', help='Block size for this pmem pool', type=int)
947    p.set_defaults(func=create_pmem_pool)
948
949    @call_cmd
950    def pmem_pool_info(args):
951        print_dict(rpc.pmem.pmem_pool_info(args.client, args))
952
953    p = subparsers.add_parser('pmem_pool_info', help='Display pmem pool info and check consistency')
954    p.add_argument('pmem_file', help='Path to pmemblk pool file')
955    p.set_defaults(func=pmem_pool_info)
956
957    @call_cmd
958    def delete_pmem_pool(args):
959        rpc.pmem.delete_pmem_pool(args.client, args)
960
961    p = subparsers.add_parser('delete_pmem_pool', help='Delete pmem pool')
962    p.add_argument('pmem_file', help='Path to pmemblk pool file')
963    p.set_defaults(func=delete_pmem_pool)
964
965    # subsystem
966    @call_cmd
967    def get_subsystems(args):
968        print_dict(rpc.subsystem.get_subsystems(args.client))
969
970    p = subparsers.add_parser('get_subsystems', help="""Print subsystems array in initialization order. Each subsystem
971    entry contain (unsorted) array of subsystems it depends on.""")
972    p.set_defaults(func=get_subsystems)
973
974    @call_cmd
975    def get_subsystem_config(args):
976        print_dict(rpc.subsystem.get_subsystem_config(args.client, args.name))
977
978    p = subparsers.add_parser('get_subsystem_config', help="""Print subsystem configuration""")
979    p.add_argument('name', help='Name of subsystem to query')
980    p.set_defaults(func=get_subsystem_config)
981
982    # vhost
983    @call_cmd
984    def set_vhost_controller_coalescing(args):
985        rpc.vhost.set_vhost_controller_coalescing(args.client, args)
986
987    p = subparsers.add_parser('set_vhost_controller_coalescing', help='Set vhost controller coalescing')
988    p.add_argument('ctrlr', help='controller name')
989    p.add_argument('delay_base_us', help='Base delay time', type=int)
990    p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
991    p.set_defaults(func=set_vhost_controller_coalescing)
992
993    @call_cmd
994    def construct_vhost_scsi_controller(args):
995        rpc.vhost.construct_vhost_scsi_controller(args.client, args)
996
997    p = subparsers.add_parser(
998        'construct_vhost_scsi_controller', help='Add new vhost controller')
999    p.add_argument('ctrlr', help='controller name')
1000    p.add_argument('--cpumask', help='cpu mask for this controller')
1001    p.set_defaults(func=construct_vhost_scsi_controller)
1002
1003    @call_cmd
1004    def add_vhost_scsi_lun(args):
1005        rpc.vhost.add_vhost_scsi_lun(args.client, args)
1006
1007    p = subparsers.add_parser('add_vhost_scsi_lun',
1008                              help='Add lun to vhost controller')
1009    p.add_argument('ctrlr', help='conntroller name where add lun')
1010    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1011    p.add_argument('bdev_name', help='bdev name')
1012    p.set_defaults(func=add_vhost_scsi_lun)
1013
1014    @call_cmd
1015    def remove_vhost_scsi_target(args):
1016        rpc.vhost.remove_vhost_scsi_target(args.client, args)
1017
1018    p = subparsers.add_parser('remove_vhost_scsi_target', help='Remove target from vhost controller')
1019    p.add_argument('ctrlr', help='controller name to remove target from')
1020    p.add_argument('scsi_target_num', help='scsi_target_num', type=int)
1021    p.set_defaults(func=remove_vhost_scsi_target)
1022
1023    @call_cmd
1024    def construct_vhost_blk_controller(args):
1025        rpc.vhost.construct_vhost_blk_controller(args.client, args)
1026
1027    p = subparsers.add_parser('construct_vhost_blk_controller', help='Add a new vhost block controller')
1028    p.add_argument('ctrlr', help='controller name')
1029    p.add_argument('dev_name', help='device name')
1030    p.add_argument('--cpumask', help='cpu mask for this controller')
1031    p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
1032    p.set_defaults(func=construct_vhost_blk_controller)
1033
1034    @call_cmd
1035    def construct_vhost_nvme_controller(args):
1036        rpc.vhost.construct_vhost_nvme_controller(args.client, args)
1037
1038    p = subparsers.add_parser('construct_vhost_nvme_controller', help='Add new vhost controller')
1039    p.add_argument('ctrlr', help='controller name')
1040    p.add_argument('io_queues', help='number of IO queues for the controller', type=int)
1041    p.add_argument('--cpumask', help='cpu mask for this controller')
1042    p.set_defaults(func=construct_vhost_nvme_controller)
1043
1044    @call_cmd
1045    def add_vhost_nvme_ns(args):
1046        rpc.vhost.add_vhost_nvme_ns(args.client, args)
1047
1048    p = subparsers.add_parser('add_vhost_nvme_ns', help='Add a Namespace to vhost controller')
1049    p.add_argument('ctrlr', help='conntroller name where add a Namespace')
1050    p.add_argument('bdev_name', help='block device name for a new Namespace')
1051    p.set_defaults(func=add_vhost_nvme_ns)
1052
1053    @call_cmd
1054    def get_vhost_controllers(args):
1055        print_dict(rpc.vhost.get_vhost_controllers(args.client, args))
1056
1057    p = subparsers.add_parser('get_vhost_controllers', help='List vhost controllers')
1058    p.set_defaults(func=get_vhost_controllers)
1059
1060    @call_cmd
1061    def remove_vhost_controller(args):
1062        rpc.vhost.remove_vhost_controller(args.client, args)
1063
1064    p = subparsers.add_parser('remove_vhost_controller', help='Remove a vhost controller')
1065    p.add_argument('ctrlr', help='controller name')
1066    p.set_defaults(func=remove_vhost_controller)
1067
1068    @call_cmd
1069    def construct_virtio_dev(args):
1070        print_dict(rpc.vhost.construct_virtio_dev(args.client, args))
1071
1072    p = subparsers.add_parser('construct_virtio_dev', help="""Construct new virtio device using provided
1073    transport type and device type. In case of SCSI device type this implies scan and add bdevs offered by
1074    remote side. Result is array of added bdevs.""")
1075    p.add_argument('name', help="Use this name as base for new created bdevs")
1076    p.add_argument('-t', '--trtype',
1077                   help='Virtio target transport type: pci or user', required=True)
1078    p.add_argument('-a', '--traddr',
1079                   help='Transport type specific target address: e.g. UNIX domain socket path or BDF', required=True)
1080    p.add_argument('-d', '--dev-type',
1081                   help='Device type: blk or scsi', required=True)
1082    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1083    p.add_argument('--vq-size', help='Size of each queue', type=int)
1084    p.set_defaults(func=construct_virtio_dev)
1085
1086    @call_cmd
1087    def construct_virtio_user_scsi_bdev(args):
1088        print_dict(rpc.vhost.construct_virtio_user_scsi_bdev(args.client, args))
1089
1090    p = subparsers.add_parser('construct_virtio_user_scsi_bdev', help="""Connect to virtio user scsi device.
1091    This imply scan and add bdevs offered by remote side.
1092    Result is array of added bdevs.""")
1093    p.add_argument('path', help='Path to Virtio SCSI socket')
1094    p.add_argument('name', help="""Use this name as base instead of 'VirtioScsiN'
1095    Base will be used to construct new bdev's found on target by adding 't<TARGET_ID>' sufix.""")
1096    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1097    p.add_argument('--vq-size', help='Size of each queue', type=int)
1098    p.set_defaults(func=construct_virtio_user_scsi_bdev)
1099
1100    @call_cmd
1101    def construct_virtio_pci_scsi_bdev(args):
1102        print_dict(rpc.vhost.construct_virtio_pci_scsi_bdev(args.client, args))
1103
1104    p = subparsers.add_parser('construct_virtio_pci_scsi_bdev', help="""Create a Virtio
1105    SCSI device from a virtio-pci device.""")
1106    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1107    domain.bus.device.function format""")
1108    p.add_argument('name', help="""Name for the virtio device.
1109    It will be inhereted by all created bdevs, which are named n the following format: <name>t<target_id>""")
1110    p.set_defaults(func=construct_virtio_pci_scsi_bdev)
1111
1112    @call_cmd
1113    def get_virtio_scsi_devs(args):
1114        print_dict(rpc.vhost.get_virtio_scsi_devs(args.client, args))
1115
1116    p = subparsers.add_parser('get_virtio_scsi_devs', help='List all Virtio-SCSI devices.')
1117    p.set_defaults(func=get_virtio_scsi_devs)
1118
1119    @call_cmd
1120    def remove_virtio_scsi_bdev(args):
1121        rpc.vhost.remove_virtio_scsi_bdev(args.client, args)
1122
1123    p = subparsers.add_parser('remove_virtio_scsi_bdev', help="""Remove a Virtio-SCSI device
1124    This will delete all bdevs exposed by this device""")
1125    p.add_argument('name', help='Virtio device name. E.g. VirtioUser0')
1126    p.set_defaults(func=remove_virtio_scsi_bdev)
1127
1128    @call_cmd
1129    def construct_virtio_user_blk_bdev(args):
1130        print_dict(rpc.vhost.construct_virtio_user_blk_bdev(args.client, args))
1131
1132    p = subparsers.add_parser('construct_virtio_user_blk_bdev', help='Connect to a virtio user blk device.')
1133    p.add_argument('path', help='Path to Virtio BLK socket')
1134    p.add_argument('name', help='Name for the bdev')
1135    p.add_argument('--vq-count', help='Number of virtual queues to be used.', type=int)
1136    p.add_argument('--vq-size', help='Size of each queue', type=int)
1137    p.set_defaults(func=construct_virtio_user_blk_bdev)
1138
1139    @call_cmd
1140    def construct_virtio_pci_blk_bdev(args):
1141        print_dict(rpc.vhost.construct_virtio_pci_blk_bdev(args.client, args))
1142
1143    p = subparsers.add_parser('construct_virtio_pci_blk_bdev', help='Create a Virtio Blk device from a virtio-pci device.')
1144    p.add_argument('pci_address', help="""PCI address in domain:bus:device.function format or
1145    domain.bus.device.function format""")
1146    p.add_argument('name', help='Name for the bdev')
1147    p.set_defaults(func=construct_virtio_pci_blk_bdev)
1148
1149    args = parser.parse_args()
1150
1151    try:
1152        args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.verbose, args.timeout)
1153    except JSONRPCException as ex:
1154        print(ex.message)
1155        exit(1)
1156    args.func(args)
1157