def _create_file(self, filename, size, sparse=True):
     try:
         f = open(filename, "w+")
     except (OSError, IOError):
         raise ExecutionError("Could not open %s" % filename)
     try:
         if sparse:
             try:
                 os.posix_fallocate(f.fileno(), 0, size)
             except AttributeError:
                 # Prior to version 3.3, Python does not provide fallocate
                 os.ftruncate(f.fileno(), size)
         else:
             self.shell.log.info("Writing %d bytes" % size)
             while size > 0:
                 write_size = min(size, 1024)
                 f.write("\0" * write_size)
                 size -= write_size
     except (OSError, IOError):
         os.remove(filename)
         raise ExecutionError("Could not expand file to %d bytes" % size)
     except OverflowError:
         raise ExecutionError("The file size is too large (%d bytes)" % size)
     finally:
         f.close()
 def setup_model_alias(self, storageobject):
     if self.shell.prefs['export_backstore_name_as_model']:
         try:
             storageobject.set_attribute("emulate_model_alias", 1)
         except RTSLibError:
             raise ExecutionError("'export_backstore_name_as_model' is set but"
                                  " emulate_model_alias\n  not supported by kernel.")
Example #3
0
 def assert_root(self):
     '''
     For commands requiring root privileges, disable command if not the root
     node's as_root attribute is False.
     '''
     root_node = self.get_root()
     if hasattr(root_node, 'as_root') and not root_node.as_root:
         raise ExecutionError("This privileged command is disabled: " +
                              "you are not root.")
Example #4
0
 def _create_file(self, filename, size, sparse=True):
     f = open(filename, "w+")
     try:
         if sparse:
             os.ftruncate(f.fileno(), size)
         else:
             self.shell.log.info("Writing %s bytes" % size)
             while size > 0:
                 write_size = min(size, 1024)
                 f.write("\0" * write_size)
                 size -= write_size
     except IOError:
         f.close()
         os.remove(filename)
         raise ExecutionError("Could not expand file to size")
     f.close()
Example #5
0
    def ui_command_enable(self):
        '''
        Enables the TPG.

        SEE ALSO
        ========
        B{disable status}
        '''
        self.assert_root()
        if self.rtsnode.enable:
            self.shell.log.info("The TPGT is already enabled.")
        else:
            try:
                self.rtsnode.enable = True
                self.shell.log.info("The TPGT has been enabled.")
            except RTSLibError:
                raise ExecutionError("The TPGT could not be enabled.")
Example #6
0
    def next_hba_index(self):
        self.shell.log.debug("%r" % [(backstore.plugin, backstore.index)
                                     for backstore in RTSRoot().backstores])
        indexes = [
            backstore.index for backstore in RTSRoot().backstores
            if backstore.plugin == self.name
        ]
        self.shell.log.debug("Existing %s backstore indexes: %r" %
                             (self.name, indexes))
        for index in range(1048576):
            if index not in indexes:
                backstore_index = index
                break

        if backstore_index is None:
            raise ExecutionError("Cannot find an available backstore index.")
        else:
            self.shell.log.debug("First available %s backstore index is %d." %
                                 (self.name, backstore_index))
            return backstore_index
    def ui_command_delete(self, name):
        '''
        Recursively deletes the storage object having the specified I{name}. If
        there are LUNs using this storage object, they will be deleted too.

        EXAMPLE
        =======
        B{delete mystorage}
        -------------------
        Deletes the storage object named mystorage, and all associated LUNs.
        '''
        self.assert_root()
        try:
            child = self.get_child(name)
        except ValueError:
            raise ExecutionError("No storage object named %s." % name)

        child.rtsnode.delete()
        self.remove_child(child)
        self.shell.log.info("Deleted storage object %s." % name)
Example #8
0
    def ui_command_restoreconfig(self, savefile=default_save_file, clear_existing=False):
        '''
        Restores configuration from a file.
        '''
        self.assert_root()

        savefile = os.path.expanduser(savefile)

        if not os.path.isfile(savefile):
            self.shell.log.info("Restore file %s not found" % savefile)
            return

        errors = self.rtsroot.restore_from_file(savefile, clear_existing)

        self.refresh()

        if errors:
            raise ExecutionError("Configuration restored, %d recoverable errors:\n%s" % \
                                     (len(errors), "\n".join(errors)))

        self.shell.log.info("Configuration restored from %s" % savefile)
Example #9
0
    def ui_command_sessions(self, action="list", sid=None):
        '''
        Displays a detailed list of all open sessions.

        PARAMETERS
        ==========

        I{action}
        ---------
        The I{action} is one of:
            - B{list} gives a short session list
            - B{detail} gives a detailed list

        I{sid}
        ------
        You can specify an I{sid} to only list this one,
        with or without details.

        SEE ALSO
        ========
        status
        '''

        indent_step = 4
        base_steps = 0
        action_list = ("list", "detail")
        root = RTSRoot()

        if action not in action_list:
            raise ExecutionError("action must be one of: %s" %
                                 ", ".join(action_list))
        if sid is not None:
            try:
                int(sid)
            except ValueError:
                raise ExecutionError("sid must be a number, '%s' given" % sid)

        def indent_print(text, steps):
            console = self.shell.con
            console.display(console.indent(text, indent_step * steps),
                            no_lf=True)

        def print_session(session):
            acl = session['parent_nodeacl']
            indent_print("alias: %(alias)s\tsid: %(id)i type: " \
                             "%(type)s session-state: %(state)s" % session,
                         base_steps)

            if action == 'detail':
                if self.as_root:
                    if acl.authenticate_target:
                        auth = " (authenticated)"
                    else:
                        auth = " (NOT AUTHENTICATED)"
                else:
                    auth = ""

                indent_print("name: %s%s" % (acl.node_wwn, auth),
                             base_steps + 1)

                for mlun in acl.mapped_luns:
                    plugin = mlun.tpg_lun.storage_object.backstore.plugin
                    name = mlun.tpg_lun.storage_object.name
                    if mlun.write_protect:
                        mode = "r"
                    else:
                        mode = "rw"
                    indent_print(
                        "mapped-lun: %d backstore: %s/%s mode: %s" %
                        (mlun.mapped_lun, plugin, name, mode), base_steps + 1)

                for connection in session['connections']:
                    indent_print("address: %(address)s (%(transport)s)  cid: " \
                                     "%(cid)i connection-state: %(cstate)s" % \
                                     connection, base_steps + 1)

        if sid:
            printed_sessions = [
                x for x in root.sessions if x['id'] == int(sid)
            ]
        else:
            printed_sessions = list(root.sessions)

        if len(printed_sessions):
            for session in printed_sessions:
                print_session(session)
        else:
            if sid is None:
                indent_print("(no open sessions)", base_steps)
            else:
                raise ExecutionError("no session found with sid %i" % int(sid))
Example #10
0
 def assert_available_so_name(self, name):
     names = [child.name for child in self.children]
     if name in names:
         raise ExecutionError("Storage object %s/%s already exist." %
                              (self.name, name))
Example #11
0
            except Exception, exception:
                backstore.delete()
                raise exception
            self.shell.log.info("Created fileio %s." % name)
            ui_so = UIStorageObject(so, self)
            return self.new_node(ui_so)
        else:
            # use given file size only if backing file does not exist
            if os.path.isfile(file_or_dev):
                new_size = str(os.path.getsize(file_or_dev))
                if size:
                    self.shell.log.info("%s exists, using its size (%s bytes)"
                                        " instead" % (file_or_dev, new_size))
                size = new_size
            elif os.path.exists(file_or_dev):
                raise ExecutionError("Path %s exists but is not a file" %
                                     file_or_dev)
            else:
                # create file and extend to given file size
                if not size:
                    raise ExecutionError("Attempting to create file for new" +
                                         " fileio backstore, need a size")
                self._create_file(file_or_dev, convert_human_to_bytes(size),
                                  sparse)


class UIIBlockBackstore(UIBackstore):
    '''
    IBlock backstore UI.
    '''
    def __init__(self, parent):
        UIBackstore.__init__(self, 'iblock', parent)
Example #12
0
    def ui_command_create(self,
                          storage_object,
                          lun=None,
                          add_mapped_luns=None):
        '''
        Creates a new LUN in the Target Portal Group, attached to a storage
        object. If the I{lun} parameter is omitted, the first available LUN in
        the TPG will be used. If present, it must be a number greater than 0.
        Alternatively, the syntax I{lunX} where I{X} is a positive number is
        also accepted.

        The I{storage_object} must be the path of an existing storage object,
        i.e. B{/backstore/pscsi0/mydisk} to reference the B{mydisk} storage
        object of the virtual HBA B{pscsi0}.

        If I{add_mapped_luns} is omitted, the global parameter
        B{auto_add_mapped_luns} will be used, else B{true} or B{false} are
        accepted. If B{true}, then after creating the LUN, mapped LUNs will be
        automatically created for all existing node ACLs, mapping the new LUN.

        SEE ALSO
        ========
        B{delete}
        '''
        self.assert_root()

        add_mapped_luns = \
                self.ui_eval_param(add_mapped_luns, 'bool',
                                   self.shell.prefs['auto_add_mapped_luns'])

        try:
            so = self.get_node(storage_object).rtsnode
        except ValueError:
            self.shell.log.error("Invalid storage object %s." % storage_object)
            return

        if so in (l.storage_object for l in self.parent.rtsnode.luns):
            raise ExecutionError("lun for storage object %s already exists" \
                                     % storage_object)

        if lun and lun.lower().startswith('lun'):
            lun = lun[3:]
        lun_object = LUN(self.tpg, lun, so)
        self.shell.log.info("Created LUN %s." % lun_object.lun)
        ui_lun = UILUN(lun_object, self)

        if add_mapped_luns:
            for acl in self.tpg.node_acls:
                if lun:
                    mapped_lun = lun
                else:
                    mapped_lun = 0
                existing_mluns = [mlun.mapped_lun for mlun in acl.mapped_luns]
                if mapped_lun in existing_mluns:
                    mapped_lun = None
                    for possible_mlun in xrange(LUN.MAX_LUN):
                        if possible_mlun not in existing_mluns:
                            mapped_lun = possible_mlun
                            break

                if mapped_lun == None:
                    self.shell.log.warning(
                        "Cannot map new lun %s into ACL %s" %
                        (lun_object.lun, acl.node_wwn))
                else:
                    mlun = MappedLUN(acl,
                                     mapped_lun,
                                     lun_object,
                                     write_protect=False)
                    self.shell.log.info(
                        "Created LUN %d->%d mapping in node ACL %s" %
                        (mlun.tpg_lun.lun, mlun.mapped_lun, acl.node_wwn))
            self.parent.refresh()

        return self.new_node(ui_lun)
Example #13
0
    def ui_command_create(self,
                          mapped_lun,
                          tpg_lun_or_backstore,
                          write_protect=None):
        '''
        Creates a mapping to one of the TPG LUNs for the initiator referenced
        by the ACL. The provided I{tpg_lun_or_backstore} will appear to that
        initiator as LUN I{mapped_lun}. If the I{write_protect} flag is set to
        B{1}, the initiator will not have write access to the Mapped LUN.

        A storage object may also be given for the I{tpg_lun_or_backstore} parameter,
        in which case the TPG LUN will be created for that backstore before
        mapping the LUN to the initiator. If a TPG LUN for the backstore already
        exists, the Mapped LUN will map to that TPG LUN.

        Finally, a path to an existing block device or file can be given. If so,
        a storage object of the appropriate type is created with default parameters,
        followed by the TPG LUN and the Mapped LUN.

        SEE ALSO
        ========
        B{delete}
        '''
        self.assert_root()
        try:
            mapped_lun = int(mapped_lun)
        except ValueError:
            raise ExecutionError("mapped_lun must be an integer")

        try:
            if tpg_lun_or_backstore.startswith("lun"):
                tpg_lun_or_backstore = tpg_lun_or_backstore[3:]
            tpg_lun = int(tpg_lun_or_backstore)
        except ValueError:
            try:
                so = self.get_node(tpg_lun_or_backstore).rtsnode
            except ValueError:
                try:
                    so = StorageObjectFactory(tpg_lun_or_backstore)
                    self.shell.log.info("Created storage object %s." % so.name)
                except RTSLibError:
                    raise ExecutionError(
                        "LUN, storage object, or path not valid")
                self.get_node("/backstores").refresh()

            ui_tpg = self.parent.parent

            for lun in ui_tpg.rtsnode.luns:
                if so == lun.storage_object:
                    tpg_lun = lun.lun
                    break
            else:
                lun_object = LUN(ui_tpg.rtsnode, storage_object=so)
                self.shell.log.info("Created LUN %s." % lun_object.lun)
                ui_lun = UILUN(lun_object, ui_tpg.get_node("luns"))
                tpg_lun = ui_lun.rtsnode.lun

        if tpg_lun in (ml.tpg_lun.lun for ml in self.rtsnodes[0].mapped_luns):
            self.shell.log.warning(
                "Warning: TPG LUN %d already mapped to this NodeACL" % tpg_lun)

        for na in self.rtsnodes:
            mlun = MappedLUN(na, mapped_lun, tpg_lun, write_protect)

        ui_mlun = UIMappedLUN(mlun, self)
        self.shell.log.info("Created Mapped LUN %s." % mlun.mapped_lun)
        return self.new_node(ui_mlun)
Example #14
0
    def ui_command_tag(self, wwn_or_tag, new_tag):
        '''
        Tag a NodeACL.

        Usage: tag <wwn_or_tag> <new_tag>

        Tags help manage initiator WWNs. A tag can apply to one or
        more WWNs. This can give a more meaningful name to a single
        initiator's configuration, or allow multiple initiators with
        identical settings to be configured en masse.

        The WWNs described by <wwn_or_tag> will be given the new
        tag. If new_tag already exists, its new members will adopt the
        current tag's configuration.

        Within a tag, the 'info' command shows the WWNs the tag applies to.

        Use 'untag' to remove tags.

        NOTE: tags are only supported in kernel 3.8 and above.
        '''
        if wwn_or_tag == new_tag:
            return

        # Since all WWNs have a '.' in them, let's avoid confusion.
        if '.' in new_tag:
            raise ExecutionError("'.' not permitted in tag names.")

        src = list(self.find_tagged(wwn_or_tag))
        if not src:
            raise ExecutionError("wwn_or_tag %s not found." % wwn_or_tag)

        old_tag_members = list(self.find_tagged(new_tag))

        # handle overlap
        src_wwns = [na.node_wwn for na in src]
        old_tag_members = [
            old for old in old_tag_members if old.node_wwn not in src_wwns
        ]

        for na in src:
            na.tag = new_tag

            # if joining a tag, take its config
            if old_tag_members:
                model = old_tag_members[0]

                for mlun in na.mapped_luns:
                    mlun.delete()

                for mlun in model.mapped_luns:
                    MappedLUN(na, mlun.mapped_lun, mlun.tpg_lun,
                              mlun.write_protect)

                if self.parent.rtsnode.has_feature("auth"):
                    for param in auth_params:
                        setattr(na, "chap_" + param,
                                getattr(model, "chap_" + param))

                for item in model.list_attributes(writable=True):
                    na.set_attribute(item, model.get_attribute(item))
                for item in model.list_parameters(writable=True):
                    na.set_parameter(item, model.get_parameter(item))

        self.refresh()
Example #15
0
    def ui_command_create(self, name, file_or_dev, size=None, write_back=None,
                          sparse=None):
        '''
        Creates a FileIO storage object. If I{file_or_dev} is a path
        to a regular file to be used as backend, then the I{size}
        parameter is mandatory. Else, if I{file_or_dev} is a path to a
        block device, the size parameter B{must} be ommited. If
        present, I{size} is the size of the file to be used, I{file}
        the path to the file or I{dev} the path to a block device. The
        I{write_back} parameter is a boolean controlling write
        caching. It is enabled by default. The I{sparse} parameter is
        only applicable when creating a new backing file. It is a
        boolean stating if the created file should be created as a
        sparse file (the default), or fully initialized.

        SIZE SYNTAX
        ===========
        - If size is an int, it represents a number of bytes.
        - If size is a string, the following units can be used:
            - B{B} or no unit present for bytes
            - B{k}, B{K}, B{kB}, B{KB} for kB (kilobytes)
            - B{m}, B{M}, B{mB}, B{MB} for MB (megabytes)
            - B{g}, B{G}, B{gB}, B{GB} for GB (gigabytes)
            - B{t}, B{T}, B{tB}, B{TB} for TB (terabytes)
        '''
        self.assert_root()

        sparse = self.ui_eval_param(sparse, 'bool', True)
        write_back = self.ui_eval_param(write_back, 'bool', True)

        self.shell.log.debug("Using params size=%s write_back=%s sparse=%s"
                             % (size, write_back, sparse))

        file_or_dev = os.path.expanduser(file_or_dev)
        # can't use is_dev_in_use() on files so just check against other
        # storage object paths
        if os.path.exists(file_or_dev):
            for so in RTSRoot().storage_objects:
                if so.udev_path and os.path.samefile(file_or_dev, so.udev_path):
                    raise ExecutionError("storage object for %s already exists: %s" % \
                                             (file_or_dev, so.name))

        if get_block_type(file_or_dev) is not None:
            if size:
                self.shell.log.info("Block device, size parameter ignored")
                size = None
            self.shell.log.info("Note: block backstore preferred for best results")
        else:
            # use given file size only if backing file does not exist
            if os.path.isfile(file_or_dev):
                new_size = os.path.getsize(file_or_dev)
                if size:
                    self.shell.log.info("%s exists, using its size (%s bytes) instead" 
                                        % (file_or_dev, new_size))
                size = new_size
            elif os.path.exists(file_or_dev):
                raise ExecutionError("Path %s exists but is not a file" % file_or_dev)
            else:
                # create file and extend to given file size
                if not size:
                    raise ExecutionError("Attempting to create file for new" +
                                         " fileio backstore, need a size")
                size = human_to_bytes(size)
                self._create_file(file_or_dev, size, sparse)

        so = FileIOStorageObject(name, file_or_dev, size, write_back=write_back)
        ui_so = UIFileioStorageObject(so, self)
        self.setup_model_alias(so)
        self.shell.log.info("Created fileio %s with size %s"
                            % (name, so.size))
        return self.new_node(ui_so)