1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright (C) 2018 Intel Corporation. 3# All rights reserved. 4 5from configshell_fb import ConfigNode, ExecutionError 6from uuid import UUID 7from ..rpc.client import JSONRPCException 8import json 9 10 11def convert_bytes_to_human(size): 12 if size == 0: 13 return "%3.1f%s" % (size, "bytes") 14 if not size: 15 return "" 16 for x in ["bytes", "K", "M", "G", "T"]: 17 if size < 1024.0: 18 return "%3.1f%s" % (size, x) 19 size /= 1024.0 20 21 22class UINode(ConfigNode): 23 def __init__(self, name, parent=None, shell=None): 24 ConfigNode.__init__(self, name, parent, shell) 25 26 def refresh(self): 27 for child in self.children: 28 child.refresh() 29 30 def refresh_node(self): 31 self.refresh() 32 33 def ui_command_refresh(self): 34 self.refresh() 35 36 def ui_command_ll(self, path=None, depth=None): 37 """ 38 Alias for ls. 39 """ 40 self.ui_command_ls(path, depth) 41 42 def execute_command(self, command, pparams=[], kparams={}): 43 try: 44 result = ConfigNode.execute_command(self, command, 45 pparams, kparams) 46 except Exception as e: 47 raise e 48 else: 49 self.shell.log.debug("Command %s succeeded." % command) 50 return result 51 finally: 52 if self.shell.interactive and\ 53 command in ["create", "start", "delete", "delete_all", "add_initiator", 54 "allow_any_host", "bdev_split_create", "add_lun", 55 "iscsi_target_node_add_pg_ig_maps", "remove_target", "add_secret", 56 "bdev_split_delete", "delete_secret_all", 57 "delete_initiator", "set_auth", "delete_secret", 58 "iscsi_target_node_remove_pg_ig_maps", "load_config", 59 "load_subsystem_config"]: 60 self.get_root().refresh() 61 self.refresh_node() 62 63 64class UIBdevs(UINode): 65 def __init__(self, parent): 66 UINode.__init__(self, "bdevs", parent) 67 self.refresh() 68 69 def refresh(self): 70 self._children = set([]) 71 UIMallocBdev(self) 72 UIAIOBdev(self) 73 UILvolBdev(self) 74 UINvmeBdev(self) 75 UINullBdev(self) 76 UIErrorBdev(self) 77 UISplitBdev(self) 78 UIRbdBdev(self) 79 UIiSCSIBdev(self) 80 UIVirtioBlkBdev(self) 81 UIVirtioScsiBdev(self) 82 UIRaidBdev(self) 83 UIUringBdev(self) 84 UICompressBdev(self) 85 86 87class UILvolStores(UINode): 88 def __init__(self, parent): 89 UINode.__init__(self, "lvol_stores", parent) 90 self.refresh() 91 92 def refresh(self): 93 self._children = set([]) 94 for lvs in self.get_root().bdev_lvol_get_lvstores(): 95 UILvsObj(lvs, self) 96 97 def delete(self, name, uuid): 98 if name is None and uuid is None: 99 self.shell.log.error("Please specify one of the identifiers: " 100 "lvol store name or UUID") 101 self.get_root().bdev_lvol_delete_lvstore(lvs_name=name, uuid=uuid) 102 103 def ui_command_create(self, name, bdev_name, cluster_size=None): 104 """ 105 Creates logical volume store on target bdev. 106 107 Arguments: 108 name - Friendly name to use alongside with UUID identifier. 109 bdev_name - On which bdev to create the lvol store. 110 cluster_size - Cluster size to use when creating lvol store, in bytes. Default: 4194304. 111 """ 112 113 cluster_size = self.ui_eval_param(cluster_size, "number", None) 114 self.get_root().bdev_lvol_create_lvstore(lvs_name=name, bdev_name=bdev_name, cluster_sz=cluster_size) 115 116 def ui_command_delete(self, name=None, uuid=None): 117 """ 118 Deletes logical volume store from configuration. 119 This will also delete all logical volume bdevs created on this lvol store! 120 121 Arguments: 122 name - Friendly name of the logical volume store to be deleted. 123 uuid - UUID number of the logical volume store to be deleted. 124 """ 125 self.delete(name, uuid) 126 127 def ui_command_delete_all(self): 128 rpc_messages = "" 129 for lvs in self._children: 130 try: 131 self.delete(None, lvs.lvs.uuid) 132 except JSONRPCException as e: 133 rpc_messages += e.message 134 if rpc_messages: 135 raise JSONRPCException(rpc_messages) 136 137 def summary(self): 138 return "Lvol stores: %s" % len(self.children), None 139 140 141class UIBdev(UINode): 142 def __init__(self, name, parent): 143 UINode.__init__(self, name, parent) 144 self.refresh() 145 146 def refresh(self): 147 self._children = set([]) 148 for bdev in self.get_root().bdev_get_bdevs(self.name): 149 UIBdevObj(bdev, self) 150 151 def ui_command_get_bdev_iostat(self, name=None): 152 ret = self.get_root().bdev_get_iostat(name=name) 153 self.shell.log.info(json.dumps(ret, indent=2)) 154 155 def ui_command_delete_all(self): 156 """Delete all bdevs from this tree node.""" 157 rpc_messages = "" 158 for bdev in self._children: 159 try: 160 self.delete(bdev.name) 161 except JSONRPCException as e: 162 rpc_messages += e.message 163 if rpc_messages: 164 raise JSONRPCException(rpc_messages) 165 166 def summary(self): 167 return "Bdevs: %d" % len(self.children), None 168 169 170class UIMallocBdev(UIBdev): 171 def __init__(self, parent): 172 UIBdev.__init__(self, "malloc", parent) 173 174 def delete(self, name): 175 self.get_root().bdev_malloc_delete(name=name) 176 177 def ui_command_create(self, size, block_size, name=None, uuid=None): 178 """ 179 Construct a Malloc bdev. 180 181 Arguments: 182 size - Size in megabytes. 183 block_size - Integer, block size to use when constructing bdev. 184 name - Optional argument. Custom name to use for bdev. If not provided 185 then name will be "MallocX" where X is next available ID. 186 uuid - Optional parameter. Custom UUID to use. If empty then random 187 will be generated. 188 """ 189 190 size = self.ui_eval_param(size, "number", None) 191 block_size = self.ui_eval_param(block_size, "number", None) 192 ret_name = self.get_root().create_malloc_bdev(num_blocks=size * 1024 * 1024 // block_size, 193 block_size=block_size, 194 name=name, uuid=uuid) 195 self.shell.log.info(ret_name) 196 197 def ui_command_delete(self, name): 198 """ 199 Deletes malloc bdev from configuration. 200 201 Arguments: 202 name - Is a unique identifier of the malloc bdev to be deleted - UUID number or name alias. 203 """ 204 self.delete(name) 205 206 207class UIAIOBdev(UIBdev): 208 def __init__(self, parent): 209 UIBdev.__init__(self, "aio", parent) 210 211 def delete(self, name): 212 self.get_root().bdev_aio_delete(name=name) 213 214 def ui_command_create(self, name, filename, block_size): 215 """ 216 Construct an AIO bdev. 217 Backend file must exist before trying to create an AIO bdev. 218 219 Arguments: 220 name - Optional argument. Custom name to use for bdev. If not provided 221 then name will be "MallocX" where X is next available ID. 222 filename - Path to AIO backend. 223 block_size - Integer, block size to use when constructing bdev. 224 """ 225 226 block_size = self.ui_eval_param(block_size, "number", None) 227 ret_name = self.get_root().bdev_aio_create(name=name, 228 block_size=int(block_size), 229 filename=filename) 230 self.shell.log.info(ret_name) 231 232 def ui_command_delete(self, name): 233 """ 234 Deletes aio bdev from configuration. 235 236 Arguments: 237 name - Is a unique identifier of the aio bdev to be deleted - UUID number or name alias. 238 """ 239 self.delete(name) 240 241 242class UILvolBdev(UIBdev): 243 def __init__(self, parent): 244 UIBdev.__init__(self, "logical_volume", parent) 245 246 def delete(self, name): 247 self.get_root().bdev_lvol_delete(name=name) 248 249 def ui_command_create(self, name, size, lvs, thin_provision=None): 250 """ 251 Construct a Logical Volume bdev. 252 253 Arguments: 254 name - Friendly name to use for creating logical volume bdev. 255 size - Size in megabytes. 256 lvs - Identifier of logical volume store on which the bdev should be 257 created. Can be either a friendly name or UUID. 258 thin_provision - Whether the bdev should be thick or thin provisioned. 259 Default is False, and created bdevs are thick-provisioned. 260 """ 261 uuid = None 262 lvs_name = None 263 try: 264 UUID(lvs) 265 uuid = lvs 266 except ValueError: 267 lvs_name = lvs 268 269 size = self.ui_eval_param(size, "number", None) 270 thin_provision = self.ui_eval_param(thin_provision, "bool", False) 271 272 ret_uuid = self.get_root().create_lvol_bdev(lvol_name=name, size_in_mib=size, 273 lvs_name=lvs_name, uuid=uuid, 274 thin_provision=thin_provision) 275 self.shell.log.info(ret_uuid) 276 277 def ui_command_delete(self, name): 278 """ 279 Deletes lvol bdev from configuration. 280 281 Arguments: 282 name - Is a unique identifier of the lvol bdev to be deleted - UUID number or name alias. 283 """ 284 self.delete(name) 285 286 287class UINvmeBdev(UIBdev): 288 def __init__(self, parent): 289 UIBdev.__init__(self, "nvme", parent) 290 291 def delete(self, name): 292 self.get_root().bdev_nvme_detach_controller(name=name) 293 294 def ui_command_create(self, name, trtype, traddr, 295 adrfam=None, trsvcid=None, subnqn=None): 296 if "rdma" in trtype and None in [adrfam, trsvcid, subnqn]: 297 self.shell.log.error("Using RDMA transport type." 298 "Please provide arguments for adrfam, trsvcid and subnqn.") 299 ret_name = self.get_root().create_nvme_bdev(name=name, trtype=trtype, 300 traddr=traddr, adrfam=adrfam, 301 trsvcid=trsvcid, subnqn=subnqn) 302 self.shell.log.info(ret_name) 303 304 def ui_command_delete_all(self): 305 rpc_messages = "" 306 ctrlrs = [x.name for x in self._children] 307 ctrlrs = [x.rsplit("n", 1)[0] for x in ctrlrs] 308 ctrlrs = set(ctrlrs) 309 for ctrlr in ctrlrs: 310 try: 311 self.delete(ctrlr) 312 except JSONRPCException as e: 313 rpc_messages += e.messages 314 if rpc_messages: 315 raise JSONRPCException(rpc_messages) 316 317 def ui_command_delete(self, name): 318 """ 319 Deletes NVMe controller from configuration. 320 321 Arguments: 322 name - Is a unique identifier of the NVMe controller to be deleted. 323 """ 324 self.delete(name) 325 326 327class UINullBdev(UIBdev): 328 def __init__(self, parent): 329 UIBdev.__init__(self, "null", parent) 330 331 def delete(self, name): 332 self.get_root().bdev_null_delete(name=name) 333 334 def ui_command_create(self, name, size, block_size, uuid=None): 335 """ 336 Construct a Null bdev. 337 338 Arguments: 339 name - Name to use for bdev. 340 size - Size in megabytes. 341 block_size - Integer, block size to use when constructing bdev. 342 uuid - Optional parameter. Custom UUID to use. If empty then random 343 will be generated. 344 """ 345 346 size = self.ui_eval_param(size, "number", None) 347 block_size = self.ui_eval_param(block_size, "number", None) 348 num_blocks = size * 1024 * 1024 // block_size 349 ret_name = self.get_root().bdev_null_create(num_blocks=num_blocks, 350 block_size=block_size, 351 name=name, uuid=uuid) 352 self.shell.log.info(ret_name) 353 354 def ui_command_delete(self, name): 355 """ 356 Deletes null bdev from configuration. 357 358 Arguments: 359 name - Is a unique identifier of the null bdev to be deleted - UUID number or name alias. 360 """ 361 self.delete(name) 362 363 364class UIErrorBdev(UIBdev): 365 def __init__(self, parent): 366 UIBdev.__init__(self, "error", parent) 367 368 def delete(self, name): 369 self.get_root().bdev_error_delete(name=name) 370 371 def ui_command_create(self, base_name): 372 """ 373 Construct a error injection bdev. 374 375 Arguments: 376 base_name - base bdev name on top of which error bdev will be created. 377 """ 378 379 self.get_root().create_error_bdev(base_name=base_name) 380 381 def ui_command_delete(self, name): 382 """ 383 Deletes error bdev from configuration. 384 385 Arguments: 386 name - Is a unique identifier of the error bdev to be deleted - UUID number or name alias. 387 """ 388 self.delete(name) 389 390 391class UISplitBdev(UIBdev): 392 def __init__(self, parent): 393 UIBdev.__init__(self, "split_disk", parent) 394 395 def delete(self, name): 396 pass 397 398 def ui_command_bdev_split_create(self, base_bdev, split_count, split_size_mb=None): 399 """ 400 Create split block devices from a base bdev. 401 402 Arguments: 403 base_bdev - Name of bdev to split 404 split_count - Number of split bdevs to create 405 split_size_mb- Size of each split volume in MiB (optional) 406 """ 407 408 split_count = self.ui_eval_param(split_count, "number", None) 409 split_size_mb = self.ui_eval_param(split_size_mb, "number", None) 410 411 ret_name = self.get_root().bdev_split_create(base_bdev=base_bdev, 412 split_count=split_count, 413 split_size_mb=split_size_mb) 414 self.shell.log.info(ret_name) 415 416 def ui_command_bdev_split_delete(self, base_bdev): 417 """Delete split block devices associated with base bdev. 418 419 Args: 420 base_bdev: name of previously split bdev 421 """ 422 423 self.get_root().bdev_split_delete(base_bdev=base_bdev) 424 425 426class UIRbdBdev(UIBdev): 427 def __init__(self, parent): 428 UIBdev.__init__(self, "rbd", parent) 429 430 def delete(self, name): 431 self.get_root().bdev_rbd_delete(name=name) 432 433 def ui_command_create(self, pool_name, rbd_name, block_size, name=None): 434 block_size = self.ui_eval_param(block_size, "number", None) 435 436 ret_name = self.get_root().create_rbd_bdev(pool_name=pool_name, 437 rbd_name=rbd_name, 438 block_size=block_size, 439 name=name) 440 self.shell.log.info(ret_name) 441 442 def ui_command_delete(self, name): 443 """ 444 Deletes rbd bdev from configuration. 445 446 Arguments: 447 name - Is a unique identifier of the rbd bdev to be deleted - UUID number or name alias. 448 """ 449 self.delete(name) 450 451 452class UIiSCSIBdev(UIBdev): 453 def __init__(self, parent): 454 UIBdev.__init__(self, "iscsi", parent) 455 456 def delete(self, name): 457 self.get_root().bdev_iscsi_delete(name=name) 458 459 def ui_command_create(self, name, url, initiator_iqn): 460 """ 461 Create iSCSI bdev in configuration by connecting to remote 462 iSCSI target. 463 464 Arguments: 465 name - name to be used as an ID for created iSCSI bdev. 466 url - iscsi url pointing to LUN on remote iSCSI target. 467 Example: iscsi://127.0.0.1:3260/iqn.2018-06.org.spdk/0. 468 initiator_iqn - IQN to use for initiating connection with the target. 469 """ 470 ret_name = self.get_root().create_iscsi_bdev(name=name, 471 url=url, 472 initiator_iqn=initiator_iqn) 473 self.shell.log.info(ret_name) 474 475 def ui_command_delete(self, name): 476 """ 477 Deletes iSCSI bdev from configuration. 478 479 Arguments: 480 name - name of the iscsi bdev to be deleted. 481 """ 482 self.delete(name) 483 484 485class UIVirtioBlkBdev(UIBdev): 486 def __init__(self, parent): 487 UIBdev.__init__(self, "virtioblk_disk", parent) 488 489 def ui_command_create(self, name, trtype, traddr, 490 vq_count=None, vq_size=None): 491 492 vq_count = self.ui_eval_param(vq_count, "number", None) 493 vq_size = self.ui_eval_param(vq_size, "number", None) 494 495 ret = self.get_root().create_virtio_dev(name=name, 496 trtype=trtype, 497 traddr=traddr, 498 dev_type="blk", 499 vq_count=vq_count, 500 vq_size=vq_size) 501 502 self.shell.log.info(ret) 503 504 def ui_command_delete(self, name): 505 """ 506 Deletes virtio scsi bdev from configuration. 507 508 Arguments: 509 name - Is a unique identifier of the virtio scsi bdev to be deleted - UUID number or name alias. 510 """ 511 self.get_root().bdev_virtio_detach_controller(name=name) 512 513 514class UIVirtioScsiBdev(UIBdev): 515 def __init__(self, parent): 516 UIBdev.__init__(self, "virtioscsi_disk", parent) 517 518 def refresh(self): 519 self._children = set([]) 520 for bdev in self.get_root().bdev_virtio_scsi_get_devices(): 521 UIVirtioScsiBdevObj(bdev, self) 522 523 def ui_command_create(self, name, trtype, traddr, 524 vq_count=None, vq_size=None): 525 526 vq_count = self.ui_eval_param(vq_count, "number", None) 527 vq_size = self.ui_eval_param(vq_size, "number", None) 528 529 ret = self.get_root().create_virtio_dev(name=name, 530 trtype=trtype, 531 traddr=traddr, 532 dev_type="scsi", 533 vq_count=vq_count, 534 vq_size=vq_size) 535 536 self.shell.log.info(ret) 537 538 def ui_command_delete(self, name): 539 self.get_root().bdev_virtio_detach_controller(name=name) 540 541 542class UIBdevObj(UINode): 543 def __init__(self, bdev, parent): 544 self.bdev = bdev 545 # Using bdev name also for lvol bdevs, which results in displaying 546 # UUID instead of alias. This is because alias naming convention 547 # (lvol_store_name/lvol_bdev_name) conflicts with configshell paths 548 # ("/" as separator). 549 # Solution: show lvol alias in "summary field" for now. 550 # TODO: Possible next steps: 551 # - Either change default separator in tree for smth else 552 # - or add a UI command which would be able to autocomplete 553 # "cd" command based on objects alias and match is to the 554 # "main" bdev name. 555 UINode.__init__(self, self.bdev.name, parent) 556 557 def ui_command_show_details(self): 558 self.shell.log.info(json.dumps(vars(self.bdev), indent=2)) 559 560 def summary(self): 561 size = convert_bytes_to_human(self.bdev.block_size * self.bdev.num_blocks) 562 size = "=".join(["Size", size]) 563 564 in_use = "Not claimed" 565 if bool(self.bdev.claimed): 566 in_use = "Claimed" 567 568 alias = None 569 if self.bdev.aliases: 570 alias = self.bdev.aliases[0] 571 572 info = ", ".join([_f for _f in [alias, size, in_use] if _f]) 573 return info, True 574 575 576class UIVirtioScsiBdevObj(UIBdevObj): 577 def __init__(self, bdev, parent): 578 UIBdevObj.__init__(self, bdev, parent) 579 self.refresh() 580 581 def refresh(self): 582 self._children = set([]) 583 for bdev in self.get_root().bdev_get_bdevs("virtio_scsi_disk"): 584 if self.bdev.name in bdev.name: 585 UIBdevObj(bdev, self) 586 587 def summary(self): 588 if "socket" in list(self.bdev.virtio.keys()): 589 info = self.bdev.virtio["socket"] 590 if "pci_address" in list(self.bdev.virtio.keys()): 591 info = self.bdev.virtio["pci_address"] 592 return info, True 593 594 595class UILvsObj(UINode): 596 def __init__(self, lvs, parent): 597 UINode.__init__(self, lvs.name, parent) 598 self.lvs = lvs 599 600 def ui_command_show_details(self): 601 self.shell.log.info(json.dumps(vars(self.lvs), indent=2)) 602 603 def summary(self): 604 size = convert_bytes_to_human(self.lvs.total_data_clusters * self.lvs.cluster_size) 605 free = convert_bytes_to_human(self.lvs.free_clusters * self.lvs.cluster_size) 606 if not free: 607 free = "0" 608 size = "=".join(["Size", size]) 609 free = "=".join(["Free", free]) 610 info = ", ".join([str(size), str(free)]) 611 return info, True 612 613 614class UIVhosts(UINode): 615 def __init__(self, parent): 616 UINode.__init__(self, "vhost", parent) 617 self.refresh() 618 619 def refresh(self): 620 self._children = set([]) 621 self.get_root().list_vhost_ctrls() 622 UIVhostBlk(self) 623 UIVhostScsi(self) 624 625 626class UIVhost(UINode): 627 def __init__(self, name, parent): 628 UINode.__init__(self, name, parent) 629 self.refresh() 630 631 def ui_command_delete(self, name): 632 """ 633 Delete a Vhost controller from configuration. 634 635 Arguments: 636 name - Controller name. 637 """ 638 self.get_root().vhost_delete_controller(ctrlr=name) 639 640 641class UIVhostBlk(UIVhost): 642 def __init__(self, parent): 643 UIVhost.__init__(self, "block", parent) 644 self.refresh() 645 646 def refresh(self): 647 self._children = set([]) 648 for ctrlr in self.get_root().vhost_get_controllers(ctrlr_type=self.name): 649 UIVhostBlkCtrlObj(ctrlr, self) 650 651 def ui_command_create(self, name, bdev, cpumask=None, readonly=False): 652 """ 653 Create a Vhost BLK controller. 654 655 Arguments: 656 name - Controller name. 657 bdev - Which bdev to attach to the controller. 658 cpumask - Optional. Integer to specify mask of CPUs to use. 659 Default: 1. 660 readonly - Whether controller should be read only or not. 661 Default: False. 662 """ 663 self.get_root().vhost_create_blk_controller(ctrlr=name, 664 dev_name=bdev, 665 cpumask=cpumask, 666 readonly=bool(readonly)) 667 668 669class UIVhostScsi(UIVhost): 670 def __init__(self, parent): 671 UIVhost.__init__(self, "scsi", parent) 672 self.refresh() 673 674 def refresh(self): 675 self._children = set([]) 676 for ctrlr in self.get_root().vhost_get_controllers(ctrlr_type=self.name): 677 UIVhostScsiCtrlObj(ctrlr, self) 678 679 def ui_command_create(self, name, delay=None, cpumask=None): 680 """ 681 Create a Vhost SCSI controller. 682 683 Arguments: 684 name - Controller name. 685 delay - Optional. whether delay starting controller or not. 686 Default: False. 687 cpumask - Optional. Integer to specify mask of CPUs to use. 688 Default: 1. 689 """ 690 delay = self.ui_eval_param(delay, "bool", False) 691 self.get_root().vhost_create_scsi_controller(ctrlr=name, 692 delay=delay, 693 cpumask=cpumask) 694 695 696class UIVhostCtrl(UINode): 697 # Base class for SCSI and BLK controllers, do not instantiate 698 def __init__(self, ctrlr, parent): 699 self.ctrlr = ctrlr 700 UINode.__init__(self, self.ctrlr.ctrlr, parent) 701 self.refresh() 702 703 def ui_command_show_details(self): 704 self.shell.log.info(json.dumps(vars(self.ctrlr), indent=2)) 705 706 def ui_command_set_coalescing(self, delay_base_us, iops_threshold): 707 delay_base_us = self.ui_eval_param(delay_base_us, "number", None) 708 iops_threshold = self.ui_eval_param(iops_threshold, "number", None) 709 710 self.get_root().vhost_controller_set_coalescing(ctrlr=self.ctrlr.ctrlr, 711 delay_base_us=delay_base_us, 712 iops_threshold=iops_threshold) 713 714 715class UIVhostScsiCtrlObj(UIVhostCtrl): 716 def refresh(self): 717 self._children = set([]) 718 for lun in self.ctrlr.backend_specific["scsi"]: 719 UIVhostTargetObj(lun, self) 720 721 def ui_command_start(self, name): 722 """ 723 Start a Vhost SCSI controller. 724 725 Arguments: 726 name - Controller name. 727 """ 728 self.get_root().vhost_start_scsi_controller(ctrlr=name) 729 730 def ui_command_remove_target(self, target_num): 731 """ 732 Remove target node from SCSI controller. 733 734 Arguments: 735 target_num - Integer identifier of target node to delete. 736 """ 737 self.get_root().vhost_scsi_controller_remove_target(ctrlr=self.ctrlr.ctrlr, 738 scsi_target_num=int(target_num)) 739 for ctrlr in self.get_root().vhost_get_controllers(ctrlr_type="scsi"): 740 if ctrlr.ctrlr == self.ctrlr.ctrlr: 741 self.ctrlr = ctrlr 742 743 def ui_command_add_lun(self, target_num, bdev_name): 744 """ 745 Add LUN to SCSI target node. 746 Currently only one LUN (which is LUN ID 0) per target is supported. 747 Adding LUN to not existing target node will create that node. 748 749 Arguments: 750 target_num - Integer identifier of target node to modify. 751 bdev - Which bdev to add as LUN. 752 """ 753 self.get_root().vhost_scsi_controller_add_target(ctrlr=self.ctrlr.ctrlr, 754 scsi_target_num=int(target_num), 755 bdev_name=bdev_name) 756 for ctrlr in self.get_root().vhost_get_controllers(ctrlr_type="scsi"): 757 if ctrlr.ctrlr == self.ctrlr.ctrlr: 758 self.ctrlr = ctrlr 759 760 def summary(self): 761 info = self.ctrlr.socket 762 return info, True 763 764 765class UIVhostBlkCtrlObj(UIVhostCtrl): 766 def refresh(self): 767 self._children = set([]) 768 UIVhostLunDevObj(self.ctrlr.backend_specific["block"]["bdev"], self) 769 770 def summary(self): 771 ro = None 772 if self.ctrlr.backend_specific["block"]["readonly"]: 773 ro = "Readonly" 774 info = ", ".join([_f for _f in [self.ctrlr.socket, ro] if _f]) 775 return info, True 776 777 778class UIVhostTargetObj(UINode): 779 def __init__(self, target, parent): 780 self.target = target 781 # Next line: configshell does not allow paths with spaces. 782 UINode.__init__(self, target["target_name"].replace(" ", "_"), parent) 783 self.refresh() 784 785 def refresh(self): 786 self._children = set([]) 787 for target in self.target["luns"]: 788 UIVhostLunDevObj(target["bdev_name"], self) 789 790 def ui_command_show_details(self): 791 self.shell.log.info(json.dumps(self.target, indent=2)) 792 793 def summary(self): 794 luns = "LUNs: %s" % len(self.target["luns"]) 795 id = "TargetID: %s" % self.target["scsi_dev_num"] 796 info = ",".join([luns, id]) 797 return info, True 798 799 800class UIVhostLunDevObj(UINode): 801 def __init__(self, name, parent): 802 UINode.__init__(self, name, parent) 803 804 805class UIRaidBdev(UIBdev): 806 def __init__(self, parent): 807 UIBdev.__init__(self, "raid_volume", parent) 808 809 def delete(self, name): 810 self.get_root().bdev_raid_delete(name=name) 811 812 def ui_command_create(self, name, raid_level, base_bdevs, strip_size_kb): 813 """ 814 Creates a raid bdev of the provided base_bdevs 815 816 Arguments: 817 name - raid bdev name 818 raid_level - raid level, supported values 0 819 base_bdevs - base bdevs name, whitespace separated list in quotes 820 strip_size_kb - strip size of raid bdev in KB, supported values like 8, 16, 32, 64, 128, 256, etc 821 """ 822 base_bdevs_array = [] 823 for u in base_bdevs.strip().split(" "): 824 base_bdevs_array.append(u) 825 826 strip_size_kb = self.ui_eval_param(strip_size_kb, "number", None) 827 828 ret_name = self.get_root().bdev_raid_create(name=name, 829 raid_level=raid_level, 830 base_bdevs=base_bdevs_array, 831 strip_size_kb=strip_size_kb) 832 self.shell.log.info(ret_name) 833 834 def ui_command_delete(self, name): 835 """ 836 Deletes this raid bdev object 837 838 Arguments: 839 name - raid bdev name 840 """ 841 self.delete(name) 842 843 844class UIUringBdev(UIBdev): 845 def __init__(self, parent): 846 UIBdev.__init__(self, "uring", parent) 847 848 def delete(self, name): 849 self.get_root().bdev_uring_delete(name=name) 850 851 def ui_command_create(self, filename, name, block_size, uuid=None): 852 """ 853 Construct a uring bdev. 854 855 Arguments: 856 filename - Path to device or file. 857 name - Name to use for bdev. 858 block_size - Integer, block size to use when constructing bdev. 859 uuid: UUID of block device (optional) 860 """ 861 862 block_size = self.ui_eval_param(block_size, "number", None) 863 ret_name = self.get_root().bdev_uring_create(filename=filename, 864 name=name, 865 block_size=int(block_size), 866 uuid=uuid) 867 self.shell.log.info(ret_name) 868 869 def ui_command_delete(self, name): 870 """ 871 Deletes a uring bdev. 872 873 Arguments: 874 name - uring bdev name 875 """ 876 self.delete(name) 877 878 879class UICompressBdev(UIBdev): 880 def __init__(self, parent): 881 UIBdev.__init__(self, "compress", parent) 882 883 def delete(self, name): 884 self.get_root().bdev_compress_delete(name=name) 885 886 def ui_command_create(self, base_bdev_name, pm_path, lb_size=None, comp_algo=None, comp_level=None): 887 """ 888 Construct a compress bdev. 889 890 Arguments: 891 base_bdev_name - Name of the base bdev. 892 pm_path - Path to persistent memory. 893 lb_size - Optional argument. Integer, compressed vol logical block size (optional, if used must be 512 or 4096). 894 comp_algo - Optional argument. Compression algorithm, (deflate, lz4). Default is deflate. 895 comp_level - Optional argument. Integer, compression algorithm level. if algo == deflate, level ranges from 0 to 3. 896 if algo == lz4, level ranges from 1 to 65537 897 """ 898 899 lb_size = self.ui_eval_param(lb_size, "number", None) 900 comp_level = self.ui_eval_param(comp_level, "number", None) 901 ret_name = self.get_root().create_compress_bdev(base_bdev_name=base_bdev_name, 902 pm_path=pm_path, 903 lb_size=lb_size, 904 comp_algo=comp_algo, 905 comp_level=comp_level) 906 907 self.shell.log.info(ret_name) 908 909 def ui_command_delete(self, name): 910 """ 911 Deletes compress bdev from configuration. 912 913 Arguments: 914 name - Is a unique identifier of the compress bdev to be deleted - UUID number or name alias. 915 """ 916 self.delete(name) 917