Module OSCPlugin
[hide private]
[frames] | no frames]

Source Code for Module OSCPlugin

   1  #!/usr/bin/env python 
   2  #pylint: disable=C0302 
   3   
   4  """ 
   5  @copyright: Copyright (C) 2008, 2010 Oracle and/or its affiliates. All rights reserved. 
   6   
   7  @license:   See the file COPYING for redistribution information. 
   8   
   9  @summary:   This module contains all the Oracle Storage Connect API 
  10              interfaces. 
  11  """ 
  12   
  13  __docformat__ = 'epytext en' 
  14   
  15  import sys 
  16  import os 
  17  import time 
  18  import socket 
  19  import gettext 
  20  import subprocess 
  21   
  22  import OSCCache 
  23  import OSCPluginUtils 
  24  from os.path import exists 
  25  from PyEnum import PyEnum 
  26   
  27  __all__ = ["IPlugin", 
  28   
  29             "IStorageArrayPlugin", 
  30             "IFileSystemPlugin", 
  31   
  32             "IPluginException", 
  33   
  34             "NoSuchOperationEx", 
  35             "OperationFailedEx", 
  36             "MissingKeyEx", 
  37             "ValueFormatEx", 
  38             "StorageArrayLicenseEx", 
  39             "TargetDiscoveryEx", 
  40             "LoginFailedEx", 
  41             "LogoutFailedEx", 
  42             "RefreshFailedEx", 
  43             "ListFailedEx", 
  44             "CreateSnapFailedEx", 
  45             "ListSnapFailedEx", 
  46             "SnapRestoreNotSafeEx", 
  47             "CloneFailedEx", 
  48             "InvalidStorageArrayEx", 
  49             "InvalidValueEx", 
  50             "StorageElementBusyEx", 
  51             "PermissionDeniedEx", 
  52             "OperationPreReqNotMetEx", 
  53             "StorageNameRequiredEx", 
  54             "InvalidFSTypeEx", 
  55             "FileSystemBusyEx", 
  56             "CommandMissingEx", 
  57             "FileSystemAlreadyMountedEx", 
  58   
  59             "ABILITY_TYPES", 
  60             "SE_STATES", 
  61             "SE_STATES_TEXT", 
  62             "FS_STATES", 
  63             "FS_STATES_TEXT", 
  64             "BACKING_DEVICE_TYPES", 
  65             "BACKING_DEVICE_TYPES_TEXT", 
  66            ] 
  67   
  68  _ = gettext.gettext 
  69   
  70  default_cache = OSCCache.OSCDefaultCache() 
  71   
  72  ABILITY_TYPES = PyEnum("UNSUPPORTED             = 0x00", 
  73                         "OFFLINE                 = 0x01", 
  74                         "ONLINE                  = 0x02", 
  75                         "NO                      = 0x04", 
  76                         "YES                     = 0x08", 
  77                         "INVALID                 = 0xFF", 
  78                        ) 
  79  """ 
  80  Enum representing the possible values a plugin/storage server 
  81  capability can be set to. 
  82  """ 
  83   
  84  SE_STATES = PyEnum("UNKNOWN                     = 0x00", 
  85                     "OFFLINE                     = 0x01", 
  86                     "BUSY_CREATE                 = 0x02", 
  87                     "BUSY_CLONE                  = 0x03", 
  88                     "BUSY_COPY                   = 0x04", 
  89                     "BUSY_CHILDREN               = 0x05", 
  90                     "ERROR                       = 0x06", 
  91                     "ONLINE                      = 0x07", 
  92                    ) 
  93  """ 
  94  Enum representing all the possible Storage Element states. 
  95  """ 
  96   
  97  SE_STATES_TEXT = {SE_STATES.UNKNOWN:            "Unknown", 
  98                    SE_STATES.OFFLINE:            "Offline", 
  99                    SE_STATES.BUSY_CREATE:        "Busy (Creating)", 
 100                    SE_STATES.BUSY_CLONE:         "Busy (Cloning)", 
 101                    SE_STATES.BUSY_COPY:          "Busy (Copying)", 
 102                    SE_STATES.BUSY_CHILDREN:      "Busy (Have children)", 
 103                    SE_STATES.ERROR:              "Error", 
 104                    SE_STATES.ONLINE:             "Online", 
 105                   } 
 106  """ 
 107  Dictionary used to lookup the text description associated with the 
 108  state of a Storage Element. 
 109  """ 
 110   
 111  FS_STATES = PyEnum("UNKNOWN                     = 0x00", 
 112                     "UNMOUNTED                   = 0x01", 
 113                     "MOUNTED                     = 0x02", 
 114                     "MOUNTED_READONLY            = 0x03", 
 115                     "ERROR                       = 0x04", 
 116                    ) 
 117  """ 
 118  Enum representing all the possible File System states. 
 119  """ 
 120   
 121  FS_STATES_TEXT = {FS_STATES.UNKNOWN:            "Unknown", 
 122                    FS_STATES.UNMOUNTED:          "Not mounted", 
 123                    FS_STATES.MOUNTED:            "Mounted", 
 124                    FS_STATES.MOUNTED_READONLY:   "Mounted Read Only", 
 125                    FS_STATES.ERROR:              "Error", 
 126                   } 
 127  """ 
 128  Dictionary used to lookup the text description associated with the 
 129  state of a File System. 
 130  """ 
 131   
 132  BACKING_DEVICE_TYPES = PyEnum("UNSUPPORTED                 = 0x00", 
 133                                "DEVICE_SINGLE               = 0x01", 
 134                                "DEVICE_MULTI                = 0x02", 
 135                                "PLUGIN_SINGLE               = 0x03", 
 136                                "PLUGIN_MULTI                = 0x04", 
 137                                "INVALID                     = 0x05", 
 138                               ) 
 139  """ 
 140  Enum representing all the possible File System states. 
 141  """ 
 142   
 143  BACKING_DEVICE_TYPES_TEXT = {BACKING_DEVICE_TYPES.UNSUPPORTED:     "File system creation is not supported", 
 144                               BACKING_DEVICE_TYPES.DEVICE_SINGLE:   "Single block device", 
 145                               BACKING_DEVICE_TYPES.DEVICE_MULTI:    "Multiple block devices", 
 146                               BACKING_DEVICE_TYPES.PLUGIN_SINGLE:   "Single plugin defined value", 
 147                               BACKING_DEVICE_TYPES.PLUGIN_MULTI:    "Multiple plugin defined values", 
 148                               BACKING_DEVICE_TYPES.INVALID:         "Invalid", 
 149                              } 
 150  """ 
 151  Dictionary used to lookup the text description associated with the 
 152  state of a File System. 
 153  """ 
154 155 -class IPlugin(object):
156 """ 157 The base interface for various Storage Connect plug-in interfaces. 158 159 The class tree of the Storage Connect API is as follows: 160 G{classtree: IPlugin} 161 162 @note: All logging should be done through the L{logger <IPlugin.logger>} 163 instance set in the L{IPlugin<IPlugin>} class. 164 """ 165 166 name = "IPlugin" 167 """ 168 @cvar: Class name. 169 @type: C{str} 170 """ 171 172 plugin_api_version = ["1", "2", "7"] 173 """ 174 @cvar: The over arching API version for the plugin interface. 175 @type: C{list} of C{str} 176 """ 177 178 required_api_vers = None 179 """ 180 @cvar: The minimum API version required by the plugin. 181 @type: C{list} of C{str} 182 """ 183 184 logger = None 185 """ 186 @cvar: Logging instance to be used by the plugin. 187 @type: C{logging} object 188 """ 189 190 iscsiadm = "/sbin/iscsiadm" 191 """ 192 @cvar: Location of the iscsiadm executable. 193 @type: C{str} 194 """ 195 196 plugin_type = "inv" 197 """ 198 @cvar: Specific type of plugin. 199 @type: C{str} 200 """ 201 202 plugin_name = "" 203 """ 204 @cvar: The name of the plugin - Name used to populate the user 205 interface drop down list. 206 @type: C{str} 207 """ 208 209 vendor_name = "" 210 """ 211 @cvar: Name of the Vendor supplying the plugin. 212 @type: C{str} 213 """ 214 215 plugin_version = "" 216 """ 217 @cvar: Version of the plugin. 218 @type: C{str} 219 """ 220 221 ss_extra_info_help = "None" 222 """ 223 @cvar: The help text that will be displayed for the extra info 224 to the user when creating the Storage Server. 225 @type: C{str} 226 """ 227 228 se_extra_info_help = "None" 229 """ 230 @cvar: The help text that will be displayed for the extra info 231 to the user when creating a Storage Element. 232 @type: C{str} 233 """ 234 235 fs_extra_info_help = "None" 236 """ 237 @cvar: The help text that will be displayed for the extra info 238 to the user when creating a File System. 239 @type: C{str} 240 """ 241 242 file_extra_info_help = "None" 243 """ 244 @cvar: The help text that will be displayed for the extra info 245 to the user when creating a File. 246 @type: C{str} 247 """ 248 249 plugin_ability = {"snapshot": ABILITY_TYPES.INVALID, 250 "custom_snap_name": ABILITY_TYPES.INVALID, 251 "snap_is_sync": ABILITY_TYPES.INVALID, 252 "clone": ABILITY_TYPES.INVALID, 253 "custom_clone_name": ABILITY_TYPES.INVALID, 254 "clone_is_sync": ABILITY_TYPES.INVALID, 255 "resize": ABILITY_TYPES.INVALID, 256 "resize_is_sync": ABILITY_TYPES.INVALID, 257 "splitclone": ABILITY_TYPES.INVALID, 258 "splitclone_is_sync": ABILITY_TYPES.INVALID, 259 "splitclone_while_open": ABILITY_TYPES.INVALID, 260 "snapclone": ABILITY_TYPES.INVALID, 261 "snapclone_is_sync": ABILITY_TYPES.INVALID, 262 "require_storage_name": ABILITY_TYPES.INVALID, 263 "backing_device_type": BACKING_DEVICE_TYPES.INVALID, 264 "access_control": ABILITY_TYPES.INVALID, 265 "max_access_entries": 0, 266 } 267 """ 268 @cvar: Capabilities that this specific plugin support. 269 L{Version<plugin_api_version>} of the API have the following 270 fields:: 271 272 Name Comment 273 -------------------------------------------------------------------- 274 "snapshot": # Set to ONLINE/OFFLINE if the plugin 275 # can create snapshots, NO if not. 276 "custom_snap_name": # Set this to YES if a custom name can 277 # be given to the snapshot. 278 "snap_is_sync": # Set this to YES if creating the 279 # snapshot is synchronously. 280 "clone": # Set to ONLINE/OFFLINE if the plugin 281 # can create clones, NO if not. 282 "custom_clone_name": # Set this to YES if a custom name can 283 # be given to the new clone. 284 "clone_is_sync": # Set this to YES if creating the 285 # clone is synchronously. 286 "resize": # Set to ONLINE/OFFLINE if the plugin 287 # can resize Storage Elements, NO 288 # if not. 289 "resize_is_sync": # Set this to YES if resizing the 290 # Storage Element is synchronously. 291 "splitclone": # Set to ONLINE/OFFLINE if the plugin 292 # can split clones, NO if not. 293 "splitclone_is_sync": # Set this to YES if splitting the 294 # clones is synchronously. 295 "splitclone_while_open": # Set this to YES if the plugin allows 296 # the clones to open when splitting. 297 "snapclone": # Set to ONLINE/OFFLINE if the plugin 298 # can create a clone from a snapshot, 299 # NO if not. 300 "snapclone_is_sync": # Set this to YES if cloning from a 301 # snapshot is synchronously. 302 "require_storage_name": # Set this to YES if the plugin require 303 # the user to supply a Storage Name 304 # (normally used by storage 305 # concentrators and appliances) 306 "backing_device_type": # This is for File System plugins ONLY, 307 # it defines what type of backing device 308 # the file system use when creating a 309 # file system. 310 "access_control": # Set this to YES if the plugin support 311 # access control groups. 312 "max_access_entries": # Set this to the maximum number any one 313 # access group can contain. 314 @type: C{dict} 315 """ 316 317 dev_path_prefix = "/dev/mapper" 318 """ 319 @cvar: This is the device path prefix that plug-ins should use when filling 320 in the path in the L{SERecord<__SERecord_fields__>}. 321 @type: C{str} 322 """ 323 324 dev_name_regex = "^[0-9a-zA-Z]+" 325 """ 326 @cvar: This is the device name regex that plug-ins should use when scanning 327 through the devices to fill in the path in 328 L{SERecord<__SERecord_fields__>}. 329 @type: C{str} 330 """ 331 332 SANStorage = "SAN" 333 """ 334 @cvar: Used to designate that the plugin can handle all types of SCSI 335 storage (FC, FCoE, SAS, SATA, etc.) except iSCSI. 336 @type: C{str} 337 """ 338 339 iSCSIStorage = "iSCSI" 340 """ 341 @cvar: Used to designate that the plugin can handle iSCSI storage. 342 @type: C{str} 343 """ 344 345 FileSysStorage = "FileSys" 346 """ 347 @cvar: Used to designate that the plugin handle File System storage. 348 @type: C{str} 349 """ 350 351 NetworkFileSystem = "NetworkFS" 352 """ 353 @cvar: Used to designate that the plugin is for a network file system. 354 @type: C{str} 355 """ 356 357 LocalFileSystem = "LocalFS" 358 """ 359 @cvar: Used to designate that the plugin is for a local file system. 360 @type: C{str} 361 """ 362 363 __access_grp__ = {"grp_name": "", 364 "grp_entries": [""], 365 "grp_modes": [""], 366 } 367 """ 368 @ivar: Access group. All the known fields and if the key is mandatory 369 are listed in L{Access Group fields<__access_grp_fields__>}. 370 @type: C{dict} 371 """ 372 373 __access_grp_fields__ = {"grp_name": (str, True), 374 "grp_entries": (list, True), 375 "grp_modes": (list, False), 376 } 377 """ 378 @cvar: Field list for the access group. L{Version<plugin_api_version>} of 379 the API have the following fields:: 380 381 Name Type Comment 382 -------------------------------------------------------------------- 383 "grp_name": str # Name of the access group. 384 "grp_entries": list # This is the access control entries 385 # for the group. For example, 386 # SAN would have a list of WWNs, 387 # iSCSI, a list of initiator names 388 # and for network file systems, a 389 # list of host names. 390 "grp_modes": list # Optional list of modes associated 391 # with the access group, for 392 # example the export mode for a 393 # network file system. 394 @type: C{dict} 395 """ 396 397 __vol_group__ = {"vol_name": "", 398 "vol_total_sz": 0, 399 "vol_used_sz": 0, 400 "vol_free_sz": 0, 401 "vol_alloc_sz": 0, 402 "vol_desc": "", 403 } 404 """ 405 @ivar: Volume group. All the known fields and if the key is mandatory 406 are listed in L{Volume group fields<__vol_group_fields__>}. 407 @type: C{dict} 408 """ 409 410 __vol_group_fields__ = {"vol_name": (str, True), 411 "vol_total_sz": (int, True), 412 "vol_used_sz": (int, True), 413 "vol_free_sz": (int, True), 414 "vol_alloc_sz": (int, False), 415 "vol_desc": (str, False), 416 } 417 """ 418 @cvar: Field list for the volume group. L{Version<plugin_api_version>} of 419 the API have the following fields:: 420 421 Name Type Comment 422 -------------------------------------------------------------------- 423 "vol_name": str # Name of the volume group. 424 "vol_total_sz": int # Total size of the volume group. 425 "vol_used_sz": int # Currently used space. 426 "vol_free_sz": int # Currently available space. 427 "vol_alloc_sz": int # Currently allocated space. 428 "vol_desc": str # Volume group description. 429 @type: C{dict} 430 """ 431 432 __qos_vals__ = {"priority": 0, 433 "value": "", 434 } 435 """ 436 @ivar: Quality-of-Service. All the known fields and if the key is mandatory 437 are listed in L{QoS fields<__qos_vals_fields__>}. 438 @type: C{dict} 439 """ 440 441 __qos_vals_fields__ = {"priority": (int, True), 442 "value": (str, True), 443 } 444 """ 445 @cvar: Field list for the qos_vals. L{Version<plugin_api_version>} of the 446 API have the following fields:: 447 448 Name Type Comment 449 -------------------------------------------------------------------- 450 "priority": int # Priority of the QoS value, 451 # zero (0) being the highest 452 # priority. It is not required for 453 # the values to follow numerically 454 "value": str # Quality-of-Service name as known 455 # by the Storage Server. 456 @type: C{dict} 457 """ 458 459 __SSRecord__ = {"name": "", 460 "uuid": "", 461 "storage_server_id": "", 462 "storage_type": "", 463 "access_host": "", 464 "access_port": "", 465 "username": "", 466 "passwd": "", 467 "chap": False, 468 "admin_host": "", 469 "admin_user": "", 470 "admin_passwd": "", 471 "netdevs": [""], 472 "storage_name": "", 473 "status": "", 474 "total_sz": 0, 475 "used_sz": 0, 476 "free_sz": 0, 477 "alloc_sz": 0, 478 "access_grps": [__access_grp__], 479 "vol_groups": [__vol_group__], 480 "storage_id": [""], 481 "storage_desc": "", 482 "extra_info": "", 483 } 484 """ 485 @cvar: Storage Server record. All the known fields and if the key is 486 mandatory are listed in L{SSRecord<__SSRecord_fields__>}. 487 @type: C{dict} 488 """ 489 490 __SSRecord_fields__ = {"name": (str, True), 491 "uuid": (str, True), 492 "storage_server_id": (str, False), 493 "storage_type": (str, True), 494 "access_host": (str, False), 495 "access_port": (str, False), 496 "username": (str, False), 497 "passwd": (str, False), 498 "chap": (bool, False), 499 "admin_host": (str, True), 500 "admin_user": (str, True), 501 "admin_passwd": (str, True), 502 "netdevs": (list, False), 503 "storage_name": (str, False), 504 "status": (str, True), 505 "total_sz": (int, True), 506 "used_sz": (int, True), 507 "free_sz": (int, True), 508 "alloc_sz": (int, False), 509 "access_grps": (list, True), 510 "vol_groups": (list, False), 511 "storage_id": (list, False), 512 "storage_desc": (str, True), 513 "extra_info": (str, False), 514 } 515 """ 516 @cvar: Field list for the Storage Server record. 517 L{Version<plugin_api_version>} of the API have the following fields:: 518 519 Name Type Comment 520 -------------------------------------------------------------------- 521 "name": str # Name of the Storage Server as 522 # shown in the Oracle VM Manager. 523 "uuid": str # UUID string of the Storage Server 524 # Record. 525 "storage_server_id": str # Storage Server unique identifier. 526 # This is for use solely by the 527 # plug-in to uniquely identify 528 # the Storage Server. 529 "storage_type": str # Storage type: SAN, iSCSI or 530 # FileSys. 531 "access_host": str # Host/IP address used to access the 532 # storage. 533 "access_port": str # Port number to access the storage. 534 "username": str # Storage server username. 535 "passwd": str # Storage server password. 536 "chap": bool # Does storage server require CHAP? 537 "admin_host": str # Host/IP address to admin the 538 # storage. 539 "admin_user": str # Storage administrator user name. 540 "admin_passwd": str # Storage administrator password. 541 "netdevs": list # Network device(s) used to access 542 # the storage. 543 "storage_name": str # Actual name of the Storage Server. 544 "status": str # Status of the Storage Server. 545 "total_sz": int # Total size in bytes. 546 "used_sz": int # Actual space already used. 547 "free_sz": int # Available space in bytes. 548 "alloc_sz": int # Allocated/reserved space in bytes. 549 "access_grps": list # List of access groups. See 550 # __access_grp_fields__ 551 "vol_groups": list # List of vol_groups. See 552 # __vol_group_fields__ 553 "storage_id": str # Storage identifier (iSCSI target 554 # name). 555 "storage_desc": str # Storage description. 556 "extra_info": str # Extra info (open format). 557 558 NOTE: Depending on the storage types some fields would not be in the 559 dict for instance SAN would not have the username, passwd etc. 560 also if the start method does not return a updated record with 561 the storage_id set it would not be passed in subsequent 562 operations. 563 @type: C{dict} 564 """ 565 __SERecord__ = {"se_type": "", 566 "ss_uuid": __SSRecord__["uuid"], 567 "name": "", 568 "uuid": "", 569 "page83_id": "", 570 "id": "", 571 "vendor": "", 572 "product_id": "", 573 "path": [""], 574 "array_path": "", 575 "size": 0, 576 "status": "", 577 "vol_group_name": "", 578 "access_grp_names": [""], 579 "qos": "", 580 "state": SE_STATES.UNKNOWN, 581 "extra_info": "", 582 } 583 """ 584 @cvar: Storage Element record. All the known fields and if the key is 585 mandatory are listed in L{SERecord<__SERecord_fields__>}. 586 @type: C{dict} 587 """ 588 589 __SERecord_fields__ = {"se_type": (str, True), 590 "ss_uuid": (str, True), 591 "name": (str, True), 592 "uuid": (str, True), 593 "page83_id": (str, True), 594 "id": (str, False), 595 "vendor": (str, False), 596 "product_id": (str, False), 597 "path": (list, True), 598 "array_path": (str, False), 599 "size": (int, True), 600 "status": (str, True), 601 "vol_group_name": (str, False), 602 "access_grp_names": (list, True), 603 "qos": (str, False), 604 "state": (SE_STATES, True), 605 "extra_info": (str, False), 606 } 607 """ 608 @cvar: Field list for the Storage Element record. 609 L{Version<plugin_api_version>} of the API have the following fields:: 610 611 Name Type Comment 612 -------------------------------------------------------------------- 613 "se_type": str # See __SETypes__. 614 "ss_uuid": str # UUID for the owning SSRecord. 615 "name": str # User friendly name. 616 "uuid": str # UUID string for the device. 617 "page83_id": str # SCSI Page 83 unique LUN ID. 618 "id": str # ID for the SE (LUN/Snap ID). 619 "vendor": str # Vendor as seen by a SCSI INQ. 620 "product_id": str # Product as seen by a SCSI INQ. 621 "path": list # System path(s) to the device. 622 "array_path": str # Path on the array for the device. 623 "size": int # Size in bytes. 624 "status": str # Returned status of the SE. 625 "vol_group_name": str # Volume group this SE belongs to. 626 "access_grp_names": list # List of access group names. 627 "qos": str # Quality-of-Service for the SE. 628 "state": SE_STATES # Current state of the SE. 629 "extra_info": str # Extra info (open format). 630 631 NOTE: Depending on the storage types some fields would not be in the 632 dict for instance SAN would not have the username, passwd etc. 633 @type: C{dict} 634 """ 635 636 LUNType = "LUN" 637 """ 638 @cvar: Used to designate that the SE record represent a LUN. 639 @type: C{str} 640 """ 641 642 GhostLUNType = "GhostLUN" 643 """ 644 @cvar: Used to designate that the SE record represent a Ghost LUN. 645 @type: C{str} 646 """ 647 648 SnapType = "Snapshot" 649 """ 650 @cvar: Used to designate that the SE record represent a Snapshot. 651 @type: C{str} 652 """ 653 654 SnapCloneType = "SnapClone" 655 """ 656 @cvar: Used to designate that the SE record represent a clone from a 657 snapshot. 658 @type: C{str} 659 """ 660 661 __SETypes__ = [LUNType, 662 GhostLUNType, 663 SnapType, 664 SnapCloneType, 665 ] 666 """ 667 @cvar: Known Storage Element types. A 668 L{SERecord<__SERecord_fields__>} must be of these types. 669 L{Version <plugin_api_version>} of the API define the following 670 types:: 671 672 Type Comment 673 -------------------------------------------------------------------- 674 LUNType # Normal block device LUN. 675 GhostLUNType # Ghost LUN. 676 SnapType # Snapshot created for a LUN, File system or File. 677 SnapCloneType # Clone created from a snapshot. This is a special 678 # case since it can become a full LUN in the 679 # future. We need to keep track as on most arrays 680 # the snap is locked until the snap clone is 681 # deleted or split from the snapshot. 682 @type: C{list} 683 """ 684 685 __FSRecord__ = {"access_path": "", 686 "ss_uuid": __SSRecord__["uuid"], 687 "name": "", 688 "mount_options": [""], 689 "array_path": "", 690 "uuid": "", 691 "size": 0, 692 "status": "", 693 "state": FS_STATES.UNKNOWN, 694 "access_grp_names": [""], 695 "qos": "", 696 "backing_device": "", 697 "extra_info": "", 698 } 699 """ 700 @cvar: File System record. All the known fields and if the key is 701 mandatory are listed in L{FSRecord<__FSRecord_fields__>}. 702 @type: C{dict} 703 """ 704 705 __FSRecord_fields__ = {"access_path": (str, False), 706 "ss_uuid": (str, True), 707 "name": (str, True), 708 "mount_options": (list, False), 709 "array_path": (str, False), 710 "uuid": (str, True), 711 "size": (int, True), 712 "status": (str, True), 713 "state": (FS_STATES, True), 714 "access_grp_names": (list, True), 715 "qos": (str, False), 716 "backing_device": (str, False), 717 "extra_info": (str, False), 718 } 719 """ 720 @cvar: Field list for the File System record. L{Version<plugin_api_version>} 721 of the API have the following fields:: 722 723 Name Type Comment 724 -------------------------------------------------------------------- 725 "access_path": str # Access path for the file system, 726 # this is only used for networked 727 # file systems. 728 "ss_uuid": str # UUID of the SS Record owning this 729 # file system. 730 "name": str # User friendly name of the file 731 # system. 732 "mount_options": list # List of default mount options for 733 # the file system. 734 "array_path": str # Path on storage server for the 735 # file system. 736 "uuid": str # UUID of the the file system. 737 "size": int # Size, returned, supplied for 738 # resizing. 739 "status": str # Status of the file system for 740 # display. 741 "state": FS_STATES # State of the file system. 742 "access_grp_names": list # List of access group names the 743 # file system is (or will be) 744 # exported to. 745 "qos": str # Quality-of-Service for the FS. 746 "backing_device": str/list # This is used to specify what type 747 # of device the File System 748 # requires. 749 "extra_info": str # Extra info (open format extra 750 # info). 751 752 NOTE: Depending on the file system type some fields would not be in 753 the dict. 754 @type: C{dict} 755 """ 756 757 __BackingDeviceRecord__ = {"name": "", 758 "total_sz": 0, 759 "free_sz": 0, 760 "value": "", 761 "description": "", 762 } 763 """ 764 @cvar: Backing device record. All the known fields and if the key is 765 mandatory are listed in L{BackingDeviceRecord<__BackingDeviceRecord_fields__>}. 766 @type: C{dict} 767 """ 768 769 __BackingDeviceRecord_fields__ = {"name": (str, True), 770 "total_sz": (int, True), 771 "free_sz": (int, True), 772 "value": (list, True), 773 "description": (str, False), 774 } 775 """ 776 @cvar: Field list for the backing device records. 777 L{Version<plugin_api_version>} of the API have the following 778 fields:: 779 780 Name Type Comment 781 -------------------------------------------------------------------- 782 "name": str # Name of the backing device. 783 "total_sz": int # Total size of the backing device. 784 "free_sz": int # Available free size in the backing 785 # device. 786 "value": str # Value that need to be passed back 787 # to the plugin to use this backing 788 # device. 789 "description": str # User friendly description for the 790 # backing device that will be. 791 @type: C{dict} 792 """ 793 794 __MountRecord__ = {"uuid": "", 795 "fs_uuid": __FSRecord__["uuid"], 796 "mount_point": "", 797 "options": [""], 798 "shared_path": "", 799 "status": "", 800 "extra_info": "", 801 } 802 """ 803 @cvar: Mount point record. All the known fields and if the key is 804 mandatory are listed in L{MountRecord<__MountRecord_fields__>}. 805 @type: C{dict} 806 """ 807 808 __MountRecord_fields__ = {"uuid": (str, True), 809 "fs_uuid": (str, True), 810 "mount_point": (str, True), 811 "options": (list, False), 812 "status": (str, True), 813 "extra_info": (str, False), 814 } 815 """ 816 @cvar: Field list for the Mount point records. 817 L{Version<plugin_api_version>} of the API have the following 818 fields:: 819 820 Name Type Comment 821 -------------------------------------------------------------------- 822 "uuid": str # UUID of this mount point. 823 "fs_uuid": str # UUID of the File System owning 824 # this mount point. 825 "mount_point": str # Path file system should be or is 826 # mounted on. 827 "options": list # List of mount options for this 828 # specific mount point. 829 "status": str # Status of the mount point for 830 # display. 831 "extra_info": str # Extra info (open format extra 832 # info). 833 @type: C{dict} 834 """ 835 836 __FileRecord__ = {"fr_type": "", 837 "file_path": "", 838 "ondisk_sz": 0, 839 "file_sz": 0, 840 "fs_uuid": __FSRecord__["uuid"], 841 "name_pattern": "", 842 "snap_name": "", 843 "extra_info": "", 844 } 845 """ 846 @cvar: File record. All the known fields and if the key is 847 mandatory are listed in L{FileRecord<__FileRecord_fields__>}. 848 @type: C{dict} 849 """ 850 851 __FileRecord_fields__ = {"fr_type": (str, True), 852 "file_path": (str, True), 853 "ondisk_sz": (int, True), 854 "file_sz": (int, True), 855 "fs_uuid": (str, True), 856 "name_pattern": (str, False), 857 "snap_name": (str, False), 858 "extra_info": (str, False), 859 } 860 """ 861 @cvar: Field list for the File System record. L{Version<plugin_api_version>} 862 of the API have the following fields:: 863 864 Name Type Comment 865 -------------------------------------------------------------------- 866 "fr_type": str # See __FRTypes__. 867 "file_path": str # Absolute path to the file. 868 "fs_uuid": str # UUID of the file system containing 869 # the file. 870 "name_pattern": str # This would optionally contain the 871 # pattern the file or directory 872 # name should match when listing. 873 "snap_name": str # Name of the snap. 874 "extra_info": str # Extra info (open format). 875 876 NOTE: Depending on the file system type some fields would not be in 877 the dict. 878 @type: C{dict} 879 """ 880 881 FileType = "File" 882 """ 883 @cvar: Used to designate that the FR record represent a file. 884 @type: C{str} 885 """ 886 887 DirType = "Directory" 888 """ 889 @cvar: Used to designate that the FR record represent a directory. 890 @type: C{str} 891 """ 892 893 SymLinkType = "SymbolicLink" 894 """ 895 @cvar: Used to designate that the FR record represent a symbolic link. 896 @type: C{str} 897 """ 898 899 CharDevType = "CharDevice" 900 """ 901 @cvar: Used to designate that the FR record represent a character device. 902 @type: C{str} 903 """ 904 905 BlkDevType = "BlockDevice" 906 """ 907 @cvar: Used to designate that the FR record represent a block device. 908 @type: C{str} 909 """ 910 911 FifoType = "FIFOFile" 912 """ 913 @cvar: Used to designate that the FR record represent a FIFO file. 914 @type: C{str} 915 """ 916 917 SockFileType = "SocketFile" 918 """ 919 @cvar: Used to designate that the FR record represent a socket file. 920 @type: C{str} 921 """ 922 923 __FRTypes__ = [FileType, 924 DirType, 925 SymLinkType, 926 CharDevType, 927 BlkDevType, 928 FifoType, 929 SockFileType, 930 SnapType, 931 SnapCloneType, 932 ] 933 """ 934 @cvar: Known File record types. A 935 L{FileRecord<__FileRecord_fields__>} must be of these types. 936 L{Version<plugin_api_version>} of the API define the following 937 types:: 938 939 Type Comment 940 -------------------------------------------------------------------- 941 FileType # Normal file. 942 DirType # Directory. 943 SymLinkType # Symbolic link. 944 CharDevType # Character device file. 945 BlkDevType # Block device file. 946 FifoType # FIFO pipe file. 947 SocketType # Socket file. 948 SnapType # Snapshot / RefLink created of the file. 949 SnapCloneType # Clone created from a snapshot. This is a special 950 # case since in some file systems the Snapshot 951 # must stay around as long as there is a clone 952 # based on it. It is only used when the file 953 # system have this restriction. 954 @type: C{list} 955 """ 956 957 __osc_install_dir__ = "/opt/storage-connect" 958 """ 959 @cvar: The Oracle Storage Connect installation directory. 960 @type: C{str} 961 """ 962 963 __plugin_top_dir__ = "%s/plugins" % __osc_install_dir__ 964 """ 965 @cvar: Top directory under which all Storage Connect plugins will be 966 installed. 967 @type: C{str} 968 """ 969 970 __plugin_types__ = ["isa", "ifs"] 971 """ 972 @cvar: Known Oracle Storage Connect plugin types. 973 @type: C{list} 974 """ 975 976 __plugin_temp_dir__ = "/var/tmp/storage-connect" 977 """ 978 @cvar: Directory where temporrary files woud be created under. 979 @type: C{str} 980 """ 981 982 __generic_plugin__ = False 983 """ 984 @cvar: Flag if this is a generic Plugin - Vendor implemented plugins 985 should NOT change this! 986 @type: C{bool} 987 """ 988 989 __cluster_required__ = False 990 """ 991 @cvar: Flag if this Plugin requires the cluster to be up - Vendor 992 implemented plugins should NOT change this! 993 @type: C{bool} 994 """ 995 996 cache = default_cache 997 """ 998 @cvar: Caching that can be used by the plugin. 999 @type: C{cache} object 1000 """ 1001
1002 - def __new__(cls, *args, **kwargs):
1003 """ 1004 Override the method to enforce that no Storage Connect classes be 1005 instantiated. 1006 """ 1007 raise TypeError("Storage Connect classes cannot be instantiated")
1008 1009 @staticmethod
1010 - def __get_key_value_pairs__(key_val_s, result_dict = {}):
1011 """ 1012 Create a dict from a string in the form of attr=value[,...]. 1013 1014 @param key_val_s: String containing key value pairs in key=val[,...] form. 1015 @type key_val_s: C{str} 1016 1017 @param result_dict: Optional dictionary to update with the parsed string. 1018 @type result_dict: C{dict} 1019 1020 @return: C{dict} with all the parsed key value pairs in the string. 1021 @rtype: C{dict} 1022 """ 1023 for kv_vals in key_val_s.split(","): 1024 kv_pair = kv_vals.split("=") 1025 if len(kv_pair) == 2: 1026 result_dict[kv_pair[0]] = kv_pair[1] 1027 1028 else: 1029 # Here we have a choice, either complain about the values 1030 # or just ignore it and run... I choose to complain since 1031 # I expect the user gave the values for a reason 1032 raise ValueFormatEx("Invalid format expecting an " 1033 "attr=value[,...] string", 1034 "extra_info") 1035 1036 return result_dict
1037 1038 @staticmethod
1039 - def __set_key_value_pairs__(key_val_d):
1040 """ 1041 This method will create a string in the form of key=value[,...] from a 1042 dict. 1043 1044 @param key_val_d: C{dict} containing all the values to inserted in the 1045 string. 1046 @type key_val_d: C{dict} 1047 1048 @return: String in with all keys in the dict in the format of 1049 key=value[,...] 1050 @rtype: C{str} 1051 """ 1052 kv_str = "" 1053 for kv_key in key_val_d: 1054 kv_str = kv_str + "%s=%s," % (kv_key, key_val_d[kv_key]) 1055 1056 return kv_str[:-1]
1057 1058 @staticmethod
1059 - def copy(src, dst):
1060 """ 1061 This will do a block copy from the source to the destination 1062 1063 @param src: Source for the block copy operation. 1064 @type src: C{str} 1065 1066 @param dst: Destination for the block copy operation. 1067 @type dst: C{str} 1068 """ 1069 IPlugin.logger.debug("ENTER: copy()") 1070 p_cmd = ("/bin/dd " 1071 "if=%s " 1072 "of=%s " 1073 "bs=1M " 1074 "iflag=direct " 1075 "oflag=direct " 1076 "conv=nocreat,notrunc,sparse") % (src, dst) 1077 p_cmd = p_cmd.split(" ") 1078 dd_p = subprocess.Popen(p_cmd, 1079 stdout = subprocess.PIPE, 1080 stderr = subprocess.PIPE) 1081 (p_out, p_err) = dd_p.communicate() 1082 if dd_p.returncode != 0: 1083 raise IOError("Unable to copy %s to %s : %s" % (src, dst, p_err)) 1084 1085 IPlugin.logger.debug("EXIT : copy() - Success")
1086 1087 @classmethod
1088 - def getPluginType(klass):
1089 """ 1090 Return the plugin type. 1091 1092 @return: C{plugin_type} for this specific plugin 1093 @rtype: C{str} 1094 """ 1095 return klass.plugin_type
1096 1097 @classmethod
1098 - def getTemporaryFile(klass, 1099 mode = 'w+b', 1100 bufsize = -1, 1101 suffix = '', 1102 prefix = 'tmpfil', 1103 directory = None):
1104 """ 1105 This method is identical to the standard tempfile.TemporaryFile() 1106 method. Please see the tempfile.TemporaryFile() documentation on how to 1107 use it. 1108 """ 1109 if directory == None: 1110 directory = klass.__plugin_temp_dir__ 1111 if not os.path.exists(directory): 1112 os.makedirs(directory) 1113 1114 if "tempfile" not in sys.modules: 1115 import tempfile 1116 1117 new_tmp_file = tempfile.TemporaryFile(mode, 1118 bufsize, 1119 suffix, 1120 prefix, 1121 directory) 1122 if getattr(klass, "__temp_files__", None): 1123 klass.__temp_files__.append(new_tmp_file) 1124 1125 else: 1126 klass.__temp_files__ = [new_tmp_file] 1127 1128 return new_tmp_file
1129 1130 @classmethod
1131 - def getNamedTemporaryFile(klass, 1132 mode = 'w+b', 1133 bufsize = -1, 1134 suffix = '', 1135 prefix = 'tmpfil', 1136 directory = None, 1137 delete = True):
1138 """ 1139 This method is identical to the standard tempfile.NamedTemporaryFile() 1140 method. Please see the tempfile.NamedTemporaryFile() documentation on 1141 how to use it. 1142 """ 1143 if directory == None: 1144 directory = klass.__plugin_temp_dir__ 1145 if not os.path.exists(directory): 1146 os.makedirs(directory) 1147 if "tempfile" not in sys.modules: 1148 import tempfile 1149 new_tmp_file = tempfile.NamedTemporaryFile(mode, 1150 bufsize, 1151 suffix, 1152 prefix, 1153 directory, 1154 delete) 1155 if getattr(klass, "__temp_files__", None): 1156 klass.__temp_files__.append(new_tmp_file) 1157 else: 1158 klass.__temp_files__ = [new_tmp_file] 1159 return new_tmp_file
1160
1161 -class IStorageArrayPlugin(IPlugin):
1162 """ 1163 Plugin interface for Storage Array management. 1164 """ 1165 1166 name = "IStorageArrayPlugin" 1167 """ 1168 @cvar: Class name. 1169 @type: C{str} 1170 """ 1171 1172 sa_api_version = ["1", "2", "7"] 1173 """ 1174 @cvar: Storage Array Plugin API version. 1175 @type: C{list} of C{str} 1176 """ 1177 1178 storage_types = [] 1179 """ 1180 @ivar: Storage types this plugin can handle, see L{SANStorage} and 1181 L{iSCSIStorage} 1182 @type: C{list} 1183 """ 1184 1185 plugin_type = "isa" 1186 """ 1187 @cvar: Oracle Storage Connect plugin type. 1188 @type: C{str} 1189 """ 1190 1191 __required_methods__ = {"validate": True, 1192 "getCapabilities": True, 1193 "getStorageNames": True, 1194 "getInfo": True, 1195 "getAccessGroups": True, 1196 "createAccessGroups": True, 1197 "removeAccessGroups": True, 1198 "addToAccessGroup": True, 1199 "renameAccessGroup": True, 1200 "removeFromAccessGroup": True, 1201 "discover": False, 1202 "start": False, 1203 "stop": False, 1204 "refresh": False, 1205 "list": True, 1206 "updateSERecords": False, 1207 "getStatus": True, 1208 "online": True, 1209 "offline": True, 1210 "create": True, 1211 "startPresent": True, 1212 "stopPresent": True, 1213 "resize": True, 1214 "remove": True, 1215 "getCloneLimits": True, 1216 "isCloneable": True, 1217 "clone": True, 1218 "isSplittable": True, 1219 "splitClone": True, 1220 "cloneFromSnap": True, 1221 "getCurrentClones": True, 1222 "getSnapLimits": True, 1223 "isSnapable": True, 1224 "createSnap": True, 1225 "createMultiSnap": True, 1226 "isRestorable": True, 1227 "snapRestore": True, 1228 "snapRemove": True, 1229 "getCurrentSnaps": True, 1230 "getQoSList": True, 1231 "setQoS": True, 1232 "getAsyncProgress": False, 1233 "deviceTeardown": False, 1234 } 1235 """ 1236 @cvar: List of required methods for this L{Version<plugin_api_version>} of 1237 the API 1238 @type: C{dict} 1239 """ 1240 1241 @classmethod
1242 - def getPluginInfo(klass):
1243 """ 1244 Return all the required information to identify this plugin. 1245 1246 @return: C{{"plugin_type", 1247 "plugin_name", 1248 "vendor_name", 1249 "plugin_version", 1250 "plugin_desc", 1251 "storage_types", 1252 "ss_extra_info_help", 1253 "se_extra_info_help", 1254 "required_api_vers", 1255 "sa_api_version", 1256 "plugin_ability", 1257 "generic_plugin"}} 1258 @rtype: C{dict} 1259 """ 1260 return {"plugin_type": klass.plugin_type, 1261 "plugin_name": klass.plugin_name, 1262 "vendor_name": klass.vendor_name, 1263 "plugin_version": klass.plugin_version, 1264 "plugin_desc": klass.plugin_desc, 1265 "storage_types": klass.storage_types, 1266 "ss_extra_info_help": klass.ss_extra_info_help, 1267 "se_extra_info_help": klass.se_extra_info_help, 1268 "required_api_vers": klass.required_api_vers, 1269 "sa_api_version": klass.sa_api_version, 1270 "plugin_ability": klass.plugin_ability, 1271 "generic_plugin": klass.__generic_plugin__, 1272 }
1273 1274 @staticmethod
1275 - def validate(ss_record):
1276 """ 1277 Validate the Storage Server record. 1278 1279 @param ss_record: L{Storage Server record<__SSRecord__>}. 1280 @type ss_record: C{dict}. 1281 1282 @raise IPluginException: on failure. 1283 """ 1284 raise NotImplementedError()
1285 1286 @staticmethod
1287 - def getCapabilities(ss_record):
1288 """ 1289 Obtain the capabilities from the Storage Array. 1290 1291 @param ss_record: L{Storage Server record<__SSRecord__>} 1292 @type ss_record: C{dict} 1293 1294 @return: L{Storage Server Capabilities<plugin_ability>} 1295 @rtype: C{dict} 1296 1297 @raise IPluginException: on failure 1298 """ 1299 raise NotImplementedError()
1300 1301 1302 @staticmethod
1303 - def getStorageNames(ss_record):
1304 """ 1305 Obtain a list of available storage names from which the user would 1306 choose the specific Storage Array to associate with this specific 1307 Storage Server record. 1308 1309 @param ss_record: L{Storage Server record<__SSRecord__>} 1310 @type ss_record: C{dict} 1311 1312 @return: list of available storage names OR if not required or supported 1313 an empty list. 1314 @rtype: C{list} 1315 1316 @raise IPluginException: on failure 1317 """ 1318 raise NotImplementedError()
1319 1320 @staticmethod
1321 - def getInfo(ss_record, se_record = None):
1322 """ 1323 Obtain information on either the Storage Array or the Storage Element. 1324 1325 @param ss_record: L{Storage Server record<__SSRecord__>} 1326 @type ss_record: C{dict} 1327 1328 @param se_record: Optional L{Storage Element record<__SERecord__>} 1329 @type se_record: C{dict} 1330 1331 @return: updated L{Storage Server record<__SSRecord__>} OR 1332 updated L{Storage Element record<__SERecord__>} 1333 @rtype: C{dict} 1334 1335 @raise IPluginException: on failure 1336 """ 1337 raise NotImplementedError()
1338 1339 @staticmethod
1340 - def getAccessGroups(ss_record, se_record = None):
1341 """ 1342 Get the access groups and access group entries for either the Storage 1343 Array or if specified the Storage Element. 1344 1345 @param ss_record: L{Storage Server record<__SSRecord__>} 1346 @type ss_record: C{dict} 1347 1348 @param se_record: An existing presented L{Storage Element record<__SERecord__>} 1349 @type se_record: C{dict} 1350 1351 @return: list of L{Access groups<__access_grp__>} 1352 @rtype: C{list} 1353 1354 @raise IPluginException: on failure 1355 """ 1356 raise NotImplementedError()
1357 1358 @staticmethod
1359 - def createAccessGroups(ss_record, access_grps):
1360 """ 1361 Create the access groups on the Storage Array. 1362 1363 @param ss_record: L{Storage Server record<__SSRecord__>} 1364 @type ss_record: C{dict} 1365 1366 @param access_grps: List of L{Access Groups<__access_grp__>} to create 1367 on the Storage Array. 1368 @type access_grps: C{list} 1369 1370 @return: list of L{Access groups<__access_grp__>} 1371 @rtype: C{list} 1372 1373 @raise IPluginException: on failure 1374 """ 1375 raise NotImplementedError()
1376 1377 @staticmethod
1378 - def renameAccessGroup(ss_record, access_grp_name, new_access_grp_name):
1379 """ 1380 Rename an access group on the Storage Array. 1381 1382 @param ss_record: L{Storage Server record<__SSRecord__>} 1383 @type ss_record: C{dict} 1384 1385 @param access_grp_name: Name of the L{Access Group<__access_grp__>} to rename. 1386 @type access_grp_name: C{str} 1387 1388 @param new_access_grp_name: New name for the L{Access Group<__access_grp__>}. 1389 @type new_access_grp_name: C{str} 1390 1391 @return: list of L{Access groups<__access_grp__>} 1392 @rtype: C{list} 1393 1394 @raise IPluginException: on failure 1395 """ 1396 raise NotImplementedError()
1397 1398 @staticmethod
1399 - def removeAccessGroups(ss_record, access_grps, forced_remove = False):
1400 """ 1401 Remove the access groups from the Storage Array. 1402 1403 @param ss_record: L{Storage Server record<__SSRecord__>} 1404 @type ss_record: C{dict} 1405 1406 @param access_grps: List of L{Access Groups<__access_grp__>} to remove 1407 from the Storage Array. 1408 @type access_grps: C{list} 1409 1410 @param forced_remove: Flag if the access group should force fully be 1411 removed from the Storage Array. 1412 @type forced_remove: C{bool} 1413 1414 @return: list of L{Access groups<__access_grp__>} 1415 @rtype: C{list} 1416 1417 @raise IPluginException: on failure 1418 """ 1419 raise NotImplementedError()
1420 1421 @staticmethod
1422 - def addToAccessGroup(ss_record, access_grp_name, grp_entries):
1423 """ 1424 Get the access groups and access group entries for either the Storage 1425 Array or if specified the Storage Element. 1426 1427 @param ss_record: L{Storage Server record<__SSRecord__>} 1428 @type ss_record: C{dict} 1429 1430 @param access_grp_name: Access group that the access control entries 1431 should be added to. 1432 @type access_grp_name: C{str} 1433 1434 @param grp_entries: List of access control entries to add to the access 1435 group. 1436 @type grp_entries: C{list} 1437 1438 @return: L{Access group<__access_grp__>} 1439 @rtype: C{dict} 1440 1441 @raise IPluginException: on failure 1442 """ 1443 raise NotImplementedError()
1444 1445 @staticmethod
1446 - def removeFromAccessGroup(ss_record, access_grp_name, grp_entries):
1447 """ 1448 Get the access groups and access group entries for either the Storage 1449 Array or if specified the Storage Element. 1450 1451 @param ss_record: L{Storage Server record<__SSRecord__>} 1452 @type ss_record: C{dict} 1453 1454 @param access_grp_name: Access group that the access control entries 1455 should be removed from. 1456 @type access_grp_name: C{str} 1457 1458 @param grp_entries: List of access control entries to add to the access 1459 group. 1460 @type grp_entries: C{list} 1461 1462 @return: L{Access group<__access_grp__>} 1463 @rtype: C{dict} 1464 1465 @raise IPluginException: on failure 1466 """ 1467 raise NotImplementedError()
1468 1469 @staticmethod
1470 - def discover(ss_record):
1471 """ 1472 Discover the targets that the Storage Array makes available. 1473 1474 @note: The is is only applicable to an iSCSI Storage Array 1475 1476 @param ss_record: L{Storage Server record<__SSRecord__>} 1477 @type ss_record: C{dict} 1478 1479 @return: updated L{Storage Server record<__SSRecord__>} with the 1480 storage_id field filled in. 1481 @rtype: C{dict} 1482 1483 @raise IPluginException: on failure 1484 """ 1485 IPlugin.logger.debug("ENTER: discover()") 1486 if ss_record["storage_type"] == IStorageArrayPlugin.iSCSIStorage: 1487 if not ss_record.get("access_port", None): 1488 ss_record["access_port"] = "3260" 1489 1490 if ss_record.get("username", None) or \ 1491 ss_record.get("passwd", None) or \ 1492 ss_record.get("chap", None): 1493 OSCPluginUtils.iSCSIDiscoveryAuth(ss_record) 1494 1495 if ss_record.get("netdev", None): 1496 # TODO: 1497 # Set up the network device for the node session 1498 pass 1499 1500 if not ss_record.get("storage_id", None): 1501 ss_record["storage_id"] = [] 1502 1503 portal = "%s:%s" % (socket.gethostbyname(ss_record["access_host"]), 1504 ss_record["access_port"]) 1505 1506 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1507 "--mode", "discovery", 1508 "--type=sendtargets", 1509 "--portal=%s" % portal], 1510 stdout = subprocess.PIPE, 1511 stderr = subprocess.PIPE) 1512 (p_out, p_err) = iscsi_p.communicate() 1513 if iscsi_p.returncode != 0: 1514 IPlugin.logger.error("Failure to get the targets: %s" % p_err) 1515 raise TargetDiscoveryEx(_("Failure to get the targets: %s" % 1516 p_err)) 1517 1518 if os.path.exists("/etc/iscsi/iscsid.conf.bak"): 1519 os.remove("/etc/iscsi/iscsid.conf") 1520 os.rename("/etc/iscsi/iscsid.conf.bak", 1521 "/etc/iscsi/iscsid.conf") 1522 1523 # pylint: disable=E1103 1524 for targets in p_out.splitlines(): 1525 target = targets.split(" ") 1526 if target > 1: 1527 if target[1] in ss_record["storage_id"]: 1528 continue 1529 1530 if ss_record.get("username", None): 1531 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1532 "--mode", "node", 1533 "--targetname=%s" % target[1], 1534 "--op", "update", 1535 "--name=node.session.auth.username", 1536 "--value=%s" % ss_record["username"]], 1537 stdout = subprocess.PIPE, 1538 stderr = subprocess.PIPE) 1539 (p_out, p_err) = iscsi_p.communicate() 1540 if iscsi_p.returncode != 0: 1541 IPlugin.logger.error("Unable to update username " 1542 "for %s: %s" % (target[1], p_err)) 1543 raise LoginFailedEx(_("Unable to update username " 1544 "for %s: %s" % (target[1], p_err))) 1545 1546 if ss_record.get("passwd", None): 1547 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1548 "--mode", "node", 1549 "--targetname=%s" % target[1], 1550 "--op", "update", 1551 "--name=node.session.auth.password", 1552 "--value=%s" % ss_record["passwd"]], 1553 stdout = subprocess.PIPE, 1554 stderr = subprocess.PIPE) 1555 (p_out, p_err) = iscsi_p.communicate() 1556 if iscsi_p.returncode != 0: 1557 IPlugin.logger.error("Unable to update password " 1558 "for %s: %s" % (target[1], p_err)) 1559 raise LoginFailedEx(_("Unable to update password " 1560 "for %s: %s" % (target[1], p_err))) 1561 1562 if ss_record.get("chap", None): 1563 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1564 "--mode", "node", 1565 "--targetname=%s" % target[1], 1566 "--op", "update", 1567 "--name=node.session.auth.authmethod", 1568 "--value=CHAP"], 1569 stdout = subprocess.PIPE, 1570 stderr = subprocess.PIPE) 1571 (p_out, p_err) = iscsi_p.communicate() 1572 if iscsi_p.returncode != 0: 1573 IPlugin.logger.error("Unable to set CHAP " 1574 "authentication for " 1575 "%s: %s" % (target[1], p_err)) 1576 raise LoginFailedEx(_("Unable to set CHAP " 1577 "authentication for " 1578 "%s: %s" % (target[1], p_err))) 1579 1580 ss_record["storage_id"].append(target[1]) 1581 1582 else: 1583 IPlugin.logger.error("Unable to determine target name") 1584 raise TargetDiscoveryEx(_("Unable to determine target name")) 1585 1586 return ss_record 1587 IPlugin.logger.debug("EXIT : discover() - Success")
1588 1589 @staticmethod
1590 - def start(ss_record):
1591 """ 1592 Start access to this Storage Array. 1593 1594 @note: The is is only applicable to an iSCSI Storage Array 1595 1596 @param ss_record: L{Storage Server record<__SSRecord__>} 1597 @type ss_record: C{dict} 1598 1599 @raise IPluginException: on failure. 1600 """ 1601 IPlugin.logger.debug("ENTER: start()") 1602 if ss_record["storage_type"] == IStorageArrayPlugin.iSCSIStorage: 1603 if not ss_record.get("storage_id", None): 1604 raise TargetDiscoveryEx(_("Target discovery no done!")) 1605 1606 portal = "%s:%s" % (socket.gethostbyname(ss_record["access_host"]), 1607 ss_record["access_port"]) 1608 for target in ss_record["storage_id"]: 1609 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1610 "--mode", "node", 1611 "--targetname=%s" % target, 1612 "--portal=%s" % portal, 1613 "--login"], 1614 stdout = subprocess.PIPE, 1615 stderr = subprocess.PIPE) 1616 1617 (p_out, p_err) = iscsi_p.communicate() 1618 if iscsi_p.returncode != 0: 1619 if not "15 - already exists" in p_err: 1620 raise LoginFailedEx(_("Target login failed: %s" % 1621 p_err)) 1622 1623 IPlugin.logger.debug("EXIT : start() - Success")
1624 1625 @staticmethod
1626 - def stop(ss_record):
1627 """ 1628 Stop access to this Storage Array. 1629 1630 @note: The is is only applicable to an iSCSI Storage Array 1631 1632 @param ss_record: L{Storage Server record<__SSRecord__>} 1633 @type ss_record: C{dict} 1634 1635 @raise IPluginException: on failure. 1636 """ 1637 IPlugin.logger.debug("ENTER: stop()") 1638 if ss_record["storage_type"] == IStorageArrayPlugin.iSCSIStorage: 1639 if not ss_record.get("storage_id", None): 1640 IPlugin.logger.error("Target discovery not done!") 1641 raise TargetDiscoveryEx(_("Target discovery not done!")) 1642 1643 for target in ss_record["storage_id"]: 1644 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1645 "--mode", "node", 1646 "--targetname=%s" % target, 1647 "--logout"], 1648 stdout = subprocess.PIPE, 1649 stderr = subprocess.PIPE) 1650 (p_out, p_err) = iscsi_p.communicate() 1651 if iscsi_p.returncode != 0: 1652 IPlugin.logger.error("Target logout failed: %s" % p_err) 1653 raise LogoutFailedEx(_("Target logout failed: %s" % p_err)) 1654 1655 IPlugin.logger.debug("EXIT : stop() - Success")
1656 1657 @staticmethod
1658 - def refresh(ss_record):
1659 """ 1660 Initiate a rescan for newly added or removed LUNs. 1661 1662 @note: This does not return a list of the new or or removed LUNs, it 1663 just initiate a rescan. 1664 1665 @param ss_record: L{Storage Server record<__SSRecord__>} 1666 @type ss_record: C{dict} 1667 1668 @raise IPluginException: on failure. 1669 """ 1670 IPlugin.logger.debug("ENTER: refresh()") 1671 if ss_record["storage_type"] == IStorageArrayPlugin.iSCSIStorage: 1672 if not ss_record.get("storage_id", None): 1673 IPlugin.logger.error("Target discovery not done!") 1674 raise TargetDiscoveryEx(_("Target discovery not done!")) 1675 1676 for target in ss_record["storage_id"]: 1677 iscsi_p = subprocess.Popen([IPlugin.iscsiadm, 1678 "--mode", "node", 1679 "--targetname=%s" % target, 1680 "--rescan"], 1681 stdout = subprocess.PIPE, 1682 stderr = subprocess.PIPE) 1683 (p_out, p_err) = iscsi_p.communicate() 1684 if iscsi_p.returncode != 0: 1685 IPlugin.logger.error("Target refresh failed: %s" % p_err) 1686 raise RefreshFailedEx(_("Target refresh failed: %s" % p_err)) 1687 1688 time.sleep(1.2) 1689 1690 elif ss_record["storage_type"] == IStorageArrayPlugin.SANStorage: 1691 if os.path.exists("/sys/class/fc_host"): 1692 for fc_host in os.listdir("/sys/class/fc_host"): 1693 try: 1694 lip_f = open("/sys/class/fc_host/%s/issue_lip" % fc_host, 1695 "w", 0) 1696 lip_f.write("1") 1697 lip_f.close() 1698 1699 except IOError, ioe: 1700 IPlugin.logger.error("IO Error: %s" % ioe.strerror) 1701 raise RefreshFailedEx(_("IO Error: %s" % ioe.strerror)) 1702 1703 for fc_host in os.listdir("/sys/class/scsi_host"): 1704 try: 1705 scan_f = open("/sys/class/scsi_host/%s/scan" % fc_host, 1706 "w", 0) 1707 scan_f.write("- - -") 1708 scan_f.close() 1709 1710 except IOError, ioe: 1711 IPlugin.logger.error("IO Error: %s" % ioe.strerror) 1712 raise RefreshFailedEx(_("IO Error: %s" % ioe.strerror)) 1713 1714 mpt_p = subprocess.Popen(["multipath", "-r"], 1715 stdout = subprocess.PIPE, 1716 stderr = subprocess.PIPE) 1717 (p_out, p_err) = mpt_p.communicate() 1718 if mpt_p.returncode != 0: 1719 IPlugin.logger.error("Multipath reload failed: %s" % p_err) 1720 1721 IPlugin.logger.debug("EXIT : refresh() - Success")
1722 1723 1724 @staticmethod
1725 - def deviceTeardown(ss_record, se_record):
1726 """ 1727 Tear down multipath device and associated slaves. 1728 1729 @param ss_record: L{Storage Server record<__SSRecord__>} 1730 @type ss_record: C{dict} 1731 1732 @param se_record: Optional L{Storage Element record<__SERecord__>} 1733 @type se_record: C{dict} 1734 1735 @raise IPluginException: on failure. 1736 """ 1737 IPlugin.logger.debug("ENTER: deviceTearDown()") 1738 1739 dev_name = "%s/%s" % (IPlugin.dev_path_prefix, se_record["page83_id"]) 1740 1741 if not exists(dev_name): 1742 IPlugin.logger.error("Device %s does not exist" % dev_name) 1743 raise InvalidValueEx(_("Device %s does not exist" % dev_name)) 1744 1745 OSCPluginUtils.destroyMPDev(dev_name) 1746 1747 IPlugin.logger.debug("EXIT : deviceTearDown() - Success")
1748 1749 1750 @staticmethod
1751 - def list(ss_record, se_type = [IPlugin.LUNType, 1752 IPlugin.SnapCloneType]):
1753 """ 1754 Return the list of Storage Entities associated with the Storage 1755 Array. 1756 1757 @param ss_record: L{Storage Server record<__SSRecord__>} 1758 @type ss_record: C{dict} 1759 1760 @param se_type: List of Storage Element types to be returned. 1761 @type se_type: C{list} 1762 1763 @return: list of L{Storage Element records<__SERecord__>} 1764 @rtype: C{list} 1765 1766 @raise IPluginException: on failure 1767 """ 1768 raise NotImplementedError()
1769 1770 @staticmethod
1771 - def updateSERecords(ss_record, se_records, append_allowed = False):
1772 """ 1773 Update the list of Storage Element records. The method should 1774 complete the each of the Storage Element records, including the 1775 device path if the Storage Element is visible on the server where 1776 the method is executing. NOTE: The plug-in should use the 1777 L{dev_path_prefix} value to determine the device path (if any) for 1778 each of the Storage Elements. 1779 1780 @param ss_record: L{Storage Server record<__SSRecord__>} 1781 @type ss_record: C{dict} 1782 1783 @param se_records: List of Storage Element records to examine and 1784 update with all the required information, this 1785 includes the local device path, if it is 1786 available on the server. 1787 @type se_records: C{list} 1788 1789 @param append_allowed: By default the method is not allowed to add 1790 new Storage Element records to the list 1791 passed in, if this flag is set the method is 1792 allowed to add Storage Element records to the 1793 list for newly discovered Storage Elements. 1794 @type append_allowed: C{bool} 1795 1796 @return: list of updated L{Storage Element records<__SERecord__>} 1797 @rtype: C{list} 1798 1799 @raise IPluginException: on failure 1800 """ 1801 1802 IPlugin.logger.debug("ENTER: updateSERecord()") 1803 1804 if len(se_records) < 1 : 1805 IPlugin.logger.debug("EXIT : updateSERecord() - Nothing to do!") 1806 return se_records 1807 1808 for se_record in se_records: 1809 if not se_record.has_key('page83_id'): 1810 IPlugin.logger.error("SERecord does not contain a page83_id") 1811 continue 1812 1813 dev_name = "%s/%s" % (IPlugin.dev_path_prefix, se_record["page83_id"]) 1814 1815 if os.path.exists(dev_name): 1816 se_record["path"].append(dev_name) 1817 1818 else: 1819 IPlugin.logger.error("Device %s does not exist", dev_name) 1820 1821 IPlugin.logger.debug("EXIT : updateSERecord() - Success") 1822 return se_records
1823 1824 1825 @staticmethod
1826 - def getStatus(ss_record, se_record = None):
1827 """ 1828 Return the status of the Storage Array or the Storage Element. 1829 1830 @param ss_record: L{Storage Server record<__SSRecord__>} 1831 @type ss_record: C{dict} 1832 1833 @param se_record: Optional L{Storage Element record<__SERecord__>} 1834 @type se_record: C{dict} 1835 1836 @return: Status of the Storage Array or the Storage Element 1837 @rtype: C{str} 1838 1839 @raise IPluginException: on failure 1840 """ 1841 raise NotImplementedError()
1842 1843 @staticmethod
1844 - def online(ss_record, se_record):
1845 """ 1846 Online the Storage Element on the Storage Array (if offline). 1847 1848 @param ss_record: L{Storage Server record<__SSRecord__>} 1849 @type ss_record: C{dict} 1850 1851 @param se_record: L{Storage Element record<__SERecord__>} 1852 @type se_record: C{dict} 1853 1854 @raise IPluginException: on failure 1855 """ 1856 raise NotImplementedError()
1857 1858 @staticmethod
1859 - def offline(ss_record, se_record):
1860 """ 1861 Offline the Storage Element on the Storage Array (if offline). 1862 1863 @param ss_record: L{Storage Server record<__SSRecord__>} 1864 @type ss_record: C{dict} 1865 1866 @param se_record: L{Storage Element record<__SERecord__>} 1867 @type se_record: C{dict} 1868 1869 @raise IPluginException: on failure 1870 """ 1871 raise NotImplementedError()
1872 1873 @staticmethod
1874 - def create(ss_record, se_record, thin_provision = True, qos = None):
1875 """ 1876 Provision a new Storage Element on the Storage Array. 1877 1878 @param ss_record: L{Storage Server record<__SSRecord__>} 1879 @type ss_record: C{dict} 1880 1881 @param se_record: L{Storage Element record<__SERecord__>} 1882 @type se_record: C{dict} 1883 1884 @param thin_provision: Indicate if the Storage Element should be thin 1885 provisioned (if the Storage Array support thin 1886 provisioning) or fully provisioned. 1887 @type thin_provision: C{bool} 1888 1889 @param qos: Desired Quality-of-Service for the new Storage Element 1890 @type qos: C{str} 1891 1892 @return: updated L{Storage Element record<__SERecord__>} 1893 @rtype: C{dict} 1894 1895 @raise IPluginException: on failure 1896 """ 1897 raise NotImplementedError()
1898 1899 @staticmethod
1900 - def startPresent(ss_record, se_record, access_grp_names):
1901 """ 1902 Present a Storage Element on Storage Array to the list of ports. 1903 1904 @param ss_record: L{Storage Server record<__SSRecord__>} 1905 @type ss_record: C{dict} 1906 1907 @param se_record: L{Storage Element record<__SERecord__>} 1908 @type se_record: C{dict} 1909 1910 @param access_grp_names: Names of the access groups the Storage Element 1911 should be presented to. 1912 @type access_grp_names: C{list} 1913 1914 @return: updated L{Storage Element record<__SERecord__>} 1915 @rtype: C{dict} 1916 1917 @raise IPluginException: on failure 1918 """ 1919 raise NotImplementedError()
1920 1921 @staticmethod
1922 - def stopPresent(ss_record, se_record, access_grp_names):
1923 """ 1924 Unpresent a Storage Element on Storage Array to the list of ports. 1925 1926 @param ss_record: L{Storage Server record<__SSRecord__>} 1927 @type ss_record: C{dict} 1928 1929 @param se_record: L{Storage Element record<__SERecord__>} 1930 @type se_record: C{dict} 1931 1932 @param access_grp_names: Names of the access groups the Storage Element 1933 should stop being be presented to. 1934 @type access_grp_names: C{list} 1935 1936 @return: updated L{Storage Element record<__SERecord__>} 1937 @rtype: C{dict} 1938 1939 @raise IPluginException: on failure 1940 """ 1941 raise NotImplementedError()
1942 1943 @staticmethod
1944 - def resize(ss_record, se_record, new_size):
1945 """ 1946 Resize the Storage Element on the Storage Array. 1947 1948 @param ss_record: L{Storage Server record<__SSRecord__>} 1949 @type ss_record: C{dict} 1950 1951 @param se_record: L{Storage Element record<__SERecord__>} 1952 @type se_record: C{dict} 1953 1954 @param new_size: New desired size for the Storage Element. 1955 @type new_size: C{int} 1956 1957 @return: updated L{Storage Element record<__SERecord__>} 1958 @rtype: C{dict} 1959 1960 @raise IPluginException: on failure 1961 """ 1962 raise NotImplementedError()
1963 1964 @staticmethod
1965 - def remove(ss_record, se_record):
1966 """ 1967 Remove a Storage Element from the Storage Array. 1968 1969 @param ss_record: L{Storage Server record<__SSRecord__>} 1970 @type ss_record: C{dict} 1971 1972 @param se_record: L{Storage Element record<__SERecord__>} 1973 @type se_record: C{dict} 1974 1975 @raise IPluginException: on failure 1976 """ 1977 raise NotImplementedError()
1978 1979 @staticmethod
1980 - def getCloneLimits(ss_record, se_record = None):
1981 """ 1982 Return the maximum number of shallow (thin) clones allowed for a 1983 Storage Array or Storage Element. 1984 1985 @param ss_record: L{Storage Server record<__SSRecord__>} 1986 @type ss_record: C{dict} 1987 1988 @param se_record: Optional L{Storage Element record<__SERecord__>} 1989 @type se_record: C{dict} 1990 1991 @return: Maximum number (-1 for unlimited) of shallow clones allowed 1992 for the Storage Array or the specific type of Storage Element 1993 if supplied. 1994 @rtype: C{int} 1995 1996 @raise IPluginException: on failure 1997 """ 1998 raise NotImplementedError()
1999 2000 @staticmethod
2001 - def isCloneable(ss_record, se_record):
2002 """ 2003 Check if shallow (thin) clone creations is allowed for the Storage 2004 Element. 2005 2006 @param ss_record: L{Storage Server record<__SSRecord__>} 2007 @type ss_record: C{dict} 2008 2009 @param se_record: L{Storage Element record<__SERecord__>} 2010 @type se_record: C{dict} 2011 2012 @return: True if a shallow clone can be created for the Storage Element. 2013 @rtype: C{bool} 2014 2015 @raise IPluginException: on failure 2016 """ 2017 raise NotImplementedError()
2018 2019 @staticmethod
2020 - def clone(ss_record, se_record, dest_se_record = None, qos = None):
2021 """ 2022 Create a shallow (thin) clone of the Storage Element. 2023 2024 @param ss_record: L{Storage Server record<__SSRecord__>} 2025 @type ss_record: C{dict} 2026 2027 @param se_record: L{Storage Element record<__SERecord__>} 2028 @type se_record: C{dict} 2029 2030 @param dest_se_record: Destination L{Storage Element record<__SERecord__>} 2031 @type dest_se_record: C{dict} 2032 2033 @param qos: Desired Quality-of_service for the new clone 2034 @type qos: C{str} 2035 2036 @return: Newly created L{Storage Element record<__SERecord__>} for the 2037 cloned Storage Element. 2038 @rtype: C{dict} 2039 2040 @raise IPluginException: on failure 2041 """ 2042 raise NotImplementedError()
2043 2044 @staticmethod
2045 - def isSplittable(ss_record, se_record):
2046 """ 2047 Determine if a deep clone can be made from a shallow (thin) clone (split the clones). 2048 2049 @param ss_record: L{Storage Server record<__SSRecord__>} 2050 @type ss_record: C{dict} 2051 2052 @param se_record: L{Storage Element record<__SERecord__>} 2053 @type se_record: C{dict} 2054 2055 @return: True if the clones can be split. 2056 @rtype: C{bool} 2057 2058 @raise IPluginException: on failure 2059 """ 2060 raise NotImplementedError()
2061 2062 @staticmethod
2063 - def splitClone(ss_record, se_record):
2064 """ 2065 Create a deep clone from a shallow (thin) clone (split the clones). 2066 2067 @param ss_record: L{Storage Server record<__SSRecord__>} 2068 @type ss_record: C{dict} 2069 2070 @param se_record: L{Storage Element record<__SERecord__>} 2071 @type se_record: C{dict} 2072 2073 @raise IPluginException: on failure 2074 """ 2075 raise NotImplementedError()
2076 2077 @staticmethod
2078 - def cloneFromSnap(ss_record, se_record, snap_se_record, 2079 dest_se_record = None, qos = None):
2080 """ 2081 Create a shallow (thin) clone using a snapshot. 2082 2083 @param ss_record: L{Storage Server record<__SSRecord__>} 2084 @type ss_record: C{dict} 2085 2086 @param se_record: Original L{Storage Element record<__SERecord__>} 2087 @type se_record: C{dict} 2088 2089 @param snap_se_record: Snapshot L{Storage Element record<__SERecord__>} 2090 to be clone from 2091 @type snap_se_record: C{dict} 2092 2093 @param dest_se_record: Destination L{Storage Element record<__SERecord__>} 2094 @type dest_se_record: C{dict} 2095 2096 @param qos: Desired Quality-of_service for the new clone 2097 @type qos: C{str} 2098 2099 @return: created L{Storage Element record<__SERecord__>} 2100 @rtype: C{dict} 2101 2102 @raise IPluginException: on failure 2103 """ 2104 raise NotImplementedError()
2105 2106 @staticmethod
2107 - def getCurrentClones(ss_record, se_record = None):
2108 """ 2109 Return a list of the current clones for a Storage Array or Storage 2110 Element. 2111 2112 @param ss_record: L{Storage Server record<__SSRecord__>} 2113 @type ss_record: C{dict} 2114 2115 @param se_record: Optional L{Storage Element record<__SERecord__>} 2116 @type se_record: C{dict} 2117 2118 @return: List of current known clones on the Storage Array or Storage 2119 Element if supplied. 2120 @rtype: C{list} 2121 2122 @raise IPluginException: on failure 2123 """ 2124 raise NotImplementedError()
2125 2126 @staticmethod
2127 - def getSnapLimits(ss_record, se_record = None):
2128 """ 2129 Return the maximum number of snapshots allowed for a Storage Array or 2130 Storage Element. 2131 2132 @param ss_record: L{Storage Server record<__SSRecord__>} 2133 @type ss_record: C{dict} 2134 2135 @param se_record: Optional L{Storage Element record<__SERecord__>} 2136 @type se_record: C{dict} 2137 2138 @return: Maximum number (-1 for unlimited) of snapshots allowed for the 2139 Storage Array or the specific type of Storage Element if 2140 supplied. 2141 @rtype: C{int} 2142 2143 @raise IPluginException: on failure 2144 """ 2145 raise NotImplementedError()
2146 2147 @staticmethod
2148 - def isSnapable(ss_record, se_record = None):
2149 """ 2150 Check if a snapshots can be created on the Storage Array or if 2151 specified for the specific Storage Element. 2152 2153 @param ss_record: L{Storage Server record<__SSRecord__>} 2154 @type ss_record: C{dict} 2155 2156 @param se_record: Optional L{Storage Element record<__SERecord__>} 2157 @type se_record: C{dict} 2158 2159 @return: True if a snapshots can be created on the Storage Array or if 2160 specified for the specific Storage Element. 2161 @rtype: C{bool} 2162 2163 @raise IPluginException: on failure 2164 """ 2165 raise NotImplementedError()
2166 2167 @staticmethod
2168 - def createSnap(ss_record, se_record, snap_se_record = None):
2169 """ 2170 Create a snapshot of the Storage Element. 2171 2172 @param ss_record: L{Storage Server record<__SSRecord__>} 2173 @type ss_record: C{dict} 2174 2175 @param se_record: L{Storage Element record<__SERecord__>} 2176 @type se_record: C{dict} 2177 2178 @param snap_se_record: Optional L{Storage Element record<__SERecord__>} 2179 to specify the snapshot name and destination 2180 @type snap_se_record: C{dict} 2181 2182 @return: created L{Storage Element record<__SERecord__>} for the snapshot 2183 @rtype: C{dict} 2184 2185 @raise IPluginException: on failure 2186 """ 2187 raise NotImplementedError()
2188 2189 @staticmethod
2190 - def createMultiSnap(ss_record, se_records, snap_se_record = None):
2191 """ 2192 Create a snapshot of all the listed Storage Entities together. 2193 2194 @param ss_record: L{Storage Server record<__SSRecord__>} 2195 @type ss_record: C{dict} 2196 2197 @param se_records: L{Storage Element record<__SERecord__>} 2198 @type se_records: C{dict} 2199 2200 @param snap_se_record: Optional L{Storage Element record<__SERecord__>} 2201 to specify the snapshot name and destination 2202 @type snap_se_record: C{dict} 2203 2204 @return: Created L{Storage Element record<__SERecord__>} for the 2205 snapshot. 2206 @rtype: C{dict} 2207 2208 @raise IPluginException: on failure 2209 """ 2210 raise NotImplementedError()
2211 2212 @staticmethod
2213 - def isRestorable(ss_record, snap_se_record, se_record = None):
2214 """ 2215 Check if the Storage Array or Storage Element can be rolled back to the 2216 named snapshot. 2217 2218 @param ss_record: L{Storage Server record<__SSRecord__>} 2219 @type ss_record: C{dict} 2220 2221 @param snap_se_record: L{Storage Element record<__SERecord__>} naming 2222 the snapshot to be rolled back to. 2223 @type snap_se_record: C{dict} 2224 2225 @param se_record: L{Storage Element record<__SERecord__>} 2226 @type se_record: C{dict} 2227 2228 @return: True if a snapshot can be rolled back to the snapshot, 2229 otherwise return False. 2230 @rtype: C{bool} 2231 2232 @raise IPluginException: on failure 2233 """ 2234 raise NotImplementedError()
2235 2236 @staticmethod
2237 - def snapRestore(ss_record, snap_se_record, se_record = None):
2238 """ 2239 Roll the Storage Array or Storage Element back to the named snapshot. 2240 2241 @param ss_record: L{Storage Server record<__SSRecord__>} 2242 @type ss_record: C{dict} 2243 2244 @param snap_se_record: L{Storage Element record<__SERecord__>} naming 2245 the snapshot to be rolled back to. 2246 @type snap_se_record: C{dict} 2247 2248 @param se_record: L{Storage Element record<__SERecord__>} 2249 @type se_record: C{dict} 2250 2251 @raise IPluginException: on failure 2252 """ 2253 raise NotImplementedError()
2254 2255 @staticmethod
2256 - def snapRemove(ss_record, snap_se_record):
2257 """ 2258 Destroy the named snapshot. 2259 2260 @param ss_record: L{Storage Server record<__SSRecord__>} 2261 @type ss_record: C{dict} 2262 2263 @param snap_se_record: L{Storage Element record<__SERecord__>} 2264 @type snap_se_record: C{dict} 2265 2266 @raise IPluginException: on failure 2267 """ 2268 raise NotImplementedError()
2269 2270 @staticmethod
2271 - def getCurrentSnaps(ss_record, se_record = None):
2272 """ 2273 Return a list of the current snapshots for a Storage Array or Storage 2274 Element. 2275 2276 @param ss_record: L{Storage Server record<__SSRecord__>} 2277 @type ss_record: C{dict} 2278 2279 @param se_record: Optional L{Storage Element record<__SERecord__>} 2280 @type se_record: C{dict} 2281 2282 @return: List of L{Storage Element records<__SERecord__>} for all known 2283 snapshots on the Storage Array or Storage Element if supplied. 2284 @rtype: C{list} 2285 2286 @raise IPluginException: on failure 2287 """ 2288 raise NotImplementedError()
2289 2290 @staticmethod
2291 - def getQoSList(ss_record):
2292 """ 2293 Return a list of possible QoS values for the Storage Array. 2294 2295 @param ss_record: L{Storage Server record<__SSRecord__>} 2296 @type ss_record: C{dict} 2297 2298 @return: List of L{qos_vals<__qos_vals__>} dicts for all the possible 2299 QoS values on the Storage Array. 2300 @rtype: C{list} 2301 2302 @raise IPluginException: on failure 2303 """ 2304 raise NotImplementedError()
2305 2306 @staticmethod
2307 - def setQoS(ss_record, se_record, qos):
2308 """ 2309 Set the QoS for the Storage Element to the QoS supplied. 2310 2311 @param ss_record: L{Storage Server record<__SSRecord__>} 2312 @type ss_record: C{dict} 2313 2314 @param se_record: L{Storage Server record<__SSRecord__>} 2315 @type se_record: C{dict} 2316 2317 @param qos: Desired Quality-of-Service for the new clone. 2318 @type qos: C{str} 2319 2320 @raise IPluginException: on failure 2321 """ 2322 raise NotImplementedError()
2323 2324 @staticmethod
2325 - def getAsyncProgress(ss_record, some_record):
2326 """ 2327 Obtain Async Progress. This should never be called as 2328 the plugin should overide this method if it is in 2329 asynch mode. 2330 2331 @param ss_record: L{Storage Server record<__SSRecord__>} 2332 @type ss_record: C{dict} 2333 2334 @param some_record: Record previously returned from the 2335 call that started the asynchronous 2336 operation with the async_progress and 2337 if required the async_handle fields 2338 added (and not set to None). 2339 @type some_record: C{dict} 2340 2341 @return: Fully completed record that would have been 2342 returned if the initial call completed 2343 synchronously except it have the async_progress field. 2344 @rtype: C{dict} 2345 2346 @raise IPluginException: on failure 2347 """ 2348 2349 raise NotImplementedError()
2350
2351 -class IFileSystemPlugin(IPlugin):
2352 """ 2353 Plugin interface for file system management. 2354 """ 2355 2356 name = "IFileSystemPlugin" 2357 """ 2358 @cvar: Class name. 2359 @type: C{str} 2360 """ 2361 2362 fs_api_version = ["1", "2", "7"] 2363 """ 2364 @cvar: File system plugin API version. 2365 @type: C{list} of C{str} 2366 """ 2367 2368 filesys_type = "" 2369 """ 2370 @cvar: File system type this plugin can handle, either L{LocalFileSystem} 2371 or L{NetworkFileSystem}. 2372 @type: C{str} 2373 """ 2374 2375 filesys_name = "" 2376 """ 2377 @cvar: Name of the file system to show to the user when selecting which file 2378 system to use, for example "OCFS2" or "ZFS" etc. 2379 @type: C{str} 2380 """ 2381 2382 plugin_type = "ifs" 2383 """ 2384 @cvar: Oracle Storage Connect plugin type. 2385 @type: C{str} 2386 """ 2387 2388 __required_methods__ = {"validate": True, 2389 "getCapabilities": True, 2390 "getStorageNames": True, 2391 "getStorageServerInfo": True, 2392 "getFileSystemInfo": True, 2393 "getFileInfo": True, 2394 "getAccessGroups": True, 2395 "createAccessGroups": True, 2396 "renameAccessGroup": True, 2397 "removeAccessGroups": True, 2398 "addToAccessGroup": True, 2399 "removeFromAccessGroup": True, 2400 "listFileSystems": True, 2401 "listMountPoints": True, 2402 "list": True, 2403 "getStatus": True, 2404 "mount": True, 2405 "unmount": True, 2406 "createFileSystem": True, 2407 "create": True, 2408 "startPresent": True, 2409 "stopPresent": True, 2410 "resizeFileSystem": True, 2411 "resize": True, 2412 "destroyFileSystem": True, 2413 "destroy": True, 2414 "getFileSystemCloneLimits": True, 2415 "getCloneLimits": True, 2416 "isCloneable": True, 2417 "clone": False, 2418 "isSplittable": True, 2419 "splitClone": True, 2420 "cloneFromSnap": True, 2421 "getCurrentClones": True, 2422 "getFileSystemSnapLimits": True, 2423 "getSnapLimits": True, 2424 "isSnapable": True, 2425 "createSnap": True, 2426 "createMultiSnap": True, 2427 "isRestorable": True, 2428 "snapRestore": True, 2429 "snapRemove": True, 2430 "getCurrentSnaps": True, 2431 "getQoSList": True, 2432 "setQoS": True, 2433 "getAsyncProgress": False, 2434 } 2435 """ 2436 @cvar: List of required methods for this L{Version<plugin_api_version>} of 2437 the API 2438 @type: C{dict} 2439 """ 2440 2441 @classmethod
2442 - def getPluginInfo(klass):
2443 """ 2444 Return all the required information to identify this plugin 2445 2446 @return: C{{"plugin_type", 2447 "plugin_name", 2448 "vendor_name", 2449 "plugin_version", 2450 "plugin_desc", 2451 "filesys_type", 2452 "filesys_name", 2453 "ss_extra_info_help", 2454 "fs_extra_info_help", 2455 "file_extra_info_help", 2456 "required_api_vers", 2457 "fs_api_version", 2458 "plugin_ability", 2459 "generic_plugin"}} 2460 @rtype: C{dict} 2461 """ 2462 return {"plugin_type": klass.plugin_type, 2463 "plugin_name": klass.plugin_name, 2464 "vendor_name": klass.vendor_name, 2465 "plugin_version": klass.plugin_version, 2466 "plugin_desc": klass.plugin_desc, 2467 "filesys_type": klass.filesys_type, 2468 "filesys_name": klass.filesys_name, 2469 "ss_extra_info_help": klass.ss_extra_info_help, 2470 "fs_extra_info_help": klass.fs_extra_info_help, 2471 "file_extra_info_help": klass.file_extra_info_help, 2472 "required_api_vers": klass.required_api_vers, 2473 "fs_api_version": klass.fs_api_version, 2474 "plugin_ability": klass.plugin_ability, 2475 "generic_plugin": klass.__generic_plugin__, 2476 "cluster_required": klass.__cluster_required__, 2477 }
2478 2479 @staticmethod
2480 - def validate(ss_record):
2481 """ 2482 Validate the Storage Server record. 2483 2484 @param ss_record: L{Storage Server record<__SSRecord__>} 2485 @type ss_record: C{dict} 2486 2487 @raise IPluginException: on failure 2488 """ 2489 raise NotImplementedError()
2490 2491 @staticmethod
2492 - def getCapabilities(ss_record):
2493 """ 2494 Obtain the capabilities from the Storage Server. 2495 2496 @param ss_record: L{Storage Server record<__SSRecord__>} 2497 @type ss_record: C{dict} 2498 2499 @return: L{Storage Server Capabilities<plugin_ability>} 2500 @rtype: C{dict} 2501 2502 @raise IPluginException: on failure 2503 """ 2504 raise NotImplementedError()
2505 2506 2507 @staticmethod
2508 - def getStorageNames(ss_record):
2509 """ 2510 Obtain a list of available storage names from which the user would 2511 choose the specific Storage Server to associate with this specific 2512 Storage Server record. 2513 2514 @param ss_record: L{Storage Server record<__SSRecord__>} 2515 @type ss_record: C{dict} 2516 2517 @return: list of available storage names OR if not required or supported 2518 an empty list. 2519 @rtype: C{list} 2520 2521 @raise IPluginException: on failure 2522 """ 2523 raise NotImplementedError()
2524 2525 @staticmethod
2526 - def getStorageServerInfo(ss_record):
2527 """ 2528 Obtain information on the file File Server. 2529 2530 @param ss_record: L{Storage Server record<__SSRecord__>} 2531 @type ss_record: C{dict} 2532 2533 @return: updated L{Storage Server record<__SSRecord__>} 2534 @rtype: C{dict} 2535 2536 @raise IPluginException: on failure 2537 """ 2538 raise NotImplementedError()
2539 2540 @staticmethod
2541 - def getFileSystemInfo(ss_record, fs_record):
2542 """ 2543 Obtain information on either the File Server or the File System. 2544 2545 @param ss_record: L{Storage Server record<__SSRecord__>} 2546 @type ss_record: C{dict} 2547 2548 @param fs_record: L{File System record<__FSRecord__>} 2549 @type fs_record: C{dict} 2550 2551 @return: updated L{File System record<__FSRecord__>} 2552 @rtype: C{dict} 2553 2554 @raise IPluginException: on failure 2555 """ 2556 raise NotImplementedError()
2557 2558 @staticmethod
2559 - def getFileInfo(ss_record, fs_record, file_record, file_comp_record = None):
2560 """ 2561 Obtain information on the file or if two file records are given, info 2562 on both files including how much (if any) data blocks are shared 2563 by the files. 2564 2565 @param ss_record: L{Storage Server record<__SSRecord__>} 2566 @type ss_record: C{dict} 2567 2568 @param fs_record: L{File System record<__FSRecord__>} 2569 @type fs_record: C{dict} 2570 2571 @param file_record: L{File record<__FileRecord__>} 2572 @type file_record: C{dict} 2573 2574 @param file_comp_record: Optional L{File record<__FileRecord__>} 2575 @type file_comp_record: C{dict} 2576 2577 @return: updated L{File record<__FileRecord__>} 2578 @rtype: C{dict} 2579 2580 @raise IPluginException: on failure 2581 """ 2582 raise NotImplementedError()
2583 2584 @staticmethod
2585 - def getAccessGroups(ss_record, fs_record = None):
2586 """ 2587 Get the access groups and access group entries for either the Storage 2588 Server or if specified the File System. 2589 2590 @param ss_record: L{Storage Server record<__SSRecord__>} 2591 @type ss_record: C{dict} 2592 2593 @param fs_record: Optional L{File System record<__FSRecord__>} 2594 @type fs_record: C{dict} 2595 2596 @return: list of L{Access groups<__access_grp__>} 2597 @rtype: C{list} 2598 2599 @raise IPluginException: on failure 2600 """ 2601 raise NotImplementedError()
2602 2603 @staticmethod
2604 - def createAccessGroups(ss_record, access_grps):
2605 """ 2606 Create the access groups on the Storage Server. 2607 2608 @param ss_record: L{Storage Server record<__SSRecord__>} 2609 @type ss_record: C{dict} 2610 2611 @param access_grps: List of L{Access Groups<__access_grp__>} to create 2612 on the Storage Server. 2613 @type access_grps: C{list} 2614 2615 @return: list of L{Access groups<__access_grp__>} 2616 @rtype: C{list} 2617 2618 @raise IPluginException: on failure 2619 """ 2620 raise NotImplementedError()
2621 2622 @staticmethod
2623 - def renameAccessGroup(ss_record, access_grp_name, new_access_grp_name):
2624 """ 2625 Rename an access group on the Storage Server. 2626 2627 @param ss_record: L{Storage Server record<__SSRecord__>} 2628 @type ss_record: C{dict} 2629 2630 @param access_grp_name: Name of the L{Access Group<__access_grp__>} to rename. 2631 @type access_grp_name: C{str} 2632 2633 @param new_access_grp_name: New name for the L{Access Group<__access_grp__>}. 2634 @type new_access_grp_name: C{str} 2635 2636 @return: list of L{Access groups<__access_grp__>} 2637 @rtype: C{list} 2638 2639 @raise IPluginException: on failure 2640 """ 2641 raise NotImplementedError()
2642 2643 @staticmethod
2644 - def removeAccessGroups(ss_record, access_grps):
2645 """ 2646 Remove the access groups from the Storage Server. 2647 2648 @param ss_record: L{Storage Server record<__SSRecord__>} 2649 @type ss_record: C{dict} 2650 2651 @param access_grps: List of L{Access Groups<__access_grp__>} to remove 2652 from the Storage Server. 2653 @type access_grps: C{list} 2654 2655 @return: list of L{Access groups<__access_grp__>} 2656 @rtype: C{list} 2657 2658 @raise IPluginException: on failure 2659 """ 2660 raise NotImplementedError()
2661 2662 @staticmethod
2663 - def addToAccessGroup(ss_record, access_grp_name, grp_entries):
2664 """ 2665 Get the access groups and access group entries for either the Storage 2666 Server or if specified the File System. 2667 2668 @param ss_record: L{Storage Server record<__SSRecord__>} 2669 @type ss_record: C{dict} 2670 2671 @param access_grp_name: Access group that the access control entries 2672 should be added to. 2673 @type access_grp_name: C{str} 2674 2675 @param grp_entries: List of access control entries to add to the access 2676 group. 2677 @type grp_entries: C{list} 2678 2679 @return: L{Access group<__access_grp__>} 2680 @rtype: C{dict} 2681 2682 @raise IPluginException: on failure 2683 """ 2684 raise NotImplementedError()
2685 2686 @staticmethod
2687 - def removeFromAccessGroup(ss_record, access_grp_name, grp_entries):
2688 """ 2689 Get the access groups and access group entries for either the Storage 2690 Server or if specified the File System. 2691 2692 @param ss_record: L{Storage Server record<__SSRecord__>} 2693 @type ss_record: C{dict} 2694 2695 @param access_grp_name: Access group that the access control entries 2696 should be removed from. 2697 @type access_grp_name: C{str} 2698 2699 @param grp_entries: List of access control entries to add to the access 2700 group. 2701 @type grp_entries: C{list} 2702 2703 @return: L{Access group<__access_grp__>} 2704 @rtype: C{dict} 2705 2706 @raise IPluginException: on failure 2707 """ 2708 raise NotImplementedError()
2709 2710 @staticmethod
2711 - def listFileSystems(ss_record, include_unpresented = False):
2712 """ 2713 Return the list of available (or known) File Systems. 2714 2715 @param ss_record: L{Storage Server record<__SSRecord__>} 2716 @type ss_record: C{dict} 2717 2718 @param include_unpresented: True if ALL File Systems on the File Server 2719 should be returned not just the available ones. 2720 @type include_unpresented: C{bool} 2721 2722 @return: list of L{File System records<__FSRecord__>} 2723 @rtype: C{list} 2724 2725 @raise IPluginException: on failure 2726 """ 2727 raise NotImplementedError()
2728 2729 @staticmethod
2730 - def listMountPoints(ss_record, fs_record = None):
2731 """ 2732 Return the list of mount points the plugin can manage or if the FS Record 2733 is supplied, all the mount points for the specific file system. 2734 2735 @param ss_record: L{Storage Server record<__SSRecord__>} 2736 @type ss_record: C{dict} 2737 2738 @param fs_record: Optional L{File System record<__FSRecord__>} 2739 @type fs_record: C{dict} 2740 2741 @return: list of L{Moint point records<__MountRecord__>} 2742 @rtype: C{list} 2743 2744 @raise IPluginException: on failure 2745 """ 2746 raise NotImplementedError()
2747 2748 @staticmethod
2749 - def list(ss_record, fs_record, file_record, recursive = False):
2750 """ 2751 Return the list of files. 2752 2753 @param ss_record: L{Storage Server record<__SSRecord__>} 2754 @type ss_record: C{dict} 2755 2756 @param fs_record: L{File System record<__FSRecord__>} 2757 @type fs_record: C{dict} 2758 2759 @param file_record: L{File record<__FileRecord__>} 2760 @type file_record: C{dict} 2761 2762 @param recursive: True if the list should traverse all directories 2763 below the directory specified in the 2764 L{file_record<__FileRecord__>}. 2765 @type recursive: C{bool} 2766 2767 @return: list of L{File records<__FileRecord__>} 2768 @rtype: C{list} 2769 2770 @raise IPluginException: on failure 2771 """ 2772 raise NotImplementedError()
2773 2774 @staticmethod
2775 - def getStatus(ss_record, fs_record = None):
2776 """ 2777 Return the status of the File System. 2778 2779 @param ss_record: L{Storage Server record<__SSRecord__>} 2780 @type ss_record: C{dict} 2781 2782 @param fs_record: Optional L{File System record<__FSRecord__>} 2783 @type fs_record: C{dict} 2784 2785 @return: Status of the File System or File Server 2786 @rtype: C{str} 2787 2788 @raise IPluginException: on failure 2789 """ 2790 raise NotImplementedError()
2791 2792 @staticmethod
2793 - def mount(ss_record, fs_record, mount_point, share_path = None, create_mount_point = False, mount_options = None):
2794 """ 2795 Mount the File System if not already mounted. 2796 2797 @param ss_record: L{Storage Server record<__SSRecord__>} 2798 @type ss_record: C{dict} 2799 2800 @param fs_record: L{File System record<__FSRecord__>} 2801 @type fs_record: C{dict} 2802 2803 @param mount_point: Directory where File System should be mounted. 2804 @type mount_point: C{str} 2805 2806 @param share_path: Subdirectory of File System could be mounted. 2807 @type share_path: C{str} 2808 2809 @param create_mount_point: Optional flag to indicate that the mount point should be created. 2810 @type create_mount_point: C{bool} 2811 2812 @param mount_options: Optional list of mount options 2813 @type mount_options: C{list} 2814 2815 @return: L{File System record<__FSRecord__>} 2816 @rtype: C{dict} 2817 2818 @raise IPluginException: on failure 2819 """ 2820 raise NotImplementedError()
2821 2822 @staticmethod
2823 - def unmount(ss_record, fs_record, mount_point, destroy_mount_point = False):
2824 """ 2825 Unmount the File System if mounted. 2826 2827 @param ss_record: L{Storage Server record<__SSRecord__>} 2828 @type ss_record: C{dict} 2829 2830 @param fs_record: L{File System record<__FSRecord__>} 2831 @type fs_record: C{dict} 2832 2833 @param mount_point: Directory of the File System that should be un-mounted. 2834 @type mount_point: C{str} 2835 2836 @param destroy_mount_point: Optional flag to indicate that the mount point should be removed. 2837 @type destroy_mount_point: C{bool} 2838 2839 @raise IPluginException: on failure 2840 """ 2841 raise NotImplementedError()
2842 2843 @staticmethod
2844 - def createFileSystem(ss_record, 2845 name, 2846 backing_device, 2847 size = 0, 2848 access_grp_names = None, 2849 qos = None, 2850 force = False):
2851 """ 2852 Create a new File System. 2853 2854 @param ss_record: L{Storage Server record<__SSRecord__>} 2855 @type ss_record: C{dict} 2856 2857 @param name: User friendly name for the new File System 2858 @type name: C{str} 2859 2860 @param backing_device: File System backing device, can 2861 be either a string with the backing 2862 device if only a single device is 2863 supported (as indicated in the 2864 plugin ability dict) or a list 2865 of backing devices. 2866 @type backing_device: C{str} or C{list} 2867 2868 @param size: Desired size for the new File System (0 implies as large 2869 as possible) 2870 @type size: C{int} 2871 2872 @param access_grp_names: Desired Quality-of-Service for the new File 2873 System 2874 @type access_grp_names: C{list} 2875 2876 @param qos: Desired Quality-of-Service for the new File System 2877 @type qos: C{str} 2878 2879 @param force: Flag to indicate any existing File System should be 2880 overwritten 2881 @type force: C{bool} 2882 2883 @return: new L{File System record<__FSRecord__>} 2884 @rtype: C{dict} 2885 2886 @note: ONLY overwrite an existing File System if the force option is 2887 specified. 2888 2889 @raise IPluginException: on failure 2890 """ 2891 raise NotImplementedError()
2892 2893 @staticmethod
2894 - def create(ss_record, fs_record, file_name, file_type, size, sparse = True, force = False):
2895 """ 2896 Create a new File. 2897 2898 @param ss_record: L{Storage Server record<__SSRecord__>} 2899 @type ss_record: C{dict} 2900 2901 @param fs_record: L{File System record<__FSRecord__>} 2902 @type fs_record: C{dict} 2903 2904 @param file_name: Name of the file to create. 2905 @type file_name: C{str} 2906 2907 @param file_type: Type of file to create. will be one of 2908 L{Known File Types<__FRTypes__>} 2909 @type file_type: C{str} 2910 2911 @param size: Size of the file to create. 2912 @type size: C{int} 2913 2914 @param sparse: Flag to indicate the File should be sparsely allocated (if possible). 2915 @type sparse: C{bool} 2916 2917 @param force: Flag to indicate any existing File should be overwritten. 2918 @type force: C{bool} 2919 2920 @return: updated L{File record<__FileRecord__>} 2921 @rtype: C{dict} 2922 2923 @note: ONLY overwrite an existing File if the force option is specified. 2924 2925 @raise IPluginException: on failure 2926 """ 2927 raise NotImplementedError()
2928 2929 @staticmethod
2930 - def startPresent(ss_record, fs_record, access_grp_names):
2931 """ 2932 Present a File system on the File Server to the list of nodes. 2933 2934 @param ss_record: L{Storage Server record<__SSRecord__>} 2935 @type ss_record: C{dict} 2936 2937 @param fs_record: L{File System record<__FSRecord__>} 2938 @type fs_record: C{dict} 2939 2940 @param access_grp_names: Names of the access groups the File System 2941 should be presented to. 2942 @type access_grp_names: C{list} 2943 2944 @return: updated L{File System record<__FSRecord__>} 2945 @rtype: C{dict} 2946 2947 @raise IPluginException: on failure 2948 """ 2949 raise NotImplementedError()
2950 2951 @staticmethod
2952 - def stopPresent(ss_record, fs_record, access_grp_names):
2953 """ 2954 Unpresent a File System on the File Server to the list of nodes. 2955 2956 @param ss_record: L{Storage Server record<__SSRecord__>} 2957 @type ss_record: C{dict} 2958 2959 @param fs_record: L{File System record<__FSRecord__>} 2960 @type fs_record: C{dict} 2961 2962 @param access_grp_names: Names of the access groups the File System 2963 should stop being be presented to. 2964 @type access_grp_names: C{list} 2965 2966 @return: updated L{File System record<__FSRecord__>} 2967 @rtype: C{dict} 2968 2969 @raise IPluginException: on failure 2970 """ 2971 raise NotImplementedError()
2972 2973 @staticmethod
2974 - def resizeFileSystem(ss_record, fs_record, new_size):
2975 """ 2976 Resize the File System. 2977 2978 @param ss_record: L{Storage Server record<__SSRecord__>} 2979 @type ss_record: C{dict} 2980 2981 @param fs_record: L{File System record<__FSRecord__>} 2982 @type fs_record: C{dict} 2983 2984 @param new_size: New desired size for the File System. 2985 @type new_size: C{int} 2986 2987 @return: updated L{File System record<__FSRecord__>} 2988 @rtype: C{dict} 2989 2990 @note: It is the plugin responsibilty to verify that all conditions are 2991 met for the resize operation. For example if online resize is not 2992 supported, the plugin must make sure the file system is not 2993 mounted and raise an Exception if it is. 2994 2995 @raise IPluginException: on failure 2996 """ 2997 raise NotImplementedError()
2998 2999 @staticmethod
3000 - def resize(ss_record, fs_record, file_record, new_size, sparse = True):
3001 """ 3002 Resize the File. 3003 3004 @param ss_record: L{Storage Server record<__SSRecord__>} 3005 @type ss_record: C{dict} 3006 3007 @param fs_record: L{File System record<__FSRecord__>} 3008 @type fs_record: C{dict} 3009 3010 @param file_record: L{File record<__FileRecord__>} 3011 @type file_record: C{dict} 3012 3013 @param new_size: New desired size for the file. 3014 @type new_size: C{int} 3015 3016 @param sparse: Flag to indicate the File should be extended using sparse 3017 (if possible). 3018 @type sparse: C{bool} 3019 3020 @return: updated L{File record<__FileRecord__>} 3021 @rtype: C{dict} 3022 3023 @note: It is the plugin responsibilty to verify that all conditions are 3024 met for the resize operation. For example if online resize is not 3025 supported, the plugin must make sure the file is not currently 3026 open and/or locked and raise an Exception if it is. 3027 3028 @raise IPluginException: on failure 3029 """ 3030 raise NotImplementedError()
3031 3032 @staticmethod
3033 - def destroyFileSystem(ss_record, fs_record):
3034 """ 3035 Remove a File System from the File Server. 3036 3037 @param ss_record: L{Storage Server record<__SSRecord__>} 3038 @type ss_record: C{dict} 3039 3040 @param fs_record: L{File System record<__FSRecord__>} 3041 @type fs_record: C{dict} 3042 3043 @raise IPluginException: on failure 3044 """ 3045 raise NotImplementedError()
3046 3047 @staticmethod
3048 - def destroy(ss_record, fs_record, file_record):
3049 """ 3050 Remove a file from the File System on the File Server. 3051 3052 @param ss_record: L{Storage Server record<__SSRecord__>} 3053 @type ss_record: C{dict} 3054 3055 @param fs_record: L{File System record<__FSRecord__>} 3056 @type fs_record: C{dict} 3057 3058 @param file_record: L{File record<__FileRecord__>} 3059 @type file_record: C{dict} 3060 3061 @raise IPluginException: on failure 3062 """ 3063 raise NotImplementedError()
3064 3065 @staticmethod
3066 - def getFileSystemCloneLimits(ss_record, fs_record = None):
3067 """ 3068 Return the maximum number of clones allowed for a File Server or 3069 File System. 3070 3071 @param ss_record: L{Storage Server record<__SSRecord__>} 3072 @type ss_record: C{dict} 3073 3074 @param fs_record: Optional L{File System record<__FSRecord__>} 3075 @type fs_record: C{dict} 3076 3077 @return: Maximum number (-1 for unlimited) of clones allowed for the 3078 File Server or the specific file system if supplied. 3079 @rtype: C{int} 3080 3081 @raise IPluginException: on failure 3082 """ 3083 raise NotImplementedError()
3084 3085 @staticmethod
3086 - def getCloneLimits(ss_record, fs_record, file_record):
3087 """ 3088 Return the maximum number of snapshots allowed for a File Server or 3089 File System. 3090 3091 @param ss_record: L{Storage Server record<__SSRecord__>} 3092 @type ss_record: C{dict} 3093 3094 @param fs_record: L{File System record<__FSRecord__>} 3095 @type fs_record: C{dict} 3096 3097 @param file_record: L{File record<__FileRecord__>} 3098 @type file_record: C{dict} 3099 3100 @return: Maximum number (-1 for unlimited) of clones allowed for the 3101 File. 3102 @rtype: C{int} 3103 3104 @raise IPluginException: on failure 3105 """ 3106 raise NotImplementedError()
3107 3108 @staticmethod
3109 - def isCloneable(ss_record, fs_record, file_record):
3110 """ 3111 Check if shallow (thin) clone creations is allowed for the file on the 3112 File System. 3113 3114 @param ss_record: L{Storage Server record<__SSRecord__>} 3115 @type ss_record: C{dict} 3116 3117 @param fs_record: L{File System record<__FSRecord__>} 3118 @type fs_record: C{dict} 3119 3120 @param file_record: L{File record<__FileRecord__>} 3121 @type file_record: C{dict} 3122 3123 @return: True if a snapshot can be created for the File record. 3124 @rtype: C{bool} 3125 3126 @raise IPluginException: on failure 3127 """ 3128 raise NotImplementedError()
3129 3130 @staticmethod
3131 - def clone(ss_record, fs_record, file_record, dest_file_name = None):
3132 """ 3133 Create a shallow clone of the file on the file system. 3134 3135 @param ss_record: L{Storage Server record<__SSRecord__>} 3136 @type ss_record: C{dict} 3137 3138 @param fs_record: L{File System record<__FSRecord__>} 3139 @type fs_record: C{dict} 3140 3141 @param file_record: L{File record<__FileRecord__>} 3142 @type file_record: C{dict} 3143 3144 @param dest_file_name: Optional destination file name 3145 @type dest_file_name: C{str} 3146 3147 @return: newly created L{File record<__FileRecord__>} for the 3148 cloned storage element 3149 @rtype: C{dict} 3150 3151 @raise IPluginException: on failure 3152 """ 3153 raise NotImplementedError()
3154 3155 @staticmethod
3156 - def isSplittable(ss_record, fs_record, file_record):
3157 """ 3158 Determine if a deep clone can be made from a shallow (thin) clone (split the clones). 3159 3160 @param ss_record: L{Storage Server record<__SSRecord__>} 3161 @type ss_record: C{dict} 3162 3163 @param fs_record: L{File System record<__FSRecord__>} 3164 @type fs_record: C{dict} 3165 3166 @param file_record: L{File record<__FileRecord__>} 3167 @type file_record: C{dict} 3168 3169 @return: True if the clones can be split. 3170 @rtype: C{bool} 3171 3172 @raise IPluginException: on failure 3173 """ 3174 raise NotImplementedError()
3175 3176 @staticmethod
3177 - def splitClone(ss_record, fs_record, file_record):
3178 """ 3179 Create a deep clone from a shallow clone (Split the clones). 3180 3181 @param ss_record: L{Storage Server record<__SSRecord__>} 3182 @type ss_record: C{dict} 3183 3184 @param fs_record: L{File System record<__FSRecord__>} 3185 @type fs_record: C{dict} 3186 3187 @param file_record: L{File record<__FileRecord__>} 3188 @type file_record: C{dict} 3189 3190 @raise IPluginException: on failure 3191 """ 3192 raise NotImplementedError()
3193 3194 @staticmethod
3195 - def cloneFromSnap(ss_record, fs_record, snap_file_record, dest_file_name = None):
3196 """ 3197 Create a shallow clone from a named snapshot. 3198 3199 @param ss_record: L{Storage Server record<__SSRecord__>} 3200 @type ss_record: C{dict} 3201 3202 @param fs_record: L{File System record<__FSRecord__>} 3203 @type fs_record: C{dict} 3204 3205 @param snap_file_record: L{File record<__FileRecord__>} 3206 @type snap_file_record: C{dict} 3207 3208 @param dest_file_name: Optional destination file name 3209 @type dest_file_name: C{str} 3210 3211 @return: created L{File record<__FileRecord__>} for the new clone 3212 @rtype: C{dict} 3213 3214 @raise IPluginException: on failure 3215 """ 3216 raise NotImplementedError()
3217 3218 @staticmethod
3219 - def getCurrentClones(ss_record, fs_record, file_record = None):
3220 """ 3221 Return a list of the current clones for the File System or Storage 3222 Element. 3223 3224 @param ss_record: L{Storage Server record<__SSRecord__>} 3225 @type ss_record: C{dict} 3226 3227 @param fs_record: L{File System record<__FSRecord__>} 3228 @type fs_record: C{dict} 3229 3230 @param file_record: Optional L{File record<__FileRecord__>} 3231 @type file_record: C{dict} 3232 3233 @return: List of current known clones on the L{File record<__FileRecord__>}. 3234 @rtype: C{list} 3235 3236 @raise IPluginException: on failure 3237 """ 3238 raise NotImplementedError()
3239 3240 @staticmethod
3241 - def getFileSystemSnapLimits(ss_record, fs_record = None):
3242 """ 3243 Return the maximum number of snapshots allowed for a Storage Array or 3244 File System. 3245 3246 @param ss_record: L{Storage Server record<__SSRecord__>} 3247 @type ss_record: C{dict} 3248 3249 @param fs_record: Optional L{File System record<__FSRecord__>} 3250 @type fs_record: C{dict} 3251 3252 @return: Maximum number (-1 for unlimited) of snapshots allowed for the 3253 Storage Array or the specific file system if supplied. 3254 @rtype: C{int} 3255 3256 @raise IPluginException: on failure 3257 """ 3258 raise NotImplementedError()
3259 3260 @staticmethod
3261 - def getSnapLimits(ss_record, fs_record, file_record):
3262 """ 3263 Return the maximum number of snapshots allowed for a specific file on 3264 the file system. 3265 3266 @param ss_record: L{Storage Server record<__SSRecord__>} 3267 @type ss_record: C{dict} 3268 3269 @param fs_record: L{File System record<__FSRecord__>} 3270 @type fs_record: C{dict} 3271 3272 @param file_record: L{File record<__FileRecord__>} 3273 @type file_record: C{dict} 3274 3275 @return: Maximum number (-1 for unlimited) of snapshots allowed for the 3276 specific file. 3277 @rtype: C{int} 3278 3279 @raise IPluginException: on failure 3280 """ 3281 raise NotImplementedError()
3282 3283 @staticmethod
3284 - def isSnapable(ss_record, fs_record, file_record):
3285 """ 3286 Check if a snapshot creation is allowed for the file on the file system 3287 file. 3288 3289 @param ss_record: L{Storage Server record<__SSRecord__>} 3290 @type ss_record: C{dict} 3291 3292 @param fs_record: L{File System record<__FSRecord__>} 3293 @type fs_record: C{dict} 3294 3295 @param file_record: L{File record<__FileRecord__>} 3296 @type file_record: C{dict} 3297 3298 @return: True if a snapshot can be created for the File record. 3299 @rtype: C{bool} 3300 3301 @raise IPluginException: on failure 3302 """ 3303 raise NotImplementedError()
3304 3305 @staticmethod
3306 - def createSnap(ss_record, fs_record, file_record, snap_name = None):
3307 """ 3308 Create a snapshot of the file for the file system. 3309 3310 @param ss_record: L{Storage Server record<__SSRecord__>} 3311 @type ss_record: C{dict} 3312 3313 @param fs_record: L{File System record<__FSRecord__>} 3314 @type fs_record: C{dict} 3315 3316 @param file_record: L{File record<__FileRecord__>} 3317 @type file_record: C{dict} 3318 3319 @param snap_name: Optional snapshot name 3320 @type snap_name: C{str} 3321 3322 @return: created L{File record<__FileRecord__>} for the snapshot 3323 @rtype: C{dict} 3324 3325 @raise IPluginException: on failure 3326 """ 3327 raise NotImplementedError()
3328 3329 @staticmethod
3330 - def createMultiSnap(ss_record, fs_record, file_records, snap_name = None):
3331 """ 3332 Create a snapshot of all the files listed for the file system. 3333 3334 @param ss_record: L{Storage Server record<__SSRecord__>} 3335 @type ss_record: C{dict} 3336 3337 @param fs_record: L{File System record<__FSRecord__>} 3338 @type fs_record: C{dict} 3339 3340 @param file_records: List of L{File record<__FileRecord__>} 3341 @type file_records: C{list} 3342 3343 @param snap_name: Optional snapshot name 3344 @type snap_name: C{str} 3345 3346 @return: Created L{File record<__FileRecord__>} for the snapshot 3347 @rtype: C{list} 3348 3349 @raise IPluginException: on failure 3350 """ 3351 raise NotImplementedError()
3352 3353 @staticmethod
3354 - def isRestorable(ss_record, fs_record, file_record, snap_file_record):
3355 """ 3356 Check if the Storage Array or Storage Element can be rolled back to the 3357 named snapshot. 3358 3359 @param ss_record: L{Storage Server record<__SSRecord__>} 3360 @type ss_record: C{dict} 3361 3362 @param fs_record: L{File System record<__FSRecord__>} 3363 @type fs_record: C{dict} 3364 3365 @param file_record: L{Storage Element record<__SERecord__>} naming 3366 the file tjat should be rolled back. 3367 @type file_record: C{dict} 3368 3369 @param snap_file_record: L{Storage Element record<__SERecord__>} naming 3370 the snapshot to be rolled back to. 3371 @type snap_file_record: C{dict} 3372 3373 @return: True if a snapshot can be rolled . 3374 @rtype: C{bool} 3375 3376 @raise IPluginException: on failure 3377 """ 3378 raise NotImplementedError()
3379 3380 @staticmethod
3381 - def snapRestore(ss_record, fs_record, file_record, snap_file_record):
3382 """ 3383 Roll the file back to the named snapshot. 3384 3385 @param ss_record: L{Storage Server record<__SSRecord__>} 3386 @type ss_record: C{dict} 3387 3388 @param fs_record: L{File System record<__FSRecord__>} 3389 @type fs_record: C{dict} 3390 3391 @param file_record: L{File record<__FileRecord__>} of the file to roll 3392 back. 3393 @type file_record: C{dict} 3394 3395 @param snap_file_record: L{File record<__FileRecord__>} naming the 3396 snapshot to roll back to. 3397 @type snap_file_record: C{dict} 3398 3399 @raise IPluginException: on failure 3400 """ 3401 raise NotImplementedError()
3402 3403 @staticmethod
3404 - def snapRemove(ss_record, fs_record, snap_file_record):
3405 """ 3406 Destroy the named snapshot. 3407 3408 @param ss_record: L{Storage Server record<__SSRecord__>} 3409 @type ss_record: C{dict} 3410 3411 @param fs_record: L{File System record<__FSRecord__>} 3412 @type fs_record: C{dict} 3413 3414 @param snap_file_record: L{File record<__FileRecord__>} 3415 @type snap_file_record: C{dict} 3416 3417 @raise IPluginException: on failure 3418 """ 3419 raise NotImplementedError()
3420 3421 @staticmethod
3422 - def getCurrentSnaps(ss_record, fs_record, file_record = None):
3423 """ 3424 Return a list of the current snapshots for a File System or File Record. 3425 3426 @param ss_record: L{Storage Server record<__SSRecord__>} 3427 @type ss_record: C{dict} 3428 3429 @param fs_record: L{File System record<__FSRecord__>} 3430 @type fs_record: C{dict} 3431 3432 @param file_record: Optional L{File record<__FileRecord__>} 3433 @type file_record: C{dict} 3434 3435 @return: List of current known snapshots for the File System or File 3436 record if supplied. 3437 @rtype: C{list} 3438 3439 @raise IPluginException: on failure 3440 """ 3441 raise NotImplementedError()
3442 3443 @staticmethod
3444 - def getQoSList(ss_record, fs_record = None):
3445 """ 3446 Return a list of possible QoS values for the File System. 3447 3448 @param ss_record: L{Storage Server record<__SSRecord__>} 3449 @type ss_record: C{dict} 3450 3451 @param fs_record: Optional L{File System record<__FSRecord__>} 3452 @type fs_record: C{dict} 3453 3454 @return: List of L{qos_vals<__qos_vals__>} dicts for all the possible 3455 QoS values for either the Storage Server or the File System. 3456 @rtype: C{list} 3457 3458 @raise IPluginException: on failure 3459 """ 3460 raise NotImplementedError()
3461 3462 @staticmethod
3463 - def setQoS(ss_record, fs_record, qos):
3464 """ 3465 Set the QoS for the Storage Element to the QoS supplied. 3466 3467 @param ss_record: L{Storage Server record<__SSRecord__>} 3468 @type ss_record: C{dict} 3469 3470 @param fs_record: L{File System record<__FSRecord__>} 3471 @type fs_record: C{dict} 3472 3473 @param qos: Desired Quality-of-Service for the new clone. 3474 @type qos: C{str} 3475 3476 @raise IPluginException: on failure 3477 """ 3478 raise NotImplementedError()
3479 3480 @staticmethod
3481 - def getFileSystemBackingDevices(ss_record, fs_record):
3482 """ 3483 Get the list of valid backing devices that can be used to create 3484 a file system on. 3485 3486 @param ss_record: L{Storage Server record<__SSRecord__>} 3487 @type ss_record: C{dict} 3488 3489 @param fs_record: L{File System record<__FSRecord__>} 3490 @type fs_record: C{dict} 3491 3492 @return: List of L{backing_device<__BackingDeviceRecord__>} dicts 3493 for all the possible backing devices that can be used to 3494 create a new file system on. 3495 @rtype: C{list} 3496 3497 @raise IPluginException: on failure 3498 """ 3499 raise NotImplementedError()
3500 3501 @staticmethod
3502 - def getAsyncProgress(ss_record, some_record):
3503 """ 3504 Obtain Async Progress. This should never be called as 3505 the plugin should overide this method if it is in 3506 asynch mode. 3507 3508 @param ss_record: L{Storage Server record<__SSRecord__>} 3509 @type ss_record: C{dict} 3510 3511 @param some_record: Record previously returned from the 3512 call that started the asynchronous 3513 operation with the async_progress and 3514 if required the async_handle fields 3515 added (and not set to None). 3516 @type some_record: C{dict} 3517 3518 @return: Fully completed record that would have been 3519 returned if the initial call completed 3520 synchronously except it have the async_progress field. 3521 @rtype: C{dict} 3522 3523 @raise IPluginException: on failure 3524 """ 3525 3526 raise NotImplementedError()
3527
3528 -class IPluginException(Exception):
3529 """ 3530 All IPlugin exceptions inherits from IPluginException to allow for blanket 3531 exception catching. 3532 """
3533 - def __init__(self, msg):
3534 Exception.__init__(self, msg) 3535 self.msg = msg
3536
3537 - def __str__(self):
3538 return repr(self.msg)
3539
3540 -class NoSuchOperationEx(IPluginException):
3541 """ 3542 Exception that gets raised if the call is not valid for the plugin. 3543 """
3544 - def __init__(self, msg):
3545 IPluginException.__init__(self, msg)
3546
3547 -class OperationFailedEx(IPluginException):
3548 """ 3549 Exception that gets raised if the operation failed. 3550 """
3551 - def __init__(self, msg):
3552 IPluginException.__init__(self, msg)
3553
3554 -class MissingKeyEx(IPluginException):
3555 """ 3556 Exception that gets raised if a required key is not in the record. 3557 """
3558 - def __init__(self, msg, key_name):
3559 IPluginException.__init__(self, msg) 3560 self.key_name = key_name
3561
3562 -class ValueFormatEx(IPluginException):
3563 """ 3564 Exception that gets raised when the plugin is unable to interpret the value 3565 passed in a key. 3566 """
3567 - def __init__(self, msg, key_name):
3568 IPluginException.__init__(self, msg) 3569 self.key_name = key_name
3570
3571 -class StorageArrayLicenseEx(IPluginException):
3572 """ 3573 Exception that gets raised if the Storage Array feature is not licensed. 3574 """
3575 - def __init__(self, msg):
3576 IPluginException.__init__(self, msg)
3577
3578 -class TargetDiscoveryEx(IPluginException):
3579 """ 3580 Exception that gets raised if discovery failed. 3581 """
3582 - def __init__(self, msg):
3583 IPluginException.__init__(self, msg)
3584
3585 -class LoginFailedEx(IPluginException):
3586 """ 3587 Exception that gets raised if the login failed. 3588 """
3589 - def __init__(self, msg):
3590 IPluginException.__init__(self, msg)
3591
3592 -class LogoutFailedEx(IPluginException):
3593 """ 3594 Exception that gets raised if the logout failed. 3595 """
3596 - def __init__(self, msg):
3597 IPluginException.__init__(self, msg)
3598
3599 -class RefreshFailedEx(IPluginException):
3600 """ 3601 Exception that gets raised if the storage array refresh failed. 3602 """
3603 - def __init__(self, msg):
3604 IPluginException.__init__(self, msg)
3605
3606 -class ListFailedEx(IPluginException):
3607 """ 3608 Exception that gets raised if the storage element list failed. 3609 """
3610 - def __init__(self, msg):
3611 IPluginException.__init__(self, msg)
3612
3613 -class CreateSnapFailedEx(IPluginException):
3614 """ 3615 Exception that gets raised if a snapshot creation has failed. 3616 """
3617 - def __init__(self, msg):
3618 IPluginException.__init__(self, msg)
3619
3620 -class ListSnapFailedEx(IPluginException):
3621 """ 3622 Exception that gets raised if listing snapshots failed. 3623 """
3624 - def __init__(self, msg):
3625 IPluginException.__init__(self, msg)
3626
3627 -class SnapRestoreNotSafeEx(IPluginException):
3628 """ 3629 Exception that gets raised if snapshot cannot safely be rolled back. 3630 """
3631 - def __init__(self, msg):
3632 IPluginException.__init__(self, msg)
3633
3634 -class CloneFailedEx(IPluginException):
3635 """ 3636 Exception that gets raised if a clone opertaion failed. 3637 """
3638 - def __init__(self, msg):
3639 IPluginException.__init__(self, msg)
3640
3641 -class InvalidStorageArrayEx(IPluginException):
3642 """ 3643 Exception that gets raised if the ss_record is invalid. 3644 """
3645 - def __init__(self, msg):
3646 IPluginException.__init__(self, msg)
3647
3648 -class InvalidValueEx(IPluginException):
3649 """ 3650 Exception that gets raised on an invalid value in one of the records. 3651 """
3652 - def __init__(self, msg):
3653 IPluginException.__init__(self, msg)
3654
3655 -class PermissionDeniedEx(IPluginException):
3656 """ 3657 Exception that gets raised if permission is denied for the operation. 3658 """
3659 - def __init__(self, msg):
3660 IPluginException.__init__(self, msg)
3661
3662 -class StorageElementBusyEx(IPluginException):
3663 """ 3664 Exception that gets raised when the operation is not allowed while the 3665 Storage Element is still in use. 3666 """
3667 - def __init__(self, msg):
3668 IPluginException.__init__(self, msg)
3669
3670 -class OperationPreReqNotMetEx(IPluginException):
3671 """ 3672 Exception that gets raised if a operation's prerequisite have not been met. 3673 """
3674 - def __init__(self, msg, pre_req):
3675 IPluginException.__init__(self, msg) 3676 self.pre_req = pre_req
3677
3678 -class StorageNameRequiredEx(IPluginException):
3679 """ 3680 Exception that gets raised by the validate() method if the plug-in require 3681 a storage name to be set in the ss_record. 3682 """
3683 - def __init__(self, msg, pre_req):
3684 IPluginException.__init__(self, msg) 3685 self.pre_req = pre_req
3686
3687 -class InvalidFSTypeEx(IPluginException):
3688 """ 3689 Exception that gets raised if the FS record file system type is invalid. 3690 """
3691 - def __init__(self, msg):
3692 IPluginException.__init__(self, msg)
3693
3694 -class FileSystemBusyEx(IPluginException):
3695 """ 3696 Exception that gets raised if the FS is busy. 3697 """
3698 - def __init__(self, msg):
3699 IPluginException.__init__(self, msg)
3700
3701 -class CommandMissingEx(IPluginException):
3702 """ 3703 Exception that gets raised if the comand is not available. 3704 """
3705 - def __init__(self, msg):
3706 IPluginException.__init__(self, msg)
3707
3708 3709 -class FileSystemAlreadyMountedEx(IPluginException):
3710 """ 3711 Exception that gets raised if the FS is already mounted. 3712 """
3713 - def __init__(self, msg):
3714 IPluginException.__init__(self, msg)
3715