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