1from configshell_fb import ExecutionError 2from ..rpc.client import JSONRPCException 3from .ui_node import UINode 4 5 6class UIISCSI(UINode): 7 def __init__(self, parent): 8 UINode.__init__(self, "iscsi", parent) 9 self.refresh() 10 11 def refresh(self): 12 self._children = set([]) 13 UIISCSIDevices(self) 14 UIPortalGroups(self) 15 UIInitiatorGroups(self) 16 UIISCSIConnections(self) 17 UIISCSIAuthGroups(self) 18 UIISCSIGlobalParams(self) 19 20 21class UIISCSIGlobalParams(UINode): 22 def __init__(self, parent): 23 UINode.__init__(self, "global_params", parent) 24 self.refresh() 25 26 def refresh(self): 27 self._children = set([]) 28 iscsi_global_params = self.get_root().iscsi_get_options() 29 if not iscsi_global_params: 30 return 31 for param, val in iscsi_global_params.items(): 32 UIISCSIGlobalParam("%s: %s" % (param, val), self) 33 34 def ui_command_set_auth(self, g=None, d=None, r=None, m=None): 35 """Set CHAP authentication for discovery service. 36 37 Optional arguments: 38 g = chap_group: Authentication group ID for discovery session 39 d = disable_chap: CHAP for discovery session should be disabled 40 r = require_chap: CHAP for discovery session should be required 41 m = mutual_chap: CHAP for discovery session should be mutual 42 """ 43 chap_group = self.ui_eval_param(g, "number", None) 44 disable_chap = self.ui_eval_param(d, "bool", None) 45 require_chap = self.ui_eval_param(r, "bool", None) 46 mutual_chap = self.ui_eval_param(m, "bool", None) 47 self.get_root().iscsi_set_discovery_auth( 48 chap_group=chap_group, disable_chap=disable_chap, 49 require_chap=require_chap, mutual_chap=mutual_chap) 50 51 52class UIISCSIGlobalParam(UINode): 53 def __init__(self, param, parent): 54 UINode.__init__(self, param, parent) 55 56 57class UIISCSIDevices(UINode): 58 def __init__(self, parent): 59 UINode.__init__(self, "target_nodes", parent) 60 self.scsi_devices = list() 61 self.refresh() 62 63 def refresh(self): 64 self._children = set([]) 65 self.target_nodes = list(self.get_root().iscsi_get_target_nodes()) 66 self.scsi_devices = list(self.get_root().scsi_get_devices()) 67 for device in self.scsi_devices: 68 for node in self.target_nodes: 69 if hasattr(device, "device_name") and node['name'] \ 70 == device.device_name: 71 UIISCSIDevice(device, node, self) 72 73 def delete(self, name): 74 self.get_root().iscsi_delete_target_node(target_node_name=name) 75 76 def ui_command_create(self, name, alias_name, bdev_name_id_pairs, 77 pg_ig_mappings, queue_depth, g=None, d=None, r=None, 78 m=None, h=None, t=None): 79 """Create target node 80 81 Positional args: 82 name: Target node name (ASCII) 83 alias_name: Target node alias name (ASCII) 84 bdev_name_id_pairs: List of bdev_name_id_pairs 85 pg_ig_mappings: List of pg_ig_mappings 86 queue_depth: Desired target queue depth 87 Optional args: 88 g = chap_group: Authentication group ID for this target node 89 d = disable_chap: CHAP authentication should be disabled for this target node 90 r = require_chap: CHAP authentication should be required for this target node 91 m = mutual_chap: CHAP authentication should be mutual/bidirectional 92 h = header_digest: Header Digest should be required for this target node 93 t = data_digest: Data Digest should be required for this target node 94 """ 95 luns = [] 96 print("bdev_name_id_pairs: %s" % bdev_name_id_pairs) 97 print("pg_ig_mappings: %s" % pg_ig_mappings) 98 for u in bdev_name_id_pairs.strip().split(" "): 99 bdev_name, lun_id = u.split(":") 100 luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)}) 101 pg_ig_maps = [] 102 for u in pg_ig_mappings.strip().split(" "): 103 pg, ig = u.split(":") 104 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 105 queue_depth = self.ui_eval_param(queue_depth, "number", None) 106 chap_group = self.ui_eval_param(g, "number", None) 107 disable_chap = self.ui_eval_param(d, "bool", None) 108 require_chap = self.ui_eval_param(r, "bool", None) 109 mutual_chap = self.ui_eval_param(m, "bool", None) 110 header_digest = self.ui_eval_param(h, "bool", None) 111 data_digest = self.ui_eval_param(t, "bool", None) 112 self.get_root().iscsi_create_target_node( 113 name=name, alias_name=alias_name, luns=luns, 114 pg_ig_maps=pg_ig_maps, queue_depth=queue_depth, 115 chap_group=chap_group, disable_chap=disable_chap, 116 require_chap=require_chap, mutual_chap=mutual_chap, 117 header_digest=header_digest, data_digest=data_digest) 118 119 def ui_command_delete(self, name=None): 120 """Delete a target node. If name is not specified delete all target nodes. 121 122 Arguments: 123 name - Target node name. 124 """ 125 self.delete(name) 126 127 def ui_command_delete_all(self): 128 """Delete all target nodes""" 129 rpc_messages = "" 130 for device in self.scsi_devices: 131 try: 132 self.delete(device.device_name) 133 except JSONRPCException as e: 134 rpc_messages += e.message 135 if rpc_messages: 136 raise JSONRPCException(rpc_messages) 137 138 def ui_command_add_lun(self, name, bdev_name, lun_id=None): 139 """Add lun to the target node. 140 141 Required args: 142 name: Target node name (ASCII) 143 bdev_name: bdev name 144 Positional args: 145 lun_id: LUN ID (integer >= 0) 146 """ 147 if lun_id: 148 lun_id = self.ui_eval_param(lun_id, "number", None) 149 self.get_root().iscsi_target_node_add_lun( 150 name=name, bdev_name=bdev_name, lun_id=lun_id) 151 152 def summary(self): 153 count = 0 154 for device in self.scsi_devices: 155 for node in self.target_nodes: 156 if hasattr(device, "device_name") and node['name'] \ 157 == device.device_name: 158 count = count + 1 159 return "Target nodes: %d" % count, None 160 161 162class UIISCSIDevice(UINode): 163 def __init__(self, device, target, parent): 164 UINode.__init__(self, device.device_name, parent) 165 self.device = device 166 self.target = target 167 self.refresh() 168 169 def ui_command_set_auth(self, g=None, d=None, r=None, m=None): 170 """Set CHAP authentication for the target node. 171 172 Optionals args: 173 g = chap_group: Authentication group ID for this target node 174 d = disable_chap: CHAP authentication should be disabled for this target node 175 r = require_chap: CHAP authentication should be required for this target node 176 m = mutual_chap: CHAP authentication should be mutual/bidirectional 177 """ 178 chap_group = self.ui_eval_param(g, "number", None) 179 disable_chap = self.ui_eval_param(d, "bool", None) 180 require_chap = self.ui_eval_param(r, "bool", None) 181 mutual_chap = self.ui_eval_param(m, "bool", None) 182 self.get_root().iscsi_target_node_set_auth( 183 name=self.device.device_name, chap_group=chap_group, 184 disable_chap=disable_chap, 185 require_chap=require_chap, mutual_chap=mutual_chap) 186 187 def ui_command_iscsi_target_node_add_pg_ig_maps(self, pg_ig_mappings): 188 """Add PG-IG maps to the target node. 189 190 Args: 191 pg_ig_maps: List of pg_ig_mappings, e.g. pg_tag:ig_tag pg_tag2:ig_tag2 192 """ 193 pg_ig_maps = [] 194 for u in pg_ig_mappings.strip().split(" "): 195 pg, ig = u.split(":") 196 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 197 self.get_root().iscsi_target_node_add_pg_ig_maps( 198 pg_ig_maps=pg_ig_maps, name=self.device.device_name) 199 200 def ui_command_iscsi_target_node_remove_pg_ig_maps(self, pg_ig_mappings): 201 """Remove PG-IG maps from the target node. 202 203 Args: 204 pg_ig_maps: List of pg_ig_mappings, e.g. pg_tag:ig_tag pg_tag2:ig_tag2 205 """ 206 pg_ig_maps = [] 207 for u in pg_ig_mappings.strip().split(" "): 208 pg, ig = u.split(":") 209 pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) 210 self.get_root().iscsi_target_node_remove_pg_ig_maps( 211 pg_ig_maps=pg_ig_maps, name=self.device.device_name) 212 213 def refresh(self): 214 self._children = set([]) 215 UIISCSILuns(self.target['luns'], self) 216 UIISCSIPgIgMaps(self.target['pg_ig_maps'], self) 217 auths = {"disable_chap": self.target["disable_chap"], 218 "require_chap": self.target["require_chap"], 219 "mutual_chap": self.target["mutual_chap"], 220 "chap_group": self.target["chap_group"], 221 "data_digest": self.target["data_digest"]} 222 UIISCSIAuth(auths, self) 223 224 def summary(self): 225 return "Id: %s, QueueDepth: %s" % (self.device.id, 226 self.target['queue_depth']), None 227 228 229class UIISCSIAuth(UINode): 230 def __init__(self, auths, parent): 231 UINode.__init__(self, "auths", parent) 232 self.auths = auths 233 self.refresh() 234 235 def summary(self): 236 return "disable_chap: %s, require_chap: %s, mutual_chap: %s, chap_group: %s" % ( 237 self.auths['disable_chap'], self.auths['require_chap'], 238 self.auths['mutual_chap'], self.auths['chap_group']), None 239 240 241class UIISCSILuns(UINode): 242 def __init__(self, luns, parent): 243 UINode.__init__(self, "luns", parent) 244 self.luns = luns 245 self.refresh() 246 247 def refresh(self): 248 self._children = set([]) 249 for lun in self.luns: 250 UIISCSILun(lun, self) 251 252 def summary(self): 253 return "Luns: %d" % len(self.luns), None 254 255 256class UIISCSILun(UINode): 257 def __init__(self, lun, parent): 258 UINode.__init__(self, "lun %s" % lun['lun_id'], parent) 259 self.lun = lun 260 self.refresh() 261 262 def summary(self): 263 return "%s" % self.lun['bdev_name'], None 264 265 266class UIISCSIPgIgMaps(UINode): 267 def __init__(self, pg_ig_maps, parent): 268 UINode.__init__(self, "pg_ig_maps", parent) 269 self.pg_ig_maps = pg_ig_maps 270 self.refresh() 271 272 def refresh(self): 273 self._children = set([]) 274 for pg_ig in self.pg_ig_maps: 275 UIISCSIPgIg(pg_ig, self) 276 277 def summary(self): 278 return "Pg_ig_maps: %d" % len(self.pg_ig_maps), None 279 280 281class UIISCSIPgIg(UINode): 282 def __init__(self, pg_ig, parent): 283 UINode.__init__(self, "portal_group%s - initiator_group%s" % 284 (pg_ig['pg_tag'], pg_ig['ig_tag']), parent) 285 self.pg_ig = pg_ig 286 self.refresh() 287 288 289class UIPortalGroups(UINode): 290 def __init__(self, parent): 291 UINode.__init__(self, "portal_groups", parent) 292 self.refresh() 293 294 def delete(self, tag): 295 self.get_root().iscsi_delete_portal_group(tag=tag) 296 297 def ui_command_create(self, tag, portal_list): 298 """Add a portal group. 299 300 Args: 301 portals: List of portals e.g. ip:port ip2:port2 302 tag: Portal group tag (unique, integer > 0) 303 """ 304 portals = [] 305 for portal in portal_list.strip().split(" "): 306 host = portal 307 cpumask = None 308 if "@" in portal: 309 host, cpumask = portal.split("@") 310 if ":" not in host: 311 raise ExecutionError("Incorrect format of portal group. Port is missing." 312 "Use 'help create' to see the command syntax.") 313 host, port = host.rsplit(":", -1) 314 portals.append({'host': host, 'port': port}) 315 if cpumask: 316 print("WARNING: Specifying a CPU mask for portal groups is no longer supported. Ignoring.") 317 tag = self.ui_eval_param(tag, "number", None) 318 self.get_root().construct_portal_group(tag=tag, portals=portals, private=None, wait=None) 319 320 def ui_command_delete(self, tag): 321 """Delete a portal group with given tag (unique, integer > 0))""" 322 tag = self.ui_eval_param(tag, "number", None) 323 self.delete(tag) 324 325 def ui_command_delete_all(self): 326 """Delete all portal groups""" 327 rpc_messages = "" 328 for pg in self.pgs: 329 try: 330 self.delete(pg.tag) 331 except JSONRPCException as e: 332 rpc_messages += e.message 333 if rpc_messages: 334 raise JSONRPCException(rpc_messages) 335 336 def refresh(self): 337 self._children = set([]) 338 self.pgs = list(self.get_root().iscsi_get_portal_groups()) 339 for pg in self.pgs: 340 try: 341 UIPortalGroup(pg, self) 342 except JSONRPCException as e: 343 self.shell.log.error(e.message) 344 345 def summary(self): 346 return "Portal groups: %d" % len(self.pgs), None 347 348 349class UIPortalGroup(UINode): 350 def __init__(self, pg, parent): 351 UINode.__init__(self, "portal_group%s" % pg.tag, parent) 352 self.pg = pg 353 self.refresh() 354 355 def refresh(self): 356 self._children = set([]) 357 for portal in self.pg.portals: 358 UIPortal(portal['host'], portal['port'], self) 359 360 def summary(self): 361 return "Portals: %d" % len(self.pg.portals), None 362 363 364class UIPortal(UINode): 365 def __init__(self, host, port, parent): 366 UINode.__init__(self, "host=%s, port=%s" % ( 367 host, port), parent) 368 self.refresh() 369 370 371class UIInitiatorGroups(UINode): 372 def __init__(self, parent): 373 UINode.__init__(self, "initiator_groups", parent) 374 self.refresh() 375 376 def delete(self, tag): 377 self.get_root().iscsi_delete_initiator_group(tag=tag) 378 379 def ui_command_create(self, tag, initiator_list, netmask_list): 380 """Add an initiator group. 381 382 Args: 383 tag: Initiator group tag (unique, integer > 0) 384 initiators: List of initiator hostnames or IP addresses 385 separated with whitespaces, e.g. 127.0.0.1 192.168.200.100 386 netmasks: List of initiator netmasks separated with whitespaces, 387 e.g. 255.255.0.0 255.248.0.0 388 """ 389 tag = self.ui_eval_param(tag, "number", None) 390 self.get_root().construct_initiator_group( 391 tag=tag, initiators=initiator_list.split(" "), 392 netmasks=netmask_list.split(" ")) 393 394 def ui_command_delete(self, tag): 395 """Delete an initiator group. 396 397 Args: 398 tag: Initiator group tag (unique, integer > 0) 399 """ 400 tag = self.ui_eval_param(tag, "number", None) 401 self.delete(tag) 402 403 def ui_command_delete_all(self): 404 """Delete all initiator groups""" 405 rpc_messages = "" 406 for ig in self.igs: 407 try: 408 self.delete(ig.tag) 409 except JSONRPCException as e: 410 rpc_messages += e.message 411 if rpc_messages: 412 raise JSONRPCException(rpc_messages) 413 414 def ui_command_add_initiator(self, tag, initiators, netmasks): 415 """Add initiators to an existing initiator group. 416 417 Args: 418 tag: Initiator group tag (unique, integer > 0) 419 initiators: List of initiator hostnames or IP addresses, 420 e.g. 127.0.0.1 192.168.200.100 421 netmasks: List of initiator netmasks, 422 e.g. 255.255.0.0 255.248.0.0 423 """ 424 tag = self.ui_eval_param(tag, "number", None) 425 self.get_root().iscsi_initiator_group_add_initiators( 426 tag=tag, initiators=initiators.split(" "), 427 netmasks=netmasks.split(" ")) 428 429 def ui_command_delete_initiator(self, tag, initiators=None, netmasks=None): 430 """Delete initiators from an existing initiator group. 431 432 Args: 433 tag: Initiator group tag (unique, integer > 0) 434 initiators: List of initiator hostnames or IP addresses, e.g. 127.0.0.1 192.168.200.100 435 netmasks: List of initiator netmasks, e.g. 255.255.0.0 255.248.0.0 436 """ 437 tag = self.ui_eval_param(tag, "number", None) 438 if initiators: 439 initiators = initiators.split(" ") 440 if netmasks: 441 netmasks = netmasks.split(" ") 442 self.get_root().iscsi_initiator_group_remove_initiators( 443 tag=tag, initiators=initiators, 444 netmasks=netmasks) 445 446 def refresh(self): 447 self._children = set([]) 448 self.igs = list(self.get_root().iscsi_get_initiator_groups()) 449 for ig in self.igs: 450 UIInitiatorGroup(ig, self) 451 452 def summary(self): 453 return "Initiator groups: %d" % len(self.igs), None 454 455 456class UIInitiatorGroup(UINode): 457 def __init__(self, ig, parent): 458 UINode.__init__(self, "initiator_group%s" % ig.tag, parent) 459 self.ig = ig 460 self.refresh() 461 462 def refresh(self): 463 self._children = set([]) 464 for initiator, netmask in zip(self.ig.initiators, self.ig.netmasks): 465 UIInitiator(initiator, netmask, self) 466 467 def summary(self): 468 return "Initiators: %d" % len(self.ig.initiators), None 469 470 471class UIInitiator(UINode): 472 def __init__(self, initiator, netmask, parent): 473 UINode.__init__(self, "hostname=%s, netmask=%s" % (initiator, netmask), parent) 474 self.refresh() 475 476 477class UIISCSIConnections(UINode): 478 def __init__(self, parent): 479 UINode.__init__(self, "iscsi_connections", parent) 480 self.refresh() 481 482 def refresh(self): 483 self._children = set([]) 484 self.iscsicons = list(self.get_root().iscsi_get_connections()) 485 for ic in self.iscsicons: 486 UIISCSIConnection(ic, self) 487 488 def summary(self): 489 return "Connections: %d" % len(self.iscsicons), None 490 491 492class UIISCSIConnection(UINode): 493 def __init__(self, ic, parent): 494 UINode.__init__(self, "%s" % ic['id'], parent) 495 self.ic = ic 496 self.refresh() 497 498 def refresh(self): 499 self._children = set([]) 500 for key, val in self.ic.items(): 501 if key == "id": 502 continue 503 UIISCSIConnectionDetails("%s: %s" % (key, val), self) 504 505 506class UIISCSIConnectionDetails(UINode): 507 def __init__(self, info, parent): 508 UINode.__init__(self, "%s" % info, parent) 509 self.refresh() 510 511 512class UIISCSIAuthGroups(UINode): 513 def __init__(self, parent): 514 UINode.__init__(self, "auth_groups", parent) 515 self.refresh() 516 517 def refresh(self): 518 self._children = set([]) 519 self.iscsi_auth_groups = list(self.get_root().iscsi_get_auth_groups()) 520 if self.iscsi_auth_groups is None: 521 self.iscsi_auth_groups = [] 522 for ag in self.iscsi_auth_groups: 523 UIISCSIAuthGroup(ag, self) 524 525 def delete(self, tag): 526 self.get_root().iscsi_delete_auth_group(tag=tag) 527 528 def delete_secret(self, tag, user): 529 self.get_root().iscsi_auth_group_remove_secret( 530 tag=tag, user=user) 531 532 def ui_command_create(self, tag, secrets=None): 533 """Add authentication group for CHAP authentication. 534 535 Args: 536 tag: Authentication group tag (unique, integer > 0). 537 Optional args: 538 secrets: Array of secrets objects separated by comma sign, 539 e.g. user:test secret:test muser:mutual_test msecret:mutual_test 540 """ 541 tag = self.ui_eval_param(tag, "number", None) 542 if secrets: 543 secrets = [dict(u.split(":") for u in a.split(" ")) 544 for a in secrets.split(",")] 545 self.get_root().iscsi_create_auth_group(tag=tag, secrets=secrets) 546 547 def ui_command_delete(self, tag): 548 """Delete an authentication group. 549 550 Args: 551 tag: Authentication group tag (unique, integer > 0) 552 """ 553 tag = self.ui_eval_param(tag, "number", None) 554 self.delete(tag) 555 556 def ui_command_delete_all(self): 557 """Delete all authentication groups.""" 558 rpc_messages = "" 559 for iscsi_auth_group in self.iscsi_auth_groups: 560 try: 561 self.delete(iscsi_auth_group['tag']) 562 except JSONRPCException as e: 563 rpc_messages += e.message 564 if rpc_messages: 565 raise JSONRPCException(rpc_messages) 566 567 def ui_command_add_secret(self, tag, user, secret, 568 muser=None, msecret=None): 569 """Add a secret to an authentication group. 570 571 Args: 572 tag: Authentication group tag (unique, integer > 0) 573 user: User name for one-way CHAP authentication 574 secret: Secret for one-way CHAP authentication 575 Optional args: 576 muser: User name for mutual CHAP authentication 577 msecret: Secret for mutual CHAP authentication 578 """ 579 tag = self.ui_eval_param(tag, "number", None) 580 self.get_root().iscsi_auth_group_add_secret( 581 tag=tag, user=user, secret=secret, 582 muser=muser, msecret=msecret) 583 584 def ui_command_delete_secret(self, tag, user): 585 """Delete a secret from an authentication group. 586 587 Args: 588 tag: Authentication group tag (unique, integer > 0) 589 user: User name for one-way CHAP authentication 590 """ 591 tag = self.ui_eval_param(tag, "number", None) 592 self.delete_secret(tag, user) 593 594 def ui_command_delete_secret_all(self, tag): 595 """Delete all secrets from an authentication group. 596 597 Args: 598 tag: Authentication group tag (unique, integer > 0) 599 """ 600 rpc_messages = "" 601 tag = self.ui_eval_param(tag, "number", None) 602 for ag in self.iscsi_auth_groups: 603 if ag['tag'] == tag: 604 for secret in ag['secrets']: 605 try: 606 self.delete_secret(tag, secret['user']) 607 except JSONRPCException as e: 608 rpc_messages += e.message 609 if rpc_messages: 610 raise JSONRPCException(rpc_messages) 611 612 def summary(self): 613 return "Groups: %s" % len(self.iscsi_auth_groups), None 614 615 616class UIISCSIAuthGroup(UINode): 617 def __init__(self, ag, parent): 618 UINode.__init__(self, "group" + str(ag['tag']), parent) 619 self.ag = ag 620 self.refresh() 621 622 def refresh(self): 623 self._children = set([]) 624 for secret in self.ag['secrets']: 625 UISCSIAuthSecret(secret, self) 626 627 def summary(self): 628 return "Secrets: %s" % len(self.ag['secrets']), None 629 630 631class UISCSIAuthSecret(UINode): 632 def __init__(self, secret, parent): 633 info_list = ["%s=%s" % (key, val) 634 for key, val in secret.items()] 635 info_list.sort(reverse=True) 636 info = ", ".join(info_list) 637 UINode.__init__(self, info, parent) 638 self.secret = secret 639 self.refresh() 640